From 5033e2cdbb1170168baccd3bcb65ac3d7955ebec Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 13:04:41 -0800 Subject: [PATCH 01/35] [Timeline] Begin adding Export as CSV Sketch in solution for https://developer.nasa.gov/mct/warp/issues/135 --- .../src/actions/ExportTimelineAsCSVAction.js | 44 +++++++++++++++++++ .../src/actions/ExportTimelineAsCSVTask.js | 42 ++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js create mode 100644 platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js new file mode 100644 index 0000000000..2e0dc71589 --- /dev/null +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js @@ -0,0 +1,44 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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(["./ExportTimelineAsCSVTask"], function (ExportTimelineAsCSVTask) { + 'use strict'; + + function ExportTimelineAsCSVAction(taskService, context) { + this.task = new ExportTimelineAsCSVTask(context.domainObject); + this.taskService = taskService; + } + + ExportTimelineAsCSVAction.prototype.perform = function () { + return this.taskService.run(this.task); + }; + + ExportTimelineAsCSVAction.appliesTo = function (context) { + return context.domainObject && + context.domainObject.hasCapability('type') && + context.domainObject.getCapability('type') + .instanceOf('timeline'); + }; + + return ExportTimelineAsCSVAction; +}); \ No newline at end of file diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js new file mode 100644 index 0000000000..82ee47b9a4 --- /dev/null +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -0,0 +1,42 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,Promise*/ + +/** + * Module defining ExportTimelineAsCSVTask. Created by vwoeltje on 2/8/16. + */ +define([], function () { + "use strict"; + + /** + * + * @constructor + * @memberof {platform/features/timeline} + */ + function ExportTimelineAsCSVTask(domainObject) { + this.domainObject = domainObject; + } + + + + return ExportTimelineAsCSVTask; +}); From d8b1e570d98292986c6ef817657a7c4207195c38 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 13:36:25 -0800 Subject: [PATCH 02/35] [CSV Export] Begin implementing Begin implementing initial step, wherein timelines composition is traversed to build up a list of objects to export. --- .../src/actions/ExportTimelineAsCSVTask.js | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 82ee47b9a4..889788090c 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -36,7 +36,63 @@ define([], function () { this.domainObject = domainObject; } + /** + * @private + */ + ExportTimelineAsCSVTask.prototype.buildObjectList = function () { + var idSet = {}, + objects = []; + function addObject(domainObject) { + var id = domainObject.getId(), + subtasks = []; + + function addCompositionObjects() { + return domainObject.useCapability('composition') + .then(function (childObjects) { + return Promise.all(childObjects.map(addObject)); + }); + } + + function addRelationships() { + var relationship = domainObject.getCapability('relationship'); + relationship.getRelatedObjects('modes') + .then(function (modeObjects) { + return Promise.all(modeObjects.map(addObject)); + }); + } + + if (!idSet[id]) { + idSet[id] = true; + objects.push(domainObject); + if (domainObject.hasCapability('composition')) { + subtasks.push(addCompositionObjects()); + } + if (domainObject.hasCapability('relationship')) { + subtasks.push(addRelationships()); + } + } + + return Promise.all(subtasks); + } + + return addObject(this.domainObject).then(function () { + return objects; + }); + }; + + + ExportTimelineAsCSVTask.prototype.run = function (progressCallback) { + var name = this.domainObject.getModel().name; + + progressCallback({ + title: "Preparing to export " + name + }); + + this.buildObjectList().then(function (objects) { + + }); + }; return ExportTimelineAsCSVTask; }); From 4adb075a2b16a63a93fa8a2f2e47e96aeb3bbe72 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 13:59:34 -0800 Subject: [PATCH 03/35] [Timelines] Separate out timeline traversal ...from rest of CSV export. --- .../src/actions/ExportTimelineAsCSVTask.js | 70 +++++------------- .../timeline/src/actions/TimelineTraverser.js | 74 +++++++++++++++++++ 2 files changed, 92 insertions(+), 52 deletions(-) create mode 100644 platform/features/timeline/src/actions/TimelineTraverser.js diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 889788090c..57379d01d4 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -24,74 +24,40 @@ /** * Module defining ExportTimelineAsCSVTask. Created by vwoeltje on 2/8/16. */ -define([], function () { +define([ + "TimelineTraverser" +], function (TimelineTraverser, TimelineCSVExporter) { "use strict"; /** * * @constructor * @memberof {platform/features/timeline} + * @implements {Task} */ - function ExportTimelineAsCSVTask(domainObject) { + function ExportTimelineAsCSVTask(exportService, domainObject) { this.domainObject = domainObject; + this.exportService = exportService; } - /** - * @private - */ - ExportTimelineAsCSVTask.prototype.buildObjectList = function () { - var idSet = {}, - objects = []; + ExportTimelineAsCSVTask.prototype.run = function (progress) { + var name = this.domainObject.getModel().name, + exportService = this.exportService; - function addObject(domainObject) { - var id = domainObject.getId(), - subtasks = []; - - function addCompositionObjects() { - return domainObject.useCapability('composition') - .then(function (childObjects) { - return Promise.all(childObjects.map(addObject)); - }); - } - - function addRelationships() { - var relationship = domainObject.getCapability('relationship'); - relationship.getRelatedObjects('modes') - .then(function (modeObjects) { - return Promise.all(modeObjects.map(addObject)); - }); - } - - if (!idSet[id]) { - idSet[id] = true; - objects.push(domainObject); - if (domainObject.hasCapability('composition')) { - subtasks.push(addCompositionObjects()); - } - if (domainObject.hasCapability('relationship')) { - subtasks.push(addRelationships()); - } - } - - return Promise.all(subtasks); + function doExport(objects) { + var exporter = new TimelineCSVExporter(objects); + return exportService.exportCSV( + exporter.rows(), + exporter.options() + ); } - return addObject(this.domainObject).then(function () { - return objects; - }); - }; - - - ExportTimelineAsCSVTask.prototype.run = function (progressCallback) { - var name = this.domainObject.getModel().name; - - progressCallback({ + progress({ title: "Preparing to export " + name }); - this.buildObjectList().then(function (objects) { - - }); + return new TimelineTraverser().buildObjectList() + .then(doExport); }; return ExportTimelineAsCSVTask; diff --git a/platform/features/timeline/src/actions/TimelineTraverser.js b/platform/features/timeline/src/actions/TimelineTraverser.js new file mode 100644 index 0000000000..0f701a4799 --- /dev/null +++ b/platform/features/timeline/src/actions/TimelineTraverser.js @@ -0,0 +1,74 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,Promise*/ + +define([], function () { + + function TimelineTraverser(domainObject) { + this.domainObject = domainObject; + } + + TimelineTraverser.prototype.buildObjectList = function () { + var idSet = {}, + objects = []; + + function addObject(domainObject) { + var id = domainObject.getId(), + subtasks = []; + + function addCompositionObjects() { + return domainObject.useCapability('composition') + .then(function (childObjects) { + return Promise.all(childObjects.map(addObject)); + }); + } + + function addRelationships() { + var relationship = domainObject.getCapability('relationship'); + relationship.getRelatedObjects('modes') + .then(function (modeObjects) { + return Promise.all(modeObjects.map(addObject)); + }); + } + + if (!idSet[id]) { + idSet[id] = true; + objects.push(domainObject); + if (domainObject.hasCapability('composition')) { + subtasks.push(addCompositionObjects()); + } + if (domainObject.hasCapability('relationship')) { + subtasks.push(addRelationships()); + } + } + + return Promise.all(subtasks); + } + + return addObject(this.domainObject).then(function () { + return objects; + }); + }; + + return TimelineTraverser; + +}); \ No newline at end of file From 32fc50bbd35bce53777a7d2256b0795a9988a5d0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 15:04:39 -0800 Subject: [PATCH 04/35] [Timelines] Begin sketching in taskService ...to separate out immediate commonality with other long-running actions which need to show a blocking progress dialog. --- .../execution/src/TaskProgressReporter.js | 36 +++++++++ platform/execution/src/TaskService.js | 74 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 platform/execution/src/TaskProgressReporter.js create mode 100644 platform/execution/src/TaskService.js diff --git a/platform/execution/src/TaskProgressReporter.js b/platform/execution/src/TaskProgressReporter.js new file mode 100644 index 0000000000..f993a1a835 --- /dev/null +++ b/platform/execution/src/TaskProgressReporter.js @@ -0,0 +1,36 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2014-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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([], function () { + "use strict"; + + function TaskProgressReporter(dialogService, notificationService) { + this.dialogService = dialogService; + this.notificationService = notificationService; + } + + TaskProgressReporter.prototype.cancel = function () { + + }; + +}); diff --git a/platform/execution/src/TaskService.js b/platform/execution/src/TaskService.js new file mode 100644 index 0000000000..a5f5c06697 --- /dev/null +++ b/platform/execution/src/TaskService.js @@ -0,0 +1,74 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2014-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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*/ + + +/** + * This bundle contains services for managing the flow of execution, + * such as support for running web workers on background threads. + * @namespace platform/execution + */ +define( + [], + function () { + "use strict"; + + /** + * Runs long-running tasks with progress reporting. + * @memberof platform/execution + * @constructor + */ + function TaskService(dialogService, notificationService) { + this.dialogService = dialogService; + this.notificationService = notificationService; + } + + /** + * Invoked to update progress associated with a running task. + * @callback TaskService~progressCallback + * @param {NotificationModel} model current progress to show + */ + + /** + * Initiate a new task. + * + * @param {function(progress : TaskService~progressCallback} : Task)} + * taskFactory a function which, when provided a + * progress-reporting callback, will return the task to run. + * @returns {Promise} a promise for the result of the task + */ + TaskService.prototype.run = function (task) { + var model = {}, + dialogService = this.dialogService, + notificationService = this.notificationService; + + function reportProgress(progressModel) { + + } + + return task.run(reportProgress); + }; + + return TaskService; + } +); + From a126e432867a45963d0f35496d4c1ab719934b57 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 16:11:00 -0800 Subject: [PATCH 05/35] [Timelines] Handle columns during CSV export --- .../timeline/src/actions/CompositionColumn.js | 38 ++++++++ .../src/actions/ExportTimelineAsCSVTask.js | 4 - .../timeline/src/actions/MetadataColumn.js | 41 ++++++++ .../timeline/src/actions/ModeColumn.js | 38 ++++++++ .../src/actions/TimelineCSVExporter.js | 97 +++++++++++++++++++ 5 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 platform/features/timeline/src/actions/CompositionColumn.js create mode 100644 platform/features/timeline/src/actions/MetadataColumn.js create mode 100644 platform/features/timeline/src/actions/ModeColumn.js create mode 100644 platform/features/timeline/src/actions/TimelineCSVExporter.js diff --git a/platform/features/timeline/src/actions/CompositionColumn.js b/platform/features/timeline/src/actions/CompositionColumn.js new file mode 100644 index 0000000000..35cbd75f69 --- /dev/null +++ b/platform/features/timeline/src/actions/CompositionColumn.js @@ -0,0 +1,38 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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([], function () { + function CompositionColumn(index) { + this.index = index; + } + + CompositionColumn.prototype.name = function () { + return "Child " + (this.index + 1); + }; + + CompositionColumn.prototype.value = function (domainObject) { + var model = domainObject.getModel(), + composition = model.composition || []; + return (composition[this.index]) || ""; + }; +}); diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 57379d01d4..45ebdffd2f 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -52,10 +52,6 @@ define([ ); } - progress({ - title: "Preparing to export " + name - }); - return new TimelineTraverser().buildObjectList() .then(doExport); }; diff --git a/platform/features/timeline/src/actions/MetadataColumn.js b/platform/features/timeline/src/actions/MetadataColumn.js new file mode 100644 index 0000000000..d31ae1a329 --- /dev/null +++ b/platform/features/timeline/src/actions/MetadataColumn.js @@ -0,0 +1,41 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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([], function () { + function MetadataColumn(property) { + this.property = property; + } + + MetadataColumn.prototype.name = function () { + return this.property.name; + }; + + MetadataColumn.prototype.value = function (domainObject) { + var properties = domainObject.useCapability('metadata'), + name = this.property.name, + property = properties.find(function (p) { + return p.name === name; + }); + return property ? property.value : ""; + }; +}); diff --git a/platform/features/timeline/src/actions/ModeColumn.js b/platform/features/timeline/src/actions/ModeColumn.js new file mode 100644 index 0000000000..545bdc19fc --- /dev/null +++ b/platform/features/timeline/src/actions/ModeColumn.js @@ -0,0 +1,38 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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([], function () { + function ModeColumn(index) { + this.index = index; + } + + ModeColumn.prototype.name = function () { + return "Mode " + (this.index + 1); + }; + + ModeColumn.prototype.value = function (domainObject) { + var model = domainObject.getModel(), + composition = (model.relationships || {}).modes || []; + return (composition[this.index]) || ""; + }; +}); diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js new file mode 100644 index 0000000000..b42debad93 --- /dev/null +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -0,0 +1,97 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,Promise*/ + +define([ + "ModeColumn", + "CompositionColumn", + "MetadataColumn" +], function (ModeColumn, CompositionColumn, MetadataColumn) { + 'use strict'; + + function TimelineCSVExporter(domainObjects) { + var maxComposition = 0, + maxRelationships = 0, + columnNames = {}, + columns = [], + i; + + function addMetadataProperty(property) { + var name = property.name; + if (!columnNames[name]) { + columnNames[name] = true; + columns.push(new MetadataColumn(name)) + } + } + + domainObjects.forEach(function (domainObject) { + var model = domainObject.getModel(), + compositionLength = model.composition ? + model.composition.length : 0, + relationshipLength = (model.relationships || {}).modes ? + model.relationships.modes.length : + 0, + metadataProperties = + domainObject.useCapability('metadata') || []; + + maxComposition = Math.max(maxComposition, compositionLength); + maxRelationships = Math.max(maxRelationships, relationshipLength); + + metadataProperties.forEach(addMetadataProperty); + }); + + for (i = 0; i < maxComposition; i += 1) { + columns.push(new CompositionColumn(i)); + } + + for (i = 0; i < maxRelationships; i += 1) { + columns.push(new RelationshipColumn(i)); + } + + this.domainObjects = domainObjects; + this.columns = columns; + } + + TimelineCSVExporter.prototype.rows = function () { + var columns = this.columns; + + function toRow(domainObject) { + var row = {}; + columns.forEach(function (column) { + row[column.name()] = column.value(domainObject); + }); + return row; + } + + return this.domainObjects.map(toRow); + }; + + TimelineCSVExporter.prototype.options = function () { + return { + headers: this.columns.map(function (column) { + return column.name(); + }) + }; + }; + + return TimelineCSVExporter; +}); \ No newline at end of file From a444fc01ad6941af3d9035a390d03af24ae4cab4 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 17:34:10 -0800 Subject: [PATCH 06/35] [Timeline] Fix column module definitions --- platform/features/timeline/src/actions/CompositionColumn.js | 4 ++++ platform/features/timeline/src/actions/MetadataColumn.js | 4 ++++ platform/features/timeline/src/actions/ModeColumn.js | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/platform/features/timeline/src/actions/CompositionColumn.js b/platform/features/timeline/src/actions/CompositionColumn.js index 35cbd75f69..6ee7fa010c 100644 --- a/platform/features/timeline/src/actions/CompositionColumn.js +++ b/platform/features/timeline/src/actions/CompositionColumn.js @@ -22,6 +22,8 @@ /*global define*/ define([], function () { + "use strict"; + function CompositionColumn(index) { this.index = index; } @@ -35,4 +37,6 @@ define([], function () { composition = model.composition || []; return (composition[this.index]) || ""; }; + + return CompositionColumn; }); diff --git a/platform/features/timeline/src/actions/MetadataColumn.js b/platform/features/timeline/src/actions/MetadataColumn.js index d31ae1a329..c798b229bc 100644 --- a/platform/features/timeline/src/actions/MetadataColumn.js +++ b/platform/features/timeline/src/actions/MetadataColumn.js @@ -22,6 +22,8 @@ /*global define*/ define([], function () { + "use strict"; + function MetadataColumn(property) { this.property = property; } @@ -38,4 +40,6 @@ define([], function () { }); return property ? property.value : ""; }; + + return MetadataColumn; }); diff --git a/platform/features/timeline/src/actions/ModeColumn.js b/platform/features/timeline/src/actions/ModeColumn.js index 545bdc19fc..0a88437211 100644 --- a/platform/features/timeline/src/actions/ModeColumn.js +++ b/platform/features/timeline/src/actions/ModeColumn.js @@ -22,6 +22,8 @@ /*global define*/ define([], function () { + "use strict"; + function ModeColumn(index) { this.index = index; } @@ -35,4 +37,6 @@ define([], function () { composition = (model.relationships || {}).modes || []; return (composition[this.index]) || ""; }; + + return ModeColumn; }); From b42ccebd5aa174acc448a907d5bab59c86781d79 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 17:42:26 -0800 Subject: [PATCH 07/35] [Timeline] Fix imports, dependencies Fix imports and dependencies needed by Export Timeline as CSV --- platform/features/timeline/bundle.js | 11 +++++++++++ .../src/actions/ExportTimelineAsCSVAction.js | 12 ++++++++---- .../timeline/src/actions/ExportTimelineAsCSVTask.js | 3 ++- .../timeline/src/actions/TimelineCSVExporter.js | 6 +++--- .../timeline/src/actions/TimelineTraverser.js | 1 + 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/platform/features/timeline/bundle.js b/platform/features/timeline/bundle.js index a791fc4fb0..3cf2935bc6 100644 --- a/platform/features/timeline/bundle.js +++ b/platform/features/timeline/bundle.js @@ -22,6 +22,7 @@ /*global define*/ define([ + "./src/actions/ExportTimelineAsCSVAction", "./src/controllers/TimelineController", "./src/controllers/TimelineGraphController", "./src/controllers/TimelineDateTimeController", @@ -40,6 +41,7 @@ define([ "./src/services/ObjectLoader", 'legacyRegistry' ], function ( + ExportTimelineAsCSVAction, TimelineController, TimelineGraphController, TimelineDateTimeController, @@ -65,6 +67,15 @@ define([ "description": "Resources, templates, CSS, and code for Timelines.", "resources": "res", "extensions": { + "actions": [ + { + "key": "timeline.export", + "name": "Export Timeline as CSV", + "category": "contextual", + "implementation": ExportTimelineAsCSVAction, + "depends": [ "exportService" ] + } + ], "constants": [ { "key": "TIMELINE_MINIMUM_DURATION", diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js index 2e0dc71589..099261256f 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js @@ -24,13 +24,17 @@ define(["./ExportTimelineAsCSVTask"], function (ExportTimelineAsCSVTask) { 'use strict'; - function ExportTimelineAsCSVAction(taskService, context) { - this.task = new ExportTimelineAsCSVTask(context.domainObject); - this.taskService = taskService; + function ExportTimelineAsCSVAction(exportService, context) { + this.task = new ExportTimelineAsCSVTask( + exportService, + context.domainObject + ); + //this.taskService = taskService; } ExportTimelineAsCSVAction.prototype.perform = function () { - return this.taskService.run(this.task); + return this.task.run(); + //return this.taskService.run(this.task); }; ExportTimelineAsCSVAction.appliesTo = function (context) { diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 45ebdffd2f..a854716367 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -25,7 +25,8 @@ * Module defining ExportTimelineAsCSVTask. Created by vwoeltje on 2/8/16. */ define([ - "TimelineTraverser" + "./TimelineTraverser", + "./TimelineCSVExporter" ], function (TimelineTraverser, TimelineCSVExporter) { "use strict"; diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index b42debad93..8364ab2c01 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -22,9 +22,9 @@ /*global define,Promise*/ define([ - "ModeColumn", - "CompositionColumn", - "MetadataColumn" + "./ModeColumn", + "./CompositionColumn", + "./MetadataColumn" ], function (ModeColumn, CompositionColumn, MetadataColumn) { 'use strict'; diff --git a/platform/features/timeline/src/actions/TimelineTraverser.js b/platform/features/timeline/src/actions/TimelineTraverser.js index 0f701a4799..48817b6963 100644 --- a/platform/features/timeline/src/actions/TimelineTraverser.js +++ b/platform/features/timeline/src/actions/TimelineTraverser.js @@ -22,6 +22,7 @@ /*global define,Promise*/ define([], function () { + "use strict"; function TimelineTraverser(domainObject) { this.domainObject = domainObject; From 273cf1c14f171a5d33d0af20d85ddb32fe62ac0f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 8 Feb 2016 18:07:03 -0800 Subject: [PATCH 08/35] [Timeline] Fix columns exported --- .../timeline/src/actions/ExportTimelineAsCSVTask.js | 3 ++- platform/features/timeline/src/actions/MetadataColumn.js | 8 ++++---- .../features/timeline/src/actions/TimelineCSVExporter.js | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index a854716367..77f0702497 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -53,7 +53,8 @@ define([ ); } - return new TimelineTraverser().buildObjectList() + return new TimelineTraverser(this.domainObject) + .buildObjectList() .then(doExport); }; diff --git a/platform/features/timeline/src/actions/MetadataColumn.js b/platform/features/timeline/src/actions/MetadataColumn.js index c798b229bc..64a0d5b2bb 100644 --- a/platform/features/timeline/src/actions/MetadataColumn.js +++ b/platform/features/timeline/src/actions/MetadataColumn.js @@ -24,17 +24,17 @@ define([], function () { "use strict"; - function MetadataColumn(property) { - this.property = property; + function MetadataColumn(propertyName) { + this.propertyName = propertyName; } MetadataColumn.prototype.name = function () { - return this.property.name; + return this.propertyName; }; MetadataColumn.prototype.value = function (domainObject) { var properties = domainObject.useCapability('metadata'), - name = this.property.name, + name = this.propertyName, property = properties.find(function (p) { return p.name === name; }); diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index 8364ab2c01..ed7bf2b953 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -64,7 +64,7 @@ define([ } for (i = 0; i < maxRelationships; i += 1) { - columns.push(new RelationshipColumn(i)); + columns.push(new ModeColumn(i)); } this.domainObjects = domainObjects; From a509dfb840976997c4bf166a5fda0f537de6ea4f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 15:30:57 -0800 Subject: [PATCH 09/35] [Timelines] Remove unused TaskService https://developer.nasa.gov/mct/warp/issues/135 --- .../execution/src/TaskProgressReporter.js | 36 --------- platform/execution/src/TaskService.js | 74 ------------------- 2 files changed, 110 deletions(-) delete mode 100644 platform/execution/src/TaskProgressReporter.js delete mode 100644 platform/execution/src/TaskService.js diff --git a/platform/execution/src/TaskProgressReporter.js b/platform/execution/src/TaskProgressReporter.js deleted file mode 100644 index f993a1a835..0000000000 --- a/platform/execution/src/TaskProgressReporter.js +++ /dev/null @@ -1,36 +0,0 @@ -/***************************************************************************** - * Open MCT Web, Copyright (c) 2014-2015, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT Web 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 Web 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([], function () { - "use strict"; - - function TaskProgressReporter(dialogService, notificationService) { - this.dialogService = dialogService; - this.notificationService = notificationService; - } - - TaskProgressReporter.prototype.cancel = function () { - - }; - -}); diff --git a/platform/execution/src/TaskService.js b/platform/execution/src/TaskService.js deleted file mode 100644 index a5f5c06697..0000000000 --- a/platform/execution/src/TaskService.js +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - * Open MCT Web, Copyright (c) 2014-2015, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT Web 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 Web 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*/ - - -/** - * This bundle contains services for managing the flow of execution, - * such as support for running web workers on background threads. - * @namespace platform/execution - */ -define( - [], - function () { - "use strict"; - - /** - * Runs long-running tasks with progress reporting. - * @memberof platform/execution - * @constructor - */ - function TaskService(dialogService, notificationService) { - this.dialogService = dialogService; - this.notificationService = notificationService; - } - - /** - * Invoked to update progress associated with a running task. - * @callback TaskService~progressCallback - * @param {NotificationModel} model current progress to show - */ - - /** - * Initiate a new task. - * - * @param {function(progress : TaskService~progressCallback} : Task)} - * taskFactory a function which, when provided a - * progress-reporting callback, will return the task to run. - * @returns {Promise} a promise for the result of the task - */ - TaskService.prototype.run = function (task) { - var model = {}, - dialogService = this.dialogService, - notificationService = this.notificationService; - - function reportProgress(progressModel) { - - } - - return task.run(reportProgress); - }; - - return TaskService; - } -); - From b383921f2a913b6a64a95a6a4866b286c80978f6 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:00:13 -0800 Subject: [PATCH 10/35] [Timeline] Export start/end to CSV --- .../src/actions/ExportTimelineAsCSVTask.js | 12 +++-- .../src/actions/TimelineCSVExporter.js | 24 ++++++---- .../timeline/src/actions/TimespanColumn.js | 44 +++++++++++++++++++ 3 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 platform/features/timeline/src/actions/TimespanColumn.js diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 77f0702497..8a0b60ca94 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -41,16 +41,14 @@ define([ this.exportService = exportService; } - ExportTimelineAsCSVTask.prototype.run = function (progress) { - var name = this.domainObject.getModel().name, - exportService = this.exportService; + ExportTimelineAsCSVTask.prototype.run = function () { + var exportService = this.exportService; function doExport(objects) { var exporter = new TimelineCSVExporter(objects); - return exportService.exportCSV( - exporter.rows(), - exporter.options() - ); + return exporter.rows().then(function (rows) { + return exportService.exportCSV(rows, exporter.options()); + }); } return new TimelineTraverser(this.domainObject) diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index ed7bf2b953..4ef27b3bc3 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -24,8 +24,9 @@ define([ "./ModeColumn", "./CompositionColumn", - "./MetadataColumn" -], function (ModeColumn, CompositionColumn, MetadataColumn) { + "./MetadataColumn", + "./TimespanColumn" +], function (ModeColumn, CompositionColumn, MetadataColumn, TimespanColumn) { 'use strict'; function TimelineCSVExporter(domainObjects) { @@ -33,6 +34,7 @@ define([ maxRelationships = 0, columnNames = {}, columns = [], + foundTimespan = false, i; function addMetadataProperty(property) { @@ -56,9 +58,17 @@ define([ maxComposition = Math.max(maxComposition, compositionLength); maxRelationships = Math.max(maxRelationships, relationshipLength); + foundTimespan = + foundTimespan || domainObject.hasCapability('timespan'); + metadataProperties.forEach(addMetadataProperty); }); + if (foundTimespan) { + columns.push(new TimespanColumn(true)); + columns.push(new TimespanColumn(false)); + } + for (i = 0; i < maxComposition; i += 1) { columns.push(new CompositionColumn(i)); } @@ -75,14 +85,12 @@ define([ var columns = this.columns; function toRow(domainObject) { - var row = {}; - columns.forEach(function (column) { - row[column.name()] = column.value(domainObject); - }); - return row; + return Promise.all(columns.map(function (column) { + return column.value(domainObject); + })); } - return this.domainObjects.map(toRow); + return Promise.all(this.domainObjects.map(toRow)); }; TimelineCSVExporter.prototype.options = function () { diff --git a/platform/features/timeline/src/actions/TimespanColumn.js b/platform/features/timeline/src/actions/TimespanColumn.js new file mode 100644 index 0000000000..e6cb118591 --- /dev/null +++ b/platform/features/timeline/src/actions/TimespanColumn.js @@ -0,0 +1,44 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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([], function () { + "use strict"; + + function TimespanColumn(isStart) { + this.isStart = isStart; + } + + TimespanColumn.prototype.name = function () { + return this.isStart ? "Start" : "End"; + }; + + TimespanColumn.prototype.value = function (domainObject) { + var isStart = this.isStart; + return domainObject.hasCapability('timespan') ? + domainObject.useCapability('timespan').then(function (timespan) { + return isStart ? timespan.getStart() : timespan.getEnd(); + }) : ""; + }; + + return TimespanColumn; +}); From 14b8e02f27b5baba7c7c89154eb12a6ea148452d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:02:33 -0800 Subject: [PATCH 11/35] [Timeline] Format exported start/end times --- platform/features/timeline/src/actions/TimespanColumn.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/features/timeline/src/actions/TimespanColumn.js b/platform/features/timeline/src/actions/TimespanColumn.js index e6cb118591..b970143f07 100644 --- a/platform/features/timeline/src/actions/TimespanColumn.js +++ b/platform/features/timeline/src/actions/TimespanColumn.js @@ -21,9 +21,11 @@ *****************************************************************************/ /*global define*/ -define([], function () { +define(['../TimelineFormatter'], function (TimelineFormatter) { "use strict"; + var FORMATTER = new TimelineFormatter(); + function TimespanColumn(isStart) { this.isStart = isStart; } @@ -36,7 +38,9 @@ define([], function () { var isStart = this.isStart; return domainObject.hasCapability('timespan') ? domainObject.useCapability('timespan').then(function (timespan) { - return isStart ? timespan.getStart() : timespan.getEnd(); + return FORMATTER.format( + isStart ? timespan.getStart() : timespan.getEnd() + ); }) : ""; }; From c4f1c4ad1f356dd1274a1f5e5691284102d20413 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:09:23 -0800 Subject: [PATCH 12/35] [Timeline] Show progress notification during export --- platform/features/timeline/bundle.js | 2 +- .../src/actions/ExportTimelineAsCSVAction.js | 20 +++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/platform/features/timeline/bundle.js b/platform/features/timeline/bundle.js index 3da27cd925..f298cb887e 100644 --- a/platform/features/timeline/bundle.js +++ b/platform/features/timeline/bundle.js @@ -93,7 +93,7 @@ define([ "name": "Export Timeline as CSV", "category": "contextual", "implementation": ExportTimelineAsCSVAction, - "depends": [ "exportService" ] + "depends": [ "exportService", "notificationService" ] } ], "constants": [ diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js index 099261256f..37c1fddbf0 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js @@ -24,17 +24,29 @@ define(["./ExportTimelineAsCSVTask"], function (ExportTimelineAsCSVTask) { 'use strict'; - function ExportTimelineAsCSVAction(exportService, context) { + function ExportTimelineAsCSVAction(exportService, notificationService, context) { this.task = new ExportTimelineAsCSVTask( exportService, context.domainObject ); - //this.taskService = taskService; + this.notificationService = notificationService; } ExportTimelineAsCSVAction.prototype.perform = function () { - return this.task.run(); - //return this.taskService.run(this.task); + var notificationService = this.notificationService, + notification = notificationService.notify({ + title: "Exporting CSV", + unknownProgress: true + }); + + return this.task.run() + .then(function () { + notification.dismiss(); + }) + .catch(function () { + notification.dismiss(); + notificationService.error("Error exporting CSV"); + }); }; ExportTimelineAsCSVAction.appliesTo = function (context) { From 5d771edcf7bc5b7c027fc4bd51c1b39a78dd4540 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:13:23 -0800 Subject: [PATCH 13/35] [Timeline] Begin testing CSV Export --- .../test/actions/CompositionColumnSpec.js | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 platform/features/timeline/test/actions/CompositionColumnSpec.js diff --git a/platform/features/timeline/test/actions/CompositionColumnSpec.js b/platform/features/timeline/test/actions/CompositionColumnSpec.js new file mode 100644 index 0000000000..d9b340604a --- /dev/null +++ b/platform/features/timeline/test/actions/CompositionColumnSpec.js @@ -0,0 +1,42 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/CompositionColumn'], + function (CompositionColumn) { + describe("CompositionColumn", function () { + var testIndex, + column; + + beforeEach(function () { + testIndex = 42; + column = new CompositionColumn(testIndex); + }); + + it("includes a one-based index in its name", function () { + expect(column.name().indexOf(String(testIndex + 1))) + .not.toEqual(-1); + }); + }); + } +); \ No newline at end of file From cdac0ad67fb3dfb99fb2ae637b11b670db133f25 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:17:19 -0800 Subject: [PATCH 14/35] [Timeline] Add test cases for CSV Export --- .../test/actions/CompositionColumnSpec.js | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/platform/features/timeline/test/actions/CompositionColumnSpec.js b/platform/features/timeline/test/actions/CompositionColumnSpec.js index d9b340604a..99e23d5597 100644 --- a/platform/features/timeline/test/actions/CompositionColumnSpec.js +++ b/platform/features/timeline/test/actions/CompositionColumnSpec.js @@ -29,7 +29,7 @@ define( column; beforeEach(function () { - testIndex = 42; + testIndex = 3; column = new CompositionColumn(testIndex); }); @@ -37,6 +37,38 @@ define( expect(column.name().indexOf(String(testIndex + 1))) .not.toEqual(-1); }); + + describe("value", function () { + var mockDomainObject, + testModel; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability' ] + ); + testModel = { + composition: [ 'a', 'b', 'c', 'd', 'e', 'f' ] + }; + mockDomainObject.getModel.andReturn(testModel); + }); + + it("returns a corresponding identifier", function () { + expect(column.value(mockDomainObject)) + .toEqual(testModel.composition[testIndex]); + }); + + it("returns nothing when composition is exceeded", function () { + testModel.composition = [ 'foo' ]; + expect(column.value(mockDomainObject)).toEqual(""); + }); + + it("returns nothing when composition is absent", function () { + delete testModel.composition; + expect(column.value(mockDomainObject)).toEqual(""); + }); + }); + }); } ); \ No newline at end of file From f9ff9921a94488c749b966941407fc363b233a12 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:22:39 -0800 Subject: [PATCH 15/35] [Timelines] Continue testing CSV Export ...with initial test cases for the action itself. --- .../actions/ExportTimelineAsCSVActionSpec.js | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js diff --git a/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js b/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js new file mode 100644 index 0000000000..5c2a561728 --- /dev/null +++ b/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js @@ -0,0 +1,63 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/ExportTimelineAsCSVAction'], + function (ExportTimelineAsCSVAction) { + describe("ExportTimelineAsCSVAction", function () { + var mockDomainObject, + mockType, + testContext, + testType, + action; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability', 'hasCapability' ] + ); + mockType = jasmine.createSpyObj('type', [ 'instanceOf' ]); + + mockDomainObject.hasCapability.andReturn(true); + mockDomainObject.getCapability.andReturn(mockType); + mockType.instanceOf.andCallFake(function (type) { + return type === testType; + }); + + testContext = { domainObject: mockDomainObject }; + }); + + it("is applicable to timelines", function () { + testType = 'timeline'; + expect(ExportTimelineAsCSVAction.appliesTo(testContext)) + .toBe(true); + }); + + it("is not applicable to non-timelines", function () { + testType = 'folder'; + expect(ExportTimelineAsCSVAction.appliesTo(testContext)) + .toBe(false); + }); + }); + } +); \ No newline at end of file From 7c140c06dc42cc231e509c95212ecb7121f9cca7 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:33:03 -0800 Subject: [PATCH 16/35] [Timeline] Test CSV Export action itself --- .../actions/ExportTimelineAsCSVActionSpec.js | 92 ++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js b/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js index 5c2a561728..3d5cd8b01c 100644 --- a/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js +++ b/platform/features/timeline/test/actions/ExportTimelineAsCSVActionSpec.js @@ -25,7 +25,10 @@ define( ['../../src/actions/ExportTimelineAsCSVAction'], function (ExportTimelineAsCSVAction) { describe("ExportTimelineAsCSVAction", function () { - var mockDomainObject, + var mockExportService, + mockNotificationService, + mockNotification, + mockDomainObject, mockType, testContext, testType, @@ -37,6 +40,20 @@ define( [ 'getId', 'getModel', 'getCapability', 'hasCapability' ] ); mockType = jasmine.createSpyObj('type', [ 'instanceOf' ]); + mockExportService = jasmine.createSpyObj( + 'exportService', + [ 'exportCSV' ] + ); + mockNotificationService = jasmine.createSpyObj( + 'notificationService', + [ 'notify', 'error' ] + ); + mockNotification = jasmine.createSpyObj( + 'notification', + [ 'dismiss' ] + ); + + mockNotificationService.notify.andReturn(mockNotification); mockDomainObject.hasCapability.andReturn(true); mockDomainObject.getCapability.andReturn(mockType); @@ -45,6 +62,12 @@ define( }); testContext = { domainObject: mockDomainObject }; + + action = new ExportTimelineAsCSVAction( + mockExportService, + mockNotificationService, + testContext + ); }); it("is applicable to timelines", function () { @@ -58,6 +81,73 @@ define( expect(ExportTimelineAsCSVAction.appliesTo(testContext)) .toBe(false); }); + + describe("when performed", function () { + var testPromise, + mockCallback; + + beforeEach(function () { + mockCallback = jasmine.createSpy('callback'); + // White-boxy; we know most work is delegated + // to the associated Task, so stub out that interaction. + spyOn(action.task, "run").andCallFake(function () { + return new Promise(function (resolve, reject) { + testPromise = { + resolve: resolve, + reject: reject + }; + }); + }); + action.perform().then(mockCallback); + }); + + it("shows a notification", function () { + expect(mockNotificationService.notify) + .toHaveBeenCalled(); + }); + + it("starts an export task", function () { + expect(action.task.run).toHaveBeenCalled(); + }); + + describe("and completed", function () { + beforeEach(function () { + testPromise.resolve(); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + }); + + it("dismisses the displayed notification", function () { + expect(mockNotification.dismiss) + .toHaveBeenCalled(); + }); + + it("shows no error messages", function () { + expect(mockNotificationService.error) + .not.toHaveBeenCalled(); + }); + }); + + describe("and an error occurs", function () { + beforeEach(function () { + testPromise.reject(); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + }); + + it("dismisses the displayed notification", function () { + expect(mockNotification.dismiss) + .toHaveBeenCalled(); + }); + + it("shows an error message", function () { + expect(mockNotificationService.error) + .toHaveBeenCalledWith(jasmine.any(String)); + }); + }); + }); }); } ); \ No newline at end of file From d5283d57e4331ca58638723fa3e34306e4e4ce7c Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 7 Mar 2016 16:35:40 -0800 Subject: [PATCH 17/35] [Timeline] Add missing semicolon --- platform/features/timeline/src/actions/TimelineCSVExporter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index 4ef27b3bc3..bc73d6f782 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -41,7 +41,7 @@ define([ var name = property.name; if (!columnNames[name]) { columnNames[name] = true; - columns.push(new MetadataColumn(name)) + columns.push(new MetadataColumn(name)); } } From dd66cb60d8bdf98b7ccae39c725015d2cd4b8860 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 09:47:09 -0800 Subject: [PATCH 18/35] [Timeline] Test export task --- .../actions/ExportTimelineAsCSVTaskSpec.js | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 platform/features/timeline/test/actions/ExportTimelineAsCSVTaskSpec.js diff --git a/platform/features/timeline/test/actions/ExportTimelineAsCSVTaskSpec.js b/platform/features/timeline/test/actions/ExportTimelineAsCSVTaskSpec.js new file mode 100644 index 0000000000..7979104ee5 --- /dev/null +++ b/platform/features/timeline/test/actions/ExportTimelineAsCSVTaskSpec.js @@ -0,0 +1,79 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/ExportTimelineAsCSVTask'], + function (ExportTimelineAsCSVTask) { + 'use strict'; + + // Note that most responsibility is delegated to helper + // classes, so testing here is minimal. + describe("EXportTimelineAsCSVTask", function () { + var mockExportService, + mockDomainObject, + task; + + beforeEach(function () { + mockExportService = jasmine.createSpyObj( + 'exportService', + [ 'exportCSV' ] + ); + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ + 'getCapability', + 'useCapability', + 'hasCapability', + 'getId', + 'getModel' + ] + ); + + mockDomainObject.getId.andReturn('mock'); + mockDomainObject.getModel.andReturn({}); + + task = new ExportTimelineAsCSVTask( + mockExportService, + mockDomainObject + ); + }); + + describe("when run", function () { + var mockCallback; + + beforeEach(function () { + mockCallback = jasmine.createSpy('callback'); + task.run().then(mockCallback); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + }); + + it("exports to CSV", function () { + expect(mockExportService.exportCSV) + .toHaveBeenCalled(); + }); + }); + }); + } +); From ed679756b36301e4bf77faec1aa54888aa3aa6e2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 09:56:21 -0800 Subject: [PATCH 19/35] [Timelines] Test metadata columns in CSV Export ...and additionally refactor to run in a test environment (don't use Array.prototype.find) --- .../timeline/src/actions/MetadataColumn.js | 10 +-- .../test/actions/MetadataColumnSpec.js | 76 +++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 platform/features/timeline/test/actions/MetadataColumnSpec.js diff --git a/platform/features/timeline/src/actions/MetadataColumn.js b/platform/features/timeline/src/actions/MetadataColumn.js index 64a0d5b2bb..ee8694082b 100644 --- a/platform/features/timeline/src/actions/MetadataColumn.js +++ b/platform/features/timeline/src/actions/MetadataColumn.js @@ -34,11 +34,11 @@ define([], function () { MetadataColumn.prototype.value = function (domainObject) { var properties = domainObject.useCapability('metadata'), - name = this.propertyName, - property = properties.find(function (p) { - return p.name === name; - }); - return property ? property.value : ""; + name = this.propertyName; + return properties.reduce(function (value, property) { + return property.name === name ? + property.value : value; + }, ""); }; return MetadataColumn; diff --git a/platform/features/timeline/test/actions/MetadataColumnSpec.js b/platform/features/timeline/test/actions/MetadataColumnSpec.js new file mode 100644 index 0000000000..ba38fc83c0 --- /dev/null +++ b/platform/features/timeline/test/actions/MetadataColumnSpec.js @@ -0,0 +1,76 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/MetadataColumn'], + function (MetadataColumn) { + describe("MetadataColumn", function () { + var testName, + column; + + beforeEach(function () { + testName = 'Foo'; + column = new MetadataColumn(testName); + }); + + it("reports its property name", function () { + expect(column.name()).toEqual(testName); + }); + + describe("value", function () { + var mockDomainObject, + testMetadata, + testIndex; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability', 'useCapability' ] + ); + testMetadata = [ + { name: "Something else", value: 123 }, + { value: 456 }, + { name: "And something else", value: 789 } + ]; + testIndex = 1; + testMetadata[testIndex].name = testName; + + mockDomainObject.useCapability.andCallFake(function (c) { + return (c === 'metadata') && testMetadata; + }); + }); + + it("returns a corresponding value", function () { + expect(column.value(mockDomainObject)) + .toEqual(testMetadata[testIndex].value); + }); + + it("returns nothing when no such property is present", function () { + testMetadata[testIndex].name = "Not " + testName; + expect(column.value(mockDomainObject)).toEqual(""); + }); + }); + + }); + } +); \ No newline at end of file From 75d6803c9f35cbca753618e5ccdd11072e4c9e7a Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 09:59:54 -0800 Subject: [PATCH 20/35] [Timeline] Test mode columns in CSV Export --- .../timeline/src/actions/ModeColumn.js | 2 +- .../timeline/test/actions/ModeColumnSpec.js | 76 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 platform/features/timeline/test/actions/ModeColumnSpec.js diff --git a/platform/features/timeline/src/actions/ModeColumn.js b/platform/features/timeline/src/actions/ModeColumn.js index 0a88437211..20a9de0e50 100644 --- a/platform/features/timeline/src/actions/ModeColumn.js +++ b/platform/features/timeline/src/actions/ModeColumn.js @@ -29,7 +29,7 @@ define([], function () { } ModeColumn.prototype.name = function () { - return "Mode " + (this.index + 1); + return "Activity Mode " + (this.index + 1); }; ModeColumn.prototype.value = function (domainObject) { diff --git a/platform/features/timeline/test/actions/ModeColumnSpec.js b/platform/features/timeline/test/actions/ModeColumnSpec.js new file mode 100644 index 0000000000..ab15d696c2 --- /dev/null +++ b/platform/features/timeline/test/actions/ModeColumnSpec.js @@ -0,0 +1,76 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/ModeColumn'], + function (ModeColumn) { + describe("ModeColumn", function () { + var testIndex, + column; + + beforeEach(function () { + testIndex = 3; + column = new ModeColumn(testIndex); + }); + + it("includes a one-based index in its name", function () { + expect(column.name().indexOf(String(testIndex + 1))) + .not.toEqual(-1); + }); + + describe("value", function () { + var mockDomainObject, + testModel; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability' ] + ); + testModel = { + relationships: { + modes: [ 'a', 'b', 'c', 'd', 'e', 'f' ] + } + }; + mockDomainObject.getModel.andReturn(testModel); + }); + + it("returns a corresponding identifier", function () { + expect(column.value(mockDomainObject)) + .toEqual(testModel.relationships.modes[testIndex]); + }); + + it("returns nothing when relationships are exceeded", function () { + testModel.relationships.modes = [ 'foo' ]; + expect(column.value(mockDomainObject)).toEqual(""); + }); + + it("returns nothing when mode relationships are absent", function () { + delete testModel.relationships.modes; + expect(column.value(mockDomainObject)).toEqual(""); + }); + }); + + }); + } +); \ No newline at end of file From 43db52fd702e156025141e4d2e7a61871f5751df Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:04:09 -0800 Subject: [PATCH 21/35] [Timeline] Simplify interface ...such that responsibility for knowing exportService interface is more localized. --- .../timeline/src/actions/ExportTimelineAsCSVTask.js | 5 +++-- .../timeline/src/actions/TimelineCSVExporter.js | 10 ++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 8a0b60ca94..790b165fd7 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -45,9 +45,10 @@ define([ var exportService = this.exportService; function doExport(objects) { - var exporter = new TimelineCSVExporter(objects); + var exporter = new TimelineCSVExporter(objects), + options = { headers: exporter.headers() }; return exporter.rows().then(function (rows) { - return exportService.exportCSV(rows, exporter.options()); + return exportService.exportCSV(rows, options); }); } diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index bc73d6f782..3ebe37db1c 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -93,12 +93,10 @@ define([ return Promise.all(this.domainObjects.map(toRow)); }; - TimelineCSVExporter.prototype.options = function () { - return { - headers: this.columns.map(function (column) { - return column.name(); - }) - }; + TimelineCSVExporter.prototype.headers = function () { + return this.columns.map(function (column) { + return column.name(); + }); }; return TimelineCSVExporter; From 40895ec1b97bad45600527fb6f05c024f7b8b501 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:07:21 -0800 Subject: [PATCH 22/35] [Timelines] Begin spec for exporter --- .../test/actions/TimelineCSVExporterSpec.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 platform/features/timeline/test/actions/TimelineCSVExporterSpec.js diff --git a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js new file mode 100644 index 0000000000..c07eb29756 --- /dev/null +++ b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js @@ -0,0 +1,51 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/TimelineCSVExporter'], + function (TimelineCSVExporter) { + describe("TimelineCSVExporter", function () { + var mockDomainObjects, + exporter; + + beforeEach(function () { + mockDomainObjects = []; + exporter = new TimelineCSVExporter(mockDomainObjects); + }); + + it("includes one row per domain object", function () { + var mockCallback = jasmine.createSpy('callback'); + exporter.rows().then(mockCallback); + waitsFor(function () { + return mockCallback.calls.length > 0; + }); + runs(function () { + expect(mockCallback.mostRecentCall.args[0].length) + .toEqual(mockDomainObjects.length); + }); + }); + + + }); + } +); \ No newline at end of file From 9e6e33983b7f4a9017387519298553d3b80f46c1 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:17:10 -0800 Subject: [PATCH 23/35] [Timeline] Add more objects to test case --- .../test/actions/TimelineCSVExporterSpec.js | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js index c07eb29756..0fb602e2ce 100644 --- a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js +++ b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js @@ -28,8 +28,29 @@ define( var mockDomainObjects, exporter; + function makeMockDomainObject(model, index) { + var mockDomainObject = jasmine.createSpyObj( + 'domainObject-' + index, + [ + 'getId', + 'getCapability', + 'useCapability', + 'hasCapability', + 'getModel' + ] + ); + mockDomainObject.getId.andReturn('id-' + index); + mockDomainObject.getModel.andReturn(model); + return mockDomainObject; + } + beforeEach(function () { - mockDomainObjects = []; + mockDomainObjects = [ + { composition: [ 'a', 'b', 'c' ] }, + { relationships: { modes: [ 'x', 'y' ] } }, + { } + ].map(makeMockDomainObject); + exporter = new TimelineCSVExporter(mockDomainObjects); }); From 938c266b4e718ad1e5ddcba35c1250ba741f144b Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:20:25 -0800 Subject: [PATCH 24/35] [Timeline] Add Id column to CSV export --- .../features/timeline/src/actions/IdColumn.js | 39 +++++++++++++++++++ .../src/actions/TimelineCSVExporter.js | 11 +++++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 platform/features/timeline/src/actions/IdColumn.js diff --git a/platform/features/timeline/src/actions/IdColumn.js b/platform/features/timeline/src/actions/IdColumn.js new file mode 100644 index 0000000000..6efeb104d3 --- /dev/null +++ b/platform/features/timeline/src/actions/IdColumn.js @@ -0,0 +1,39 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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([], function () { + "use strict"; + + function IdColumn() { + } + + IdColumn.prototype.name = function () { + return "Identifier"; + }; + + IdColumn.prototype.value = function (domainObject) { + return domainObject.getId(); + }; + + return IdColumn; +}); diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index 3ebe37db1c..f0d3efd953 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -22,11 +22,18 @@ /*global define,Promise*/ define([ + "./IdColumn", "./ModeColumn", "./CompositionColumn", "./MetadataColumn", "./TimespanColumn" -], function (ModeColumn, CompositionColumn, MetadataColumn, TimespanColumn) { +], function ( + IdColumn, + ModeColumn, + CompositionColumn, + MetadataColumn, + TimespanColumn +) { 'use strict'; function TimelineCSVExporter(domainObjects) { @@ -45,6 +52,8 @@ define([ } } + columns.push(new IdColumn()); + domainObjects.forEach(function (domainObject) { var model = domainObject.getModel(), compositionLength = model.composition ? From fd92c5f97088868dd277dfbb3f75db9674823bd0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:22:46 -0800 Subject: [PATCH 25/35] [Timeline] Add more tests for rows --- .../test/actions/TimelineCSVExporterSpec.js | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js index 0fb602e2ce..cbe382c988 100644 --- a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js +++ b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js @@ -54,19 +54,33 @@ define( exporter = new TimelineCSVExporter(mockDomainObjects); }); - it("includes one row per domain object", function () { - var mockCallback = jasmine.createSpy('callback'); - exporter.rows().then(mockCallback); - waitsFor(function () { - return mockCallback.calls.length > 0; + describe("rows", function () { + var rows; + + beforeEach(function () { + exporter.rows().then(function (r) { + rows = r; + }); + waitsFor(function () { + return rows !== undefined; + }); }); - runs(function () { - expect(mockCallback.mostRecentCall.args[0].length) - .toEqual(mockDomainObjects.length); + + + it("include one row per domain object", function () { + expect(rows.length).toEqual(mockDomainObjects.length); + }); + + it("includes identifiers for each domain object", function () { + rows.forEach(function (row, index) { + var id = mockDomainObjects[index].getId(); + expect(row.indexOf(id)).not.toEqual(-1); + }); }); }); + }); } ); \ No newline at end of file From 0c2285719e66088301266131cbfd7c73267191bf Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:27:50 -0800 Subject: [PATCH 26/35] [Timeline] Test inclusion of metadata headers --- .../test/actions/TimelineCSVExporterSpec.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js index cbe382c988..d406db43b7 100644 --- a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js +++ b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js @@ -26,6 +26,7 @@ define( function (TimelineCSVExporter) { describe("TimelineCSVExporter", function () { var mockDomainObjects, + testMetadata, exporter; function makeMockDomainObject(model, index) { @@ -41,16 +42,28 @@ define( ); mockDomainObject.getId.andReturn('id-' + index); mockDomainObject.getModel.andReturn(model); + mockDomainObject.useCapability.andCallFake(function (c) { + return c === 'metadata' && []; + }); return mockDomainObject; } beforeEach(function () { + testMetadata = [ + { name: "abc", value: 123 }, + { name: "xyz", value: 456 } + ]; + mockDomainObjects = [ { composition: [ 'a', 'b', 'c' ] }, { relationships: { modes: [ 'x', 'y' ] } }, { } ].map(makeMockDomainObject); + mockDomainObjects[2].useCapability.andCallFake(function (c) { + return c === 'metadata' && testMetadata; + }); + exporter = new TimelineCSVExporter(mockDomainObjects); }); @@ -79,7 +92,20 @@ define( }); }); + describe("headers", function () { + var headers; + beforeEach(function () { + headers = exporter.headers(); + }); + + it("contains all metadata properties", function () { + testMetadata.forEach(function (property) { + expect(headers.indexOf(property.name)) + .not.toEqual(-1); + }); + }); + }); }); } From c23c2b84bf127824dfde959c1ce53c2376393a3f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:31:25 -0800 Subject: [PATCH 27/35] [Timeline] Test inclusion of timespan properties ...in prepared data for CSV export --- .../test/actions/TimelineCSVExporterSpec.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js index d406db43b7..4267f95a1b 100644 --- a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js +++ b/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js @@ -49,6 +49,11 @@ define( } beforeEach(function () { + var mockTimespan = jasmine.createSpyObj( + 'timespan', + [ 'getStart', 'getEnd' ] + ); + testMetadata = [ { name: "abc", value: 123 }, { name: "xyz", value: 456 } @@ -60,6 +65,13 @@ define( { } ].map(makeMockDomainObject); + mockDomainObjects[1].hasCapability.andCallFake(function (c) { + return c === 'timespan'; + }); + mockDomainObjects[1].useCapability.andCallFake(function (c) { + return c === 'timespan' ? Promise.resolve(mockTimespan) : + c === 'metadata' ? [] : undefined; + }); mockDomainObjects[2].useCapability.andCallFake(function (c) { return c === 'metadata' && testMetadata; }); @@ -105,6 +117,11 @@ define( .not.toEqual(-1); }); }); + + it("contains timespan properties", function () { + expect(headers.indexOf("Start")).not.toEqual(-1); + expect(headers.indexOf("End")).not.toEqual(-1); + }); }); }); From 66b1a92554a67d9186b338a74c684edd254c2e4f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:43:13 -0800 Subject: [PATCH 28/35] [Timeline] Add test cases for TimelineTraverser --- .../test/actions/TimelineTraverserSpec.js | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 platform/features/timeline/test/actions/TimelineTraverserSpec.js diff --git a/platform/features/timeline/test/actions/TimelineTraverserSpec.js b/platform/features/timeline/test/actions/TimelineTraverserSpec.js new file mode 100644 index 0000000000..3d9dcfdb4b --- /dev/null +++ b/platform/features/timeline/test/actions/TimelineTraverserSpec.js @@ -0,0 +1,107 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define([ + "../../src/actions/TimelineTraverser" +], function (TimelineTraverser) { + 'use strict'; + + describe("TimelineTraverser", function () { + var testModels, + mockDomainObjects, + traverser; + + function addMockDomainObject(id) { + var mockDomainObject = jasmine.createSpyObj( + 'domainObject-' + id, + [ + 'getId', + 'getCapability', + 'useCapability', + 'hasCapability', + 'getModel' + ] + ), + model = testModels[id]; + + mockDomainObject.getId.andReturn(id); + mockDomainObject.getModel.andReturn(model); + + mockDomainObject.hasCapability.andCallFake(function (c) { + return c === 'composition' ? !!model.composition : + c === 'relationship' ? !!model.relationships : + false; + }); + + mockDomainObjects[id] = mockDomainObject; + } + + beforeEach(function () { + testModels = { + a: { composition: [ 'b', 'c' ]}, + b: { composition: [ 'c' ] }, + c: { relationships: { modes: [ 'd' ] } }, + d: {}, + unreachable: {} + }; + + mockDomainObjects = {}; + Object.keys(testModels).forEach(addMockDomainObject); + + + traverser = new TimelineTraverser(mockDomainObjects.a); + }); + + describe("buildObjectList", function () { + var objects; + + function contains(id) { + return objects.indexOf(mockDomainObjects[id]) !== -1; + } + + beforeEach(function () { + traverser.buildObjectList().then(function (objectList) { + objects = objectList; + }); + }); + + it("includes the object originally passed in", function () { + expect(contains('a')).toBe(true); + }); + + it("includes objects reachable via composition", function () { + expect(contains('b')).toBe(true); + expect(contains('c')).toBe(true); + }); + + it("includes objects reachable via relationships", function () { + expect(contains('d')).toBe(true); + }); + + it("does not include unreachable objects", function () { + expect(contains('unreachable')).toBe(false); + }); + }); + + }); +}); \ No newline at end of file From 5ee5e7fea18d1130cd7aeb07a9cb7b1bb9c3d1b9 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 10:47:01 -0800 Subject: [PATCH 29/35] [Timeline] Add capabilities to test inputs --- .../test/actions/TimelineTraverserSpec.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/platform/features/timeline/test/actions/TimelineTraverserSpec.js b/platform/features/timeline/test/actions/TimelineTraverserSpec.js index 3d9dcfdb4b..1ccb7625c3 100644 --- a/platform/features/timeline/test/actions/TimelineTraverserSpec.js +++ b/platform/features/timeline/test/actions/TimelineTraverserSpec.js @@ -42,6 +42,7 @@ define([ 'getModel' ] ), + mockRelationships, model = testModels[id]; mockDomainObject.getId.andReturn(id); @@ -53,6 +54,31 @@ define([ false; }); + if (!!model.composition) { + mockDomainObject.useCapability.andCallFake(function (c) { + return c === 'composition' && + Promise.resolve(model.composition.map(function (id) { + return mockDomainObjects[id] + })); + }); + } + + if (!!model.relationships) { + mockRelationships = jasmine.createSpyObj( + 'relationship', + ['getRelatedObjects'] + ); + mockRelationships.getRelatedObjects.andCallFake(function (k) { + var ids = model.relationships[k] || []; + return Promise.resolve(ids.map(function (id) { + return mockDomainObjects[id]; + })); + }); + mockDomainObject.getCapability.andCallFake(function (c) { + return c === 'relationship' && mockRelationships; + }); + } + mockDomainObjects[id] = mockDomainObject; } From 0d419fa5fd756c7869f3dd0a126fde288bbfbcc8 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 11:30:26 -0800 Subject: [PATCH 30/35] [Timeline] Test TimelineTraverser --- .../timeline/test/actions/TimelineTraverserSpec.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/features/timeline/test/actions/TimelineTraverserSpec.js b/platform/features/timeline/test/actions/TimelineTraverserSpec.js index 1ccb7625c3..56674c7a6e 100644 --- a/platform/features/timeline/test/actions/TimelineTraverserSpec.js +++ b/platform/features/timeline/test/actions/TimelineTraverserSpec.js @@ -94,7 +94,6 @@ define([ mockDomainObjects = {}; Object.keys(testModels).forEach(addMockDomainObject); - traverser = new TimelineTraverser(mockDomainObjects.a); }); @@ -102,13 +101,18 @@ define([ var objects; function contains(id) { - return objects.indexOf(mockDomainObjects[id]) !== -1; + return objects.some(function (object) { + return object.getId() === id; + }); } beforeEach(function () { traverser.buildObjectList().then(function (objectList) { objects = objectList; }); + waitsFor(function () { + return objects !== undefined; + }); }); it("includes the object originally passed in", function () { From bd7cb98a4c0e74acb1ae7ab52211f8e87d2aeb9d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 11:40:54 -0800 Subject: [PATCH 31/35] [Timeline] Add missing semicolon ...to pass code style checks --- .../features/timeline/test/actions/TimelineTraverserSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/features/timeline/test/actions/TimelineTraverserSpec.js b/platform/features/timeline/test/actions/TimelineTraverserSpec.js index 56674c7a6e..6962373ff9 100644 --- a/platform/features/timeline/test/actions/TimelineTraverserSpec.js +++ b/platform/features/timeline/test/actions/TimelineTraverserSpec.js @@ -58,7 +58,7 @@ define([ mockDomainObject.useCapability.andCallFake(function (c) { return c === 'composition' && Promise.resolve(model.composition.map(function (id) { - return mockDomainObjects[id] + return mockDomainObjects[id]; })); }); } From 9e4e3e9c437d8490334e2159cc48f50b206251eb Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 11:59:53 -0800 Subject: [PATCH 32/35] [Timeline] Add JSDoc Add JSDoc to classes implemented Export Timeline as CSV --- .../timeline/src/actions/CompositionColumn.js | 8 ++++ .../src/actions/ExportTimelineAsCSVAction.js | 10 +++++ .../src/actions/ExportTimelineAsCSVTask.js | 11 ++++- .../features/timeline/src/actions/IdColumn.js | 5 +++ .../timeline/src/actions/MetadataColumn.js | 5 +++ .../timeline/src/actions/ModeColumn.js | 7 +++ .../src/actions/TimelineCSVExporter.js | 44 +++++++++++++++++++ .../timeline/src/actions/TimelineTraverser.js | 10 +++++ .../timeline/src/actions/TimespanColumn.js | 7 +++ 9 files changed, 106 insertions(+), 1 deletion(-) diff --git a/platform/features/timeline/src/actions/CompositionColumn.js b/platform/features/timeline/src/actions/CompositionColumn.js index 6ee7fa010c..b7208c3e92 100644 --- a/platform/features/timeline/src/actions/CompositionColumn.js +++ b/platform/features/timeline/src/actions/CompositionColumn.js @@ -24,6 +24,14 @@ define([], function () { "use strict"; + /** + * A column containing references to other objects contained + * in a domain object's composition. + * @param {number} index the zero-based index of the composition + * element associated with this column + * @constructor + * @implements {platform/features/timeline.TimelineCSVColumn} + */ function CompositionColumn(index) { this.index = index; } diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js index 37c1fddbf0..387c0839a0 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVAction.js @@ -24,6 +24,16 @@ define(["./ExportTimelineAsCSVTask"], function (ExportTimelineAsCSVTask) { 'use strict'; + /** + * Implements the "Export Timeline as CSV" action. + * + * @param exportService the service used to perform the CSV export + * @param notificationService the service used to show notifications + * @param context the Action's context + * @implements {Action} + * @constructor + * @memberof {platform/features/timeline} + */ function ExportTimelineAsCSVAction(exportService, notificationService, context) { this.task = new ExportTimelineAsCSVTask( exportService, diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 790b165fd7..2193c6510f 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -31,16 +31,25 @@ define([ "use strict"; /** + * Runs (and coordinates) the preparation and export of CSV data + * for the "Export Timeline as CSV" action. * * @constructor * @memberof {platform/features/timeline} - * @implements {Task} + * @param exportService the service used to export as CSV + * @param {DomainObject} domainObject the timeline being exported */ function ExportTimelineAsCSVTask(exportService, domainObject) { this.domainObject = domainObject; this.exportService = exportService; } + /** + * Run this CSV export task. + * + * @returns {Promise} a promise that will be resolved when the + * export has finished (or rejected if there are problems.) + */ ExportTimelineAsCSVTask.prototype.run = function () { var exportService = this.exportService; diff --git a/platform/features/timeline/src/actions/IdColumn.js b/platform/features/timeline/src/actions/IdColumn.js index 6efeb104d3..56ddfe385f 100644 --- a/platform/features/timeline/src/actions/IdColumn.js +++ b/platform/features/timeline/src/actions/IdColumn.js @@ -24,6 +24,11 @@ define([], function () { "use strict"; + /** + * A column showing domain object identifiers. + * @constructor + * @implements {platform/features/timeline.TimelineCSVColumn} + */ function IdColumn() { } diff --git a/platform/features/timeline/src/actions/MetadataColumn.js b/platform/features/timeline/src/actions/MetadataColumn.js index ee8694082b..c94237a917 100644 --- a/platform/features/timeline/src/actions/MetadataColumn.js +++ b/platform/features/timeline/src/actions/MetadataColumn.js @@ -24,6 +24,11 @@ define([], function () { "use strict"; + /** + * A column reflecting properties from domain object metadata. + * @constructor + * @implements {platform/features/timeline.TimelineCSVColumn} + */ function MetadataColumn(propertyName) { this.propertyName = propertyName; } diff --git a/platform/features/timeline/src/actions/ModeColumn.js b/platform/features/timeline/src/actions/ModeColumn.js index 20a9de0e50..4ae61b30d3 100644 --- a/platform/features/timeline/src/actions/ModeColumn.js +++ b/platform/features/timeline/src/actions/ModeColumn.js @@ -24,6 +24,13 @@ define([], function () { "use strict"; + /** + * A column showing relationships to activity modes. + * @constructor + * @param {number} index the zero-based index of the composition + * element associated with this column + * @implements {platform/features/timeline.TimelineCSVColumn} + */ function ModeColumn(index) { this.index = index; } diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index f0d3efd953..17d8941865 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -36,6 +36,38 @@ define([ ) { 'use strict'; + /** + * A description of how to populate a given column within a + * prepared table of domain object data, for CSV export. + * @interface platform/features/timeline.TimelineCSVColumn + */ + + /** + * Get the value that belongs in this column for a given + * domain object. + * @memberof {platform/features/timeline.TimelineCSVColumn#} + * @method value + * @param {DomainObject} domainObject the domain object + * represented by this row + * @returns {string|Promise} the value for this cell + */ + + /** + * Get the name of this column, as belongs in a header. + * @memberof {platform/features/timeline.TimelineCSVColumn#} + * @method name + * @returns {string} the name of this column + */ + + /** + * Handles conversion of a list of domain objects to a table + * representation appropriate for CSV export. + * + * @param {DomainObject[]} domainObjects the objects to include + * in the exported data + * @constructor + * @memberof {platform/features/timeline} + */ function TimelineCSVExporter(domainObjects) { var maxComposition = 0, maxRelationships = 0, @@ -90,6 +122,13 @@ define([ this.columns = columns; } + /** + * Get a tabular representation of domain object data. + * Each row corresponds to a single object; each element + * in each row corresponds to a property designated by + * the `headers`, correlated by index. + * @returns {Promise.} domain object data + */ TimelineCSVExporter.prototype.rows = function () { var columns = this.columns; @@ -102,6 +141,11 @@ define([ return Promise.all(this.domainObjects.map(toRow)); }; + /** + * Get the column headers associated with this tabular + * representation of objects. + * @returns {string[]} column headers + */ TimelineCSVExporter.prototype.headers = function () { return this.columns.map(function (column) { return column.name(); diff --git a/platform/features/timeline/src/actions/TimelineTraverser.js b/platform/features/timeline/src/actions/TimelineTraverser.js index 48817b6963..f6857658fb 100644 --- a/platform/features/timeline/src/actions/TimelineTraverser.js +++ b/platform/features/timeline/src/actions/TimelineTraverser.js @@ -24,10 +24,20 @@ define([], function () { "use strict"; + /** + * Builds a list of domain objects which should be included + * in the CSV export of a given timeline. + * @param {DomainObject} domainObject the object being exported + * @constructor + */ function TimelineTraverser(domainObject) { this.domainObject = domainObject; } + /** + * Get a list of domain objects for CSV export. + * @returns {Promise.} a list of domain objects + */ TimelineTraverser.prototype.buildObjectList = function () { var idSet = {}, objects = []; diff --git a/platform/features/timeline/src/actions/TimespanColumn.js b/platform/features/timeline/src/actions/TimespanColumn.js index b970143f07..6d0c4e05a9 100644 --- a/platform/features/timeline/src/actions/TimespanColumn.js +++ b/platform/features/timeline/src/actions/TimespanColumn.js @@ -26,6 +26,13 @@ define(['../TimelineFormatter'], function (TimelineFormatter) { var FORMATTER = new TimelineFormatter(); + /** + * A column showing start or end times associated with a domain object. + * @constructor + * @param {boolean} isStart true if this column refers to the object's + * start time; false if it refers to the object's end time + * @implements {platform/features/timeline.TimelineCSVColumn} + */ function TimespanColumn(isStart) { this.isStart = isStart; } From 406a31889ef4ca05861207c4e136ed710f88ff10 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 8 Mar 2016 12:34:08 -0800 Subject: [PATCH 33/35] [Timeline] Add specs for remaining columns --- .../timeline/test/actions/IdColumnSpec.js | 59 ++++++++++++ .../test/actions/TimespanColumnSpec.js | 94 +++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 platform/features/timeline/test/actions/IdColumnSpec.js create mode 100644 platform/features/timeline/test/actions/TimespanColumnSpec.js diff --git a/platform/features/timeline/test/actions/IdColumnSpec.js b/platform/features/timeline/test/actions/IdColumnSpec.js new file mode 100644 index 0000000000..a12b6145a9 --- /dev/null +++ b/platform/features/timeline/test/actions/IdColumnSpec.js @@ -0,0 +1,59 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/IdColumn'], + function (IdColumn) { + describe("IdColumn", function () { + var column; + + beforeEach(function () { + column = new IdColumn(); + }); + + it("has a name", function () { + expect(column.name()).toEqual(jasmine.any(String)); + }); + + describe("value", function () { + var mockDomainObject, + testId; + + beforeEach(function () { + testId = "foo"; + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'getId', 'getModel', 'getCapability' ] + ); + mockDomainObject.getId.andReturn(testId); + }); + + it("provides a domain object's identifier", function () { + expect(column.value(mockDomainObject)) + .toEqual(testId); + }); + }); + + }); + } +); \ No newline at end of file diff --git a/platform/features/timeline/test/actions/TimespanColumnSpec.js b/platform/features/timeline/test/actions/TimespanColumnSpec.js new file mode 100644 index 0000000000..f4970b778e --- /dev/null +++ b/platform/features/timeline/test/actions/TimespanColumnSpec.js @@ -0,0 +1,94 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2009-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ + +define( + ['../../src/actions/TimespanColumn', '../../src/TimelineFormatter'], + function (TimespanColumn, TimelineFormatter) { + describe("TimespanColumn", function () { + var testTimes, + mockTimespan, + mockDomainObject, + column; + + beforeEach(function () { + testTimes = { + start: 101000, + end: 987654321 + }; + mockTimespan = jasmine.createSpyObj( + 'timespan', + [ 'getStart', 'getEnd' ] + ); + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ 'useCapability', 'hasCapability' ] + ); + mockTimespan.getStart.andReturn(testTimes.start); + mockTimespan.getEnd.andReturn(testTimes.end); + mockDomainObject.useCapability.andCallFake(function (c) { + return c === 'timespan' && Promise.resolve(mockTimespan); + }); + mockDomainObject.hasCapability.andCallFake(function (c) { + return c === 'timespan'; + }); + }); + + [ "start", "end" ].forEach(function (bound) { + describe("when referring to " + bound + " times", function () { + var name = bound.charAt(0).toUpperCase() + bound.slice(1); + + beforeEach(function () { + column = new TimespanColumn(bound === "start"); + }); + + it("is named \"" + name + "\"", function () { + expect(column.name()).toEqual(name); + }); + + describe("value", function () { + var testFormatter, + value; + + beforeEach(function () { + value = undefined; + testFormatter = new TimelineFormatter(); + column.value(mockDomainObject).then(function (v) { + value = v; + }); + waitsFor(function () { + return value !== undefined; + }); + }); + + it("returns a formatted " + bound + " time", function () { + var expected = + testFormatter.format(testTimes[bound]); + expect(value).toEqual(expected); + }); + }); + }); + }); + + }); + } +); \ No newline at end of file From 0ff360ced31885ce51e38e50de56322156787fec Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 14 Mar 2016 11:53:28 -0700 Subject: [PATCH 34/35] [Timelines] Remove excessive ternaries ...to improve readability of logic to determine which columns are needed for a given group of domain objects for CSV export, as requested during code review, https://github.com/nasa/openmctweb/pull/728#discussion_r55910477 --- .../src/actions/TimelineCSVExporter.js | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineCSVExporter.js index 17d8941865..edf06bec7b 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineCSVExporter.js @@ -88,21 +88,26 @@ define([ domainObjects.forEach(function (domainObject) { var model = domainObject.getModel(), - compositionLength = model.composition ? - model.composition.length : 0, - relationshipLength = (model.relationships || {}).modes ? - model.relationships.modes.length : - 0, - metadataProperties = - domainObject.useCapability('metadata') || []; + composition = model.composition, + relationships = model.relationships, + modes = relationships && relationships.modes, + metadataProperties = domainObject.useCapability('metadata'); - maxComposition = Math.max(maxComposition, compositionLength); - maxRelationships = Math.max(maxRelationships, relationshipLength); + if (composition) { + maxComposition = Math.max(maxComposition, composition.length); + } - foundTimespan = - foundTimespan || domainObject.hasCapability('timespan'); + if (modes) { + maxRelationships = Math.max(maxRelationships, modes.length); + } - metadataProperties.forEach(addMetadataProperty); + if (domainObject.hasCapability('timespan')) { + foundTimespan = true; + } + + if (metadataProperties) { + metadataProperties.forEach(addMetadataProperty); + } }); if (foundTimespan) { @@ -153,4 +158,4 @@ define([ }; return TimelineCSVExporter; -}); \ No newline at end of file +}); From f2c040367b61a07039b2ab6ddae2bbda328bccde Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 14 Mar 2016 11:59:19 -0700 Subject: [PATCH 35/35] [Timeline] Rename TimelineCSVExporter ...to TimelineColumnizer, clarifying its role/responsibilities in the context of the CSV export task; https://github.com/nasa/openmctweb/pull/728#discussion_r56031331 --- .../timeline/src/actions/ExportTimelineAsCSVTask.js | 6 +++--- .../{TimelineCSVExporter.js => TimelineColumnizer.js} | 8 ++++---- ...ineCSVExporterSpec.js => TimelineColumnizerSpec.js} | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) rename platform/features/timeline/src/actions/{TimelineCSVExporter.js => TimelineColumnizer.js} (96%) rename platform/features/timeline/test/actions/{TimelineCSVExporterSpec.js => TimelineColumnizerSpec.js} (95%) diff --git a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js index 2193c6510f..253db5c8b9 100644 --- a/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js +++ b/platform/features/timeline/src/actions/ExportTimelineAsCSVTask.js @@ -26,8 +26,8 @@ */ define([ "./TimelineTraverser", - "./TimelineCSVExporter" -], function (TimelineTraverser, TimelineCSVExporter) { + "./TimelineColumnizer" +], function (TimelineTraverser, TimelineColumnizer) { "use strict"; /** @@ -54,7 +54,7 @@ define([ var exportService = this.exportService; function doExport(objects) { - var exporter = new TimelineCSVExporter(objects), + var exporter = new TimelineColumnizer(objects), options = { headers: exporter.headers() }; return exporter.rows().then(function (rows) { return exportService.exportCSV(rows, options); diff --git a/platform/features/timeline/src/actions/TimelineCSVExporter.js b/platform/features/timeline/src/actions/TimelineColumnizer.js similarity index 96% rename from platform/features/timeline/src/actions/TimelineCSVExporter.js rename to platform/features/timeline/src/actions/TimelineColumnizer.js index edf06bec7b..3069bd8b96 100644 --- a/platform/features/timeline/src/actions/TimelineCSVExporter.js +++ b/platform/features/timeline/src/actions/TimelineColumnizer.js @@ -68,7 +68,7 @@ define([ * @constructor * @memberof {platform/features/timeline} */ - function TimelineCSVExporter(domainObjects) { + function TimelineColumnizer(domainObjects) { var maxComposition = 0, maxRelationships = 0, columnNames = {}, @@ -134,7 +134,7 @@ define([ * the `headers`, correlated by index. * @returns {Promise.} domain object data */ - TimelineCSVExporter.prototype.rows = function () { + TimelineColumnizer.prototype.rows = function () { var columns = this.columns; function toRow(domainObject) { @@ -151,11 +151,11 @@ define([ * representation of objects. * @returns {string[]} column headers */ - TimelineCSVExporter.prototype.headers = function () { + TimelineColumnizer.prototype.headers = function () { return this.columns.map(function (column) { return column.name(); }); }; - return TimelineCSVExporter; + return TimelineColumnizer; }); diff --git a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js b/platform/features/timeline/test/actions/TimelineColumnizerSpec.js similarity index 95% rename from platform/features/timeline/test/actions/TimelineCSVExporterSpec.js rename to platform/features/timeline/test/actions/TimelineColumnizerSpec.js index 4267f95a1b..9eacf4f3b3 100644 --- a/platform/features/timeline/test/actions/TimelineCSVExporterSpec.js +++ b/platform/features/timeline/test/actions/TimelineColumnizerSpec.js @@ -22,9 +22,9 @@ /*global define,describe,it,expect,beforeEach,waitsFor,jasmine,window,afterEach*/ define( - ['../../src/actions/TimelineCSVExporter'], - function (TimelineCSVExporter) { - describe("TimelineCSVExporter", function () { + ['../../src/actions/TimelineColumnizer'], + function (TimelineColumnizer) { + describe("TimelineColumnizer", function () { var mockDomainObjects, testMetadata, exporter; @@ -76,7 +76,7 @@ define( return c === 'metadata' && testMetadata; }); - exporter = new TimelineCSVExporter(mockDomainObjects); + exporter = new TimelineColumnizer(mockDomainObjects); }); describe("rows", function () { @@ -126,4 +126,4 @@ define( }); } -); \ No newline at end of file +);