mirror of
https://github.com/nasa/openmct.git
synced 2024-12-21 22:17:49 +00:00
Merge remote-tracking branch 'origin/open670'
This commit is contained in:
commit
7e60593501
1
main.js
1
main.js
@ -77,6 +77,7 @@ define([
|
||||
'./platform/features/plot/bundle',
|
||||
'./platform/features/scrolling/bundle',
|
||||
'./platform/features/timeline/bundle',
|
||||
'./platform/features/table/bundle',
|
||||
'./platform/forms/bundle',
|
||||
'./platform/identity/bundle',
|
||||
'./platform/persistence/aggregator/bundle',
|
||||
|
125
platform/features/table/bundle.js
Normal file
125
platform/features/table/bundle.js
Normal file
@ -0,0 +1,125 @@
|
||||
/*****************************************************************************
|
||||
* 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([
|
||||
"./src/directives/MCTTable",
|
||||
"./src/controllers/TelemetryTableController",
|
||||
"./src/controllers/TableOptionsController",
|
||||
'../../commonUI/regions/src/Region',
|
||||
'../../commonUI/browse/src/InspectorRegion',
|
||||
"legacyRegistry"
|
||||
], function (
|
||||
MCTTable,
|
||||
TelemetryTableController,
|
||||
TableOptionsController,
|
||||
Region,
|
||||
InspectorRegion,
|
||||
legacyRegistry
|
||||
) {
|
||||
"use strict";
|
||||
/**
|
||||
* Two region parts are defined here. One that appears only in browse
|
||||
* mode, and one that appears only in edit mode. For not they both point
|
||||
* to the same representation, but a different key could be used here to
|
||||
* include a customized representation for edit mode.
|
||||
*/
|
||||
var tableInspector = new InspectorRegion(),
|
||||
tableOptionsEditRegion = new Region({
|
||||
name: "table-options",
|
||||
title: "Table Options",
|
||||
modes: ['edit'],
|
||||
content: {
|
||||
key: "table-options-edit"
|
||||
}
|
||||
});
|
||||
tableInspector.addRegion(tableOptionsEditRegion);
|
||||
|
||||
legacyRegistry.register("platform/features/table", {
|
||||
"extensions": {
|
||||
"types": [
|
||||
{
|
||||
"key": "table",
|
||||
"name": "Table",
|
||||
"glyph": "\ue605",
|
||||
"description": "A table for displaying telemetry data",
|
||||
"features": "creation",
|
||||
"delegates": [
|
||||
"telemetry"
|
||||
],
|
||||
"inspector": tableInspector,
|
||||
"contains": [
|
||||
{
|
||||
"has": "telemetry"
|
||||
}
|
||||
],
|
||||
"model": {
|
||||
"composition": []
|
||||
},
|
||||
"views": [
|
||||
"table"
|
||||
]
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "TelemetryTableController",
|
||||
"implementation": TelemetryTableController,
|
||||
"depends": ["$scope", "telemetryHandler", "telemetryFormatter"]
|
||||
},
|
||||
{
|
||||
"key": "TableOptionsController",
|
||||
"implementation": TableOptionsController,
|
||||
"depends": ["$scope"]
|
||||
}
|
||||
|
||||
],
|
||||
"views": [
|
||||
{
|
||||
"name": "Table",
|
||||
"key": "table",
|
||||
"glyph": "\ue605",
|
||||
"templateUrl": "templates/table.html",
|
||||
"needs": [
|
||||
"telemetry"
|
||||
],
|
||||
"delegation": true,
|
||||
"editable": true
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctTable",
|
||||
"implementation": MCTTable,
|
||||
"depends": ["$timeout"]
|
||||
}
|
||||
],
|
||||
"representations": [
|
||||
{
|
||||
"key": "table-options-edit",
|
||||
"templateUrl": "templates/table-options-edit.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
});
|
64
platform/features/table/res/templates/mct-data-table.html
Normal file
64
platform/features/table/res/templates/mct-data-table.html
Normal file
@ -0,0 +1,64 @@
|
||||
<div class="l-view-section scrolling"
|
||||
style="overflow: auto;"
|
||||
>
|
||||
<table class="filterable"
|
||||
ng-style="overrideRowPositioning && {
|
||||
height: totalHeight + 'px',
|
||||
'table-layout': overrideRowPositioning ? 'fixed' : 'auto'
|
||||
}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th ng-repeat="header in displayHeaders"
|
||||
ng-style="overrideRowPositioning && {
|
||||
width: columnWidths[$index] + 'px',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
overflow: 'none',
|
||||
'box-sizing': 'border-box'
|
||||
}"
|
||||
ng-class="[
|
||||
enableSort ? 'sortable' : '',
|
||||
sortColumn === header ? 'sort' : '',
|
||||
sortDirection || ''
|
||||
].join(' ')"
|
||||
ng-click="toggleSort(header)">
|
||||
{{ header }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-if="enableFilter" class="s-filters">
|
||||
<th ng-repeat="header in displayHeaders"
|
||||
ng-style="overrideRowPositioning && {
|
||||
width: columnWidths[$index] + 'px',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
overflow: 'none',
|
||||
'box-sizing': 'border-box'
|
||||
}">
|
||||
<input type="text"
|
||||
ng-model="filters[header]"/>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody ng-style="overrideRowPositioning ? '' : {
|
||||
'opacity': '0.0'
|
||||
}">
|
||||
<tr ng-repeat="visibleRow in visibleRows track by visibleRow.rowIndex"
|
||||
ng-style="overrideRowPositioning && {
|
||||
position: 'absolute',
|
||||
top: visibleRow.offsetY + 'px',
|
||||
}">
|
||||
<td ng-repeat="header in displayHeaders"
|
||||
ng-style="overrideRowPositioning && {
|
||||
width: columnWidths[$index] + 'px',
|
||||
'white-space': 'nowrap',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
overflow: 'hidden',
|
||||
'box-sizing': 'border-box'
|
||||
}"
|
||||
class="{{visibleRow.contents[header].cssClass}}">
|
||||
{{ visibleRow.contents[header].text }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
@ -0,0 +1,30 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<div ng-controller="TableOptionsController" class="flex-elem grows l-inspector-part">
|
||||
<em class="t-inspector-part-header" title="Display properties for this object">Display</em>
|
||||
<mct-form
|
||||
ng-model="configuration.table.columns"
|
||||
structure="columnsForm"
|
||||
name="columnsFormState"
|
||||
class="flex-elem l-flex-row no-validate no-margin reduced-min-width">
|
||||
</mct-form>
|
||||
</div>
|
8
platform/features/table/res/templates/table.html
Normal file
8
platform/features/table/res/templates/table.html
Normal file
@ -0,0 +1,8 @@
|
||||
<div ng-controller="TelemetryTableController">
|
||||
<mct-table
|
||||
headers="headers"
|
||||
rows="rows"
|
||||
enableFilter="true"
|
||||
enableSort="true">
|
||||
</mct-table>
|
||||
</div>
|
64
platform/features/table/src/DomainColumn.js
Normal file
64
platform/features/table/src/DomainColumn.js
Normal file
@ -0,0 +1,64 @@
|
||||
/*****************************************************************************
|
||||
* 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,moment*/
|
||||
|
||||
/**
|
||||
* Module defining DomainColumn.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A column which will report telemetry domain values
|
||||
* (typically, timestamps.) Used by the ScrollingListController.
|
||||
*
|
||||
* @memberof platform/features/table
|
||||
* @constructor
|
||||
* @param domainMetadata an object with the machine- and human-
|
||||
* readable names for this domain (in `key` and `name`
|
||||
* fields, respectively.)
|
||||
* @param {TelemetryFormatter} telemetryFormatter the telemetry
|
||||
* formatting service, for making values human-readable.
|
||||
*/
|
||||
function DomainColumn(domainMetadata, telemetryFormatter) {
|
||||
this.domainMetadata = domainMetadata;
|
||||
this.telemetryFormatter = telemetryFormatter;
|
||||
}
|
||||
|
||||
DomainColumn.prototype.getTitle = function () {
|
||||
return this.domainMetadata.name;
|
||||
};
|
||||
|
||||
DomainColumn.prototype.getValue = function (domainObject, datum) {
|
||||
return {
|
||||
text: this.telemetryFormatter.formatDomainValue(
|
||||
datum[this.domainMetadata.key],
|
||||
this.domainMetadata.format
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
return DomainColumn;
|
||||
}
|
||||
);
|
54
platform/features/table/src/NameColumn.js
Normal file
54
platform/features/table/src/NameColumn.js
Normal file
@ -0,0 +1,54 @@
|
||||
/*****************************************************************************
|
||||
* 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,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining NameColumn. Created by vwoeltje on 11/18/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A column which will report the name of the domain object
|
||||
* which exposed specific telemetry values.
|
||||
*
|
||||
* @memberof platform/features/table
|
||||
* @constructor
|
||||
*/
|
||||
function NameColumn() {
|
||||
}
|
||||
|
||||
NameColumn.prototype.getTitle = function () {
|
||||
return "Name";
|
||||
};
|
||||
|
||||
NameColumn.prototype.getValue = function (domainObject) {
|
||||
return {
|
||||
text: domainObject.getModel().name
|
||||
};
|
||||
};
|
||||
|
||||
return NameColumn;
|
||||
}
|
||||
);
|
67
platform/features/table/src/RangeColumn.js
Normal file
67
platform/features/table/src/RangeColumn.js
Normal file
@ -0,0 +1,67 @@
|
||||
/*****************************************************************************
|
||||
* 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,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining DomainColumn. Created by vwoeltje on 11/18/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A column which will report telemetry range values
|
||||
* (typically, measurements.) Used by the ScrollingListController.
|
||||
*
|
||||
* @memberof platform/features/table
|
||||
* @constructor
|
||||
* @param rangeMetadata an object with the machine- and human-
|
||||
* readable names for this range (in `key` and `name`
|
||||
* fields, respectively.)
|
||||
* @param {TelemetryFormatter} telemetryFormatter the telemetry
|
||||
* formatting service, for making values human-readable.
|
||||
*/
|
||||
function RangeColumn(rangeMetadata, telemetryFormatter) {
|
||||
this.rangeMetadata = rangeMetadata;
|
||||
this.telemetryFormatter = telemetryFormatter;
|
||||
}
|
||||
|
||||
RangeColumn.prototype.getTitle = function () {
|
||||
return this.rangeMetadata.name;
|
||||
};
|
||||
|
||||
RangeColumn.prototype.getValue = function (domainObject, datum) {
|
||||
var range = this.rangeMetadata.key,
|
||||
limit = domainObject.getCapability('limit'),
|
||||
value = isNaN(datum[range]) ? datum[range] : parseFloat(datum[range]),
|
||||
alarm = limit && limit.evaluate(datum, range);
|
||||
|
||||
return {
|
||||
cssClass: alarm && alarm.cssClass,
|
||||
text: typeof(value) === 'undefined' ? undefined : this.telemetryFormatter.formatRangeValue(value)
|
||||
};
|
||||
};
|
||||
|
||||
return RangeColumn;
|
||||
}
|
||||
);
|
180
platform/features/table/src/TableConfiguration.js
Normal file
180
platform/features/table/src/TableConfiguration.js
Normal file
@ -0,0 +1,180 @@
|
||||
/*****************************************************************************
|
||||
* 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,moment*/
|
||||
|
||||
define(
|
||||
[
|
||||
'./DomainColumn',
|
||||
'./RangeColumn',
|
||||
'./NameColumn'
|
||||
],
|
||||
function (DomainColumn, RangeColumn, NameColumn) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Class that manages table metadata, state, and contents.
|
||||
* @memberof platform/features/table
|
||||
* @param domainObject
|
||||
* @constructor
|
||||
*/
|
||||
function TableConfiguration(domainObject, telemetryFormatter) {
|
||||
this.domainObject = domainObject;
|
||||
this.columns = [];
|
||||
this.telemetryFormatter = telemetryFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build column definitions based on supplied telemetry metadata
|
||||
* @param metadata Metadata describing the domains and ranges available
|
||||
* @returns {TableConfiguration} This object
|
||||
*/
|
||||
TableConfiguration.prototype.buildColumns = function(metadata) {
|
||||
var self = this;
|
||||
|
||||
this.columns = [];
|
||||
|
||||
if (metadata) {
|
||||
|
||||
if (metadata.length > 1){
|
||||
self.addColumn(new NameColumn(), 0);
|
||||
}
|
||||
|
||||
metadata.forEach(function (metadatum) {
|
||||
//Push domains first
|
||||
(metadatum.domains || []).forEach(function (domainMetadata) {
|
||||
self.addColumn(new DomainColumn(domainMetadata, self.telemetryFormatter));
|
||||
});
|
||||
(metadatum.ranges || []).forEach(function (rangeMetadata) {
|
||||
self.addColumn(new RangeColumn(rangeMetadata, self.telemetryFormatter));
|
||||
});
|
||||
});
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a column definition to this Table
|
||||
* @param {RangeColumn | DomainColumn | NameColumn} column
|
||||
* @param {Number} [index] Where the column should appear (will be
|
||||
* affected by column filtering)
|
||||
*/
|
||||
TableConfiguration.prototype.addColumn = function (column, index) {
|
||||
if (typeof index === 'undefined') {
|
||||
this.columns.push(column);
|
||||
} else {
|
||||
this.columns.splice(index, 0, column);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param column
|
||||
* @returns {*|string}
|
||||
*/
|
||||
TableConfiguration.prototype.getColumnTitle = function (column) {
|
||||
return column.getTitle();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a simple list of column titles
|
||||
* @returns {Array} The titles of the columns
|
||||
*/
|
||||
TableConfiguration.prototype.getHeaders = function() {
|
||||
var self = this;
|
||||
return this.columns.map(function (column, i){
|
||||
return self.getColumnTitle(column) || 'Column ' + (i + 1);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve and format values for a given telemetry datum.
|
||||
* @param telemetryObject The object that the telemetry data is
|
||||
* associated with
|
||||
* @param datum The telemetry datum to retrieve values from
|
||||
* @returns {Object} Key value pairs where the key is the column
|
||||
* title, and the value is the formatted value from the provided datum.
|
||||
*/
|
||||
TableConfiguration.prototype.getRowValues = function(telemetryObject, datum) {
|
||||
var self = this;
|
||||
return this.columns.reduce(function(rowObject, column, i){
|
||||
var columnTitle = self.getColumnTitle(column) || 'Column ' + (i + 1),
|
||||
columnValue = column.getValue(telemetryObject, datum);
|
||||
|
||||
if (columnValue !== undefined && columnValue.text === undefined){
|
||||
columnValue.text = '';
|
||||
}
|
||||
// Don't replace something with nothing.
|
||||
// This occurs when there are multiple columns with the
|
||||
// column title
|
||||
if (rowObject[columnTitle] === undefined || rowObject[columnTitle].text === undefined || rowObject[columnTitle].text.length === 0) {
|
||||
rowObject[columnTitle] = columnValue;
|
||||
}
|
||||
return rowObject;
|
||||
}, {});
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
TableConfiguration.prototype.defaultColumnConfiguration = function () {
|
||||
return ((this.domainObject.getModel().configuration || {}).table || {}).columns || {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the established configuration on the domain object
|
||||
* @private
|
||||
*/
|
||||
TableConfiguration.prototype.saveColumnConfiguration = function (columnConfig) {
|
||||
this.domainObject.useCapability('mutation', function (model) {
|
||||
model.configuration = model.configuration || {};
|
||||
model.configuration.table = model.configuration.table || {};
|
||||
model.configuration.table.columns = columnConfig;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* As part of the process of building the table definition, extract
|
||||
* configuration from column definitions.
|
||||
* @returns {Object} A configuration object consisting of key-value
|
||||
* pairs where the key is the column title, and the value is a
|
||||
* boolean indicating whether the column should be shown.
|
||||
*/
|
||||
TableConfiguration.prototype.getColumnConfiguration = function() {
|
||||
var configuration = {},
|
||||
//Use existing persisted config, or default it
|
||||
defaultConfig = this.defaultColumnConfiguration();
|
||||
|
||||
/**
|
||||
* For each column header, define a configuration value
|
||||
* specifying whether the column is visible or not. Default to
|
||||
* existing (persisted) configuration if available
|
||||
*/
|
||||
this.getHeaders().forEach(function(columnTitle) {
|
||||
configuration[columnTitle] = typeof defaultConfig[columnTitle] === 'undefined' ? true : defaultConfig[columnTitle];
|
||||
});
|
||||
|
||||
return configuration;
|
||||
};
|
||||
|
||||
return TableConfiguration;
|
||||
}
|
||||
);
|
354
platform/features/table/src/controllers/MCTTableController.js
Normal file
354
platform/features/table/src/controllers/MCTTableController.js
Normal file
@ -0,0 +1,354 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
function MCTTableController($scope, $timeout, element) {
|
||||
var self = this;
|
||||
|
||||
this.$scope = $scope;
|
||||
this.element = element;
|
||||
this.$timeout = $timeout;
|
||||
this.maxDisplayRows = 50;
|
||||
|
||||
$scope.visibleRows = [];
|
||||
$scope.overrideRowPositioning = false;
|
||||
|
||||
/**
|
||||
* Set default values for optional parameters on a given scope
|
||||
*/
|
||||
function setDefaults($scope) {
|
||||
if (typeof $scope.enableFilter === 'undefined') {
|
||||
$scope.enableFilter = true;
|
||||
$scope.filters = {};
|
||||
}
|
||||
if (typeof $scope.enableSort === 'undefined') {
|
||||
$scope.enableSort = true;
|
||||
$scope.sortColumn = undefined;
|
||||
$scope.sortDirection = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
setDefaults($scope);
|
||||
|
||||
element.find('div').on('scroll', this.onScroll.bind(this));
|
||||
|
||||
$scope.toggleSort = function (key) {
|
||||
if (!$scope.enableSort) {
|
||||
return;
|
||||
}
|
||||
if ($scope.sortColumn !== key) {
|
||||
$scope.sortColumn = key;
|
||||
$scope.sortDirection = 'asc';
|
||||
} else if ($scope.sortDirection === 'asc') {
|
||||
$scope.sortDirection = 'desc';
|
||||
} else if ($scope.sortDirection === 'desc') {
|
||||
$scope.sortColumn = undefined;
|
||||
$scope.sortDirection = undefined;
|
||||
}
|
||||
self.updateRows($scope.rows);
|
||||
};
|
||||
|
||||
$scope.$watchCollection('filters', function () {
|
||||
self.updateRows(self.$scope.rows);
|
||||
});
|
||||
$scope.$watchCollection('headers', this.updateHeaders.bind(this));
|
||||
$scope.$watchCollection('rows', this.updateRows.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* On scroll, calculate which rows indexes are visible and
|
||||
* ensure that an equal number of rows are preloaded for
|
||||
* scrolling in either direction.
|
||||
*/
|
||||
MCTTableController.prototype.onScroll = function (event) {
|
||||
var self = this,
|
||||
topScroll = event.target.scrollTop,
|
||||
bottomScroll = topScroll + event.target.offsetHeight,
|
||||
firstVisible,
|
||||
lastVisible,
|
||||
totalVisible,
|
||||
numberOffscreen,
|
||||
start,
|
||||
end;
|
||||
|
||||
if (this.$scope.displayRows.length < this.maxDisplayRows) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (topScroll < this.$scope.headerHeight) {
|
||||
firstVisible = 0;
|
||||
} else {
|
||||
firstVisible = Math.floor(
|
||||
(topScroll - this.$scope.headerHeight) / this.$scope.rowHeight
|
||||
);
|
||||
}
|
||||
lastVisible = Math.ceil(
|
||||
(bottomScroll - this.$scope.headerHeight) / this.$scope.rowHeight
|
||||
);
|
||||
|
||||
totalVisible = lastVisible - firstVisible;
|
||||
numberOffscreen = this.maxDisplayRows - totalVisible;
|
||||
start = firstVisible - Math.floor(numberOffscreen / 2);
|
||||
end = lastVisible + Math.ceil(numberOffscreen / 2);
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
end = this.$scope.visibleRows.length - 1;
|
||||
} else if (end >= this.$scope.displayRows.length) {
|
||||
end = this.$scope.displayRows.length - 1;
|
||||
start = end - this.maxDisplayRows + 1;
|
||||
}
|
||||
if (this.$scope.visibleRows[0].rowIndex === start &&
|
||||
this.$scope.visibleRows[this.$scope.visibleRows.length-1]
|
||||
.rowIndex === end) {
|
||||
|
||||
return; // don't update if no changes are required.
|
||||
}
|
||||
|
||||
this.$scope.visibleRows = this.$scope.displayRows.slice(start, end)
|
||||
.map(function(row, i) {
|
||||
return {
|
||||
rowIndex: start + i,
|
||||
offsetY: ((start + i) * self.$scope.rowHeight) +
|
||||
self.$scope.headerHeight,
|
||||
contents: row
|
||||
};
|
||||
});
|
||||
|
||||
this.$scope.$digest();
|
||||
};
|
||||
|
||||
/**
|
||||
* Update table headers with new headers. If filtering is
|
||||
* enabled, reset filters. If sorting is enabled, reset
|
||||
* sorting.
|
||||
*/
|
||||
MCTTableController.prototype.updateHeaders = function (newHeaders) {
|
||||
if (!newHeaders){
|
||||
return;
|
||||
}
|
||||
|
||||
this.$scope.displayHeaders = newHeaders;
|
||||
if (this.$scope.enableFilter) {
|
||||
this.$scope.filters = {};
|
||||
}
|
||||
// Reset column sort information unless the new headers
|
||||
// contain the column current sorted on.
|
||||
if (this.$scope.enableSort && newHeaders.indexOf(this.$scope.sortColumn) === -1) {
|
||||
this.$scope.sortColumn = undefined;
|
||||
this.$scope.sortDirection = undefined;
|
||||
}
|
||||
this.updateRows(this.$scope.rows);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read styles from the DOM and use them to calculate offsets
|
||||
* for individual rows.
|
||||
*/
|
||||
MCTTableController.prototype.setElementSizes = function () {
|
||||
var self = this,
|
||||
thead = this.element.find('thead'),
|
||||
tbody = this.element.find('tbody'),
|
||||
firstRow = tbody.find('tr'),
|
||||
column = firstRow.find('td'),
|
||||
headerHeight = thead.prop('offsetHeight'),
|
||||
//row height is hard-coded for now.
|
||||
rowHeight = 20,
|
||||
overallHeight = headerHeight + (rowHeight * (this.$scope.displayRows ? this.$scope.displayRows.length - 1 : 0));
|
||||
|
||||
this.$scope.columnWidths = [];
|
||||
|
||||
while (column.length) {
|
||||
this.$scope.columnWidths.push(column.prop('offsetWidth'));
|
||||
column = column.next();
|
||||
}
|
||||
this.$scope.headerHeight = headerHeight;
|
||||
this.$scope.rowHeight = rowHeight;
|
||||
this.$scope.totalHeight = overallHeight;
|
||||
|
||||
this.$scope.visibleRows = this.$scope.displayRows.slice(0, this.maxDisplayRows).map(function(row, i) {
|
||||
return {
|
||||
rowIndex: i,
|
||||
offsetY: (i * self.$scope.rowHeight) + self.$scope.headerHeight,
|
||||
contents: row
|
||||
};
|
||||
});
|
||||
|
||||
this.$scope.overrideRowPositioning = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a new array which is a result of applying the sort
|
||||
* criteria defined in $scope.
|
||||
*
|
||||
* Does not modify the array that was passed in.
|
||||
*/
|
||||
MCTTableController.prototype.sortRows = function(rowsToSort) {
|
||||
/**
|
||||
* Compare two variables, returning a number that represents
|
||||
* which is larger. Similar to the default array sort
|
||||
* comparator, but does not coerce all values to string before
|
||||
* conversion. Strings are lowercased before comparison.
|
||||
*/
|
||||
function genericComparator(a, b) {
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!this.$scope.sortColumn || !this.$scope.sortDirection) {
|
||||
return rowsToSort;
|
||||
}
|
||||
var sortKey = this.$scope.sortColumn,
|
||||
sortDirectionMultiplier;
|
||||
|
||||
if (this.$scope.sortDirection === 'asc') {
|
||||
sortDirectionMultiplier = 1;
|
||||
} else if (this.$scope.sortDirection === 'desc') {
|
||||
sortDirectionMultiplier = -1;
|
||||
}
|
||||
|
||||
return rowsToSort.slice(0).sort(function(a, b) {
|
||||
//If the values to compare can be compared as
|
||||
// numbers, do so. String comparison of number
|
||||
// values can cause inconsistencies
|
||||
var valA = isNaN(a[sortKey].text) ? a[sortKey].text : parseFloat(a[sortKey].text),
|
||||
valB = isNaN(b[sortKey].text) ? b[sortKey].text : parseFloat(b[sortKey].text);
|
||||
|
||||
return genericComparator(valA, valB) *
|
||||
sortDirectionMultiplier;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object which contains the largest values
|
||||
* for each key in the given set of rows. This is used to
|
||||
* pre-calculate optimal column sizes without having to render
|
||||
* every row.
|
||||
*/
|
||||
MCTTableController.prototype.findLargestRow = function(rows) {
|
||||
var largestRow = rows.reduce(function (largestRow, row) {
|
||||
Object.keys(row).forEach(function (key) {
|
||||
var currentColumn = row[key].text,
|
||||
currentColumnLength =
|
||||
(currentColumn && currentColumn.length) ?
|
||||
currentColumn.length :
|
||||
currentColumn,
|
||||
largestColumn = largestRow[key].text,
|
||||
largestColumnLength =
|
||||
(largestColumn && largestColumn.length) ?
|
||||
largestColumn.length :
|
||||
largestColumn;
|
||||
|
||||
if (currentColumnLength > largestColumnLength) {
|
||||
largestRow[key] = JSON.parse(JSON.stringify(row[key]));
|
||||
}
|
||||
});
|
||||
return largestRow;
|
||||
}, JSON.parse(JSON.stringify(rows[0] || {})));
|
||||
|
||||
// Pad with characters to accomodate variable-width fonts,
|
||||
// and remove characters that would allow word-wrapping.
|
||||
largestRow = JSON.parse(JSON.stringify(largestRow));
|
||||
Object.keys(largestRow).forEach(function(key) {
|
||||
var padCharacters,
|
||||
i;
|
||||
|
||||
largestRow[key].text = String(largestRow[key].text);
|
||||
padCharacters = largestRow[key].text.length / 10;
|
||||
for (i = 0; i < padCharacters; i++) {
|
||||
largestRow[key].text = largestRow[key].text + 'W';
|
||||
}
|
||||
largestRow[key].text = largestRow[key].text
|
||||
.replace(/[ \-_]/g, 'W');
|
||||
});
|
||||
return largestRow;
|
||||
};
|
||||
|
||||
MCTTableController.prototype.resize = function (){
|
||||
var largestRow = this.findLargestRow(this.$scope.displayRows);
|
||||
this.$scope.visibleRows = [
|
||||
{
|
||||
rowIndex: 0,
|
||||
offsetY: undefined,
|
||||
contents: largestRow
|
||||
}
|
||||
];
|
||||
|
||||
this.$timeout(this.setElementSizes.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Update rows with new data. If filtering is enabled, rows
|
||||
* will be sorted before display.
|
||||
*/
|
||||
MCTTableController.prototype.updateRows = function (newRows) {
|
||||
var displayRows = newRows;
|
||||
this.$scope.visibleRows = [];
|
||||
this.$scope.overrideRowPositioning = false;
|
||||
|
||||
if (!this.$scope.displayHeaders) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$scope.enableFilter) {
|
||||
displayRows = this.filterRows(displayRows);
|
||||
}
|
||||
|
||||
if (this.$scope.enableSort) {
|
||||
displayRows = this.sortRows(displayRows);
|
||||
}
|
||||
this.$scope.displayRows = displayRows;
|
||||
this.resize();
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter rows.
|
||||
*/
|
||||
MCTTableController.prototype.filterRows = function(rowsToFilter) {
|
||||
var filters = {},
|
||||
self = this;
|
||||
|
||||
/**
|
||||
* Returns true if row matches all filters.
|
||||
*/
|
||||
function matchRow(filters, row) {
|
||||
return Object.keys(filters).every(function(key) {
|
||||
if (!row[key]) {
|
||||
return false;
|
||||
}
|
||||
var testVal = String(row[key].text).toLowerCase();
|
||||
return testVal.indexOf(filters[key]) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
if (!Object.keys(this.$scope.filters).length) {
|
||||
return rowsToFilter;
|
||||
}
|
||||
|
||||
Object.keys(this.$scope.filters).forEach(function(key) {
|
||||
if (!self.$scope.filters[key]) {
|
||||
return;
|
||||
}
|
||||
filters[key] = self.$scope.filters[key].toLowerCase();
|
||||
});
|
||||
|
||||
return rowsToFilter.filter(matchRow.bind(null, filters));
|
||||
};
|
||||
|
||||
|
||||
return MCTTableController;
|
||||
}
|
||||
);
|
@ -0,0 +1,94 @@
|
||||
/*****************************************************************************
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* Notes on implementation of plot options
|
||||
*
|
||||
* Multiple y-axes will have to be handled with multiple forms as
|
||||
* they will need to be stored on distinct model object
|
||||
*
|
||||
* Likewise plot series options per-child will need to be separate
|
||||
* forms.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The LayoutController is responsible for supporting the
|
||||
* Layout view. It arranges frames according to saved configuration
|
||||
* and provides methods for updating these based on mouse
|
||||
* movement.
|
||||
* @memberof platform/features/plot
|
||||
* @constructor
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function TableOptionsController($scope) {
|
||||
|
||||
var self = this;
|
||||
|
||||
this.$scope = $scope;
|
||||
this.domainObject = $scope.domainObject;
|
||||
|
||||
$scope.columnsForm = {};
|
||||
|
||||
this.domainObject.getCapability('mutation').listen(function (model) {
|
||||
self.populateForm(model);
|
||||
});
|
||||
|
||||
$scope.$watchCollection('configuration.table.columns', function(columns){
|
||||
if (columns){
|
||||
self.domainObject.useCapability('mutation', function(model) {
|
||||
model.configuration.table.columns = columns;
|
||||
});
|
||||
self.domainObject.getCapability('persistence').persist();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
TableOptionsController.prototype.populateForm = function (model) {
|
||||
var columnsDefinition = (((model.configuration || {}).table || {}).columns || {}),
|
||||
rows = [];
|
||||
this.$scope.columnsForm = {
|
||||
'name':'Columns',
|
||||
'sections': [{
|
||||
'name': 'Columns',
|
||||
'rows': rows
|
||||
}]};
|
||||
|
||||
Object.keys(columnsDefinition).forEach(function (key){
|
||||
rows.push({
|
||||
'name': key,
|
||||
'control': 'checkbox',
|
||||
'key': key
|
||||
});
|
||||
});
|
||||
this.$scope.configuration = JSON.parse(JSON.stringify(model.configuration));
|
||||
};
|
||||
|
||||
return TableOptionsController;
|
||||
}
|
||||
);
|
@ -0,0 +1,189 @@
|
||||
/*****************************************************************************
|
||||
* 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 adds a table view for displaying telemetry data.
|
||||
* @namespace platform/features/table
|
||||
*/
|
||||
define(
|
||||
[
|
||||
'../TableConfiguration'
|
||||
],
|
||||
function (TableConfiguration) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The TableController is responsible for getting data onto the page
|
||||
* in the table widget. This includes handling composition,
|
||||
* configuration, and telemetry subscriptions.
|
||||
* @memberof platform/features/table
|
||||
* @param $scope
|
||||
* @param telemetryHandler
|
||||
* @param telemetryFormatter
|
||||
* @constructor
|
||||
*/
|
||||
function TelemetryTableController(
|
||||
$scope,
|
||||
telemetryHandler,
|
||||
telemetryFormatter
|
||||
) {
|
||||
var self = this;
|
||||
|
||||
this.$scope = $scope;
|
||||
this.columns = {}; //Range and Domain columns
|
||||
this.handle = undefined;
|
||||
//this.pending = false;
|
||||
this.telemetryHandler = telemetryHandler;
|
||||
this.table = new TableConfiguration($scope.domainObject, telemetryFormatter);
|
||||
this.changeListeners = [];
|
||||
|
||||
$scope.rows = [];
|
||||
|
||||
// Subscribe to telemetry when a domain object becomes available
|
||||
this.$scope.$watch('domainObject', function(domainObject){
|
||||
if (!domainObject)
|
||||
return;
|
||||
|
||||
self.subscribe();
|
||||
self.registerChangeListeners();
|
||||
});
|
||||
|
||||
// Unsubscribe when the plot is destroyed
|
||||
this.$scope.$on("$destroy", this.destroy.bind(this));
|
||||
}
|
||||
|
||||
TelemetryTableController.prototype.registerChangeListeners = function() {
|
||||
//Defer registration of change listeners until domain object is
|
||||
// available in order to avoid race conditions
|
||||
|
||||
this.changeListeners.forEach(function (listener) {
|
||||
return listener && listener();
|
||||
});
|
||||
this.changeListeners = [];
|
||||
// When composition changes, re-subscribe to the various
|
||||
// telemetry subscriptions
|
||||
this.changeListeners.push(this.$scope.$watchCollection('domainObject.getModel().composition', this.subscribe.bind(this)));
|
||||
|
||||
//Change of bounds in time conductor
|
||||
this.changeListeners.push(this.$scope.$on('telemetry:display:bounds', this.subscribe.bind(this)));
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Release the current subscription (called when scope is destroyed)
|
||||
*/
|
||||
TelemetryTableController.prototype.destroy = function () {
|
||||
if (this.handle) {
|
||||
this.handle.unsubscribe();
|
||||
this.handle = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Create a new subscription. This is called when
|
||||
*/
|
||||
TelemetryTableController.prototype.subscribe = function() {
|
||||
|
||||
if (this.handle) {
|
||||
this.handle.unsubscribe();
|
||||
}
|
||||
|
||||
this.$scope.rows = [];
|
||||
|
||||
//Noop because not supporting realtime data right now
|
||||
function noop(){
|
||||
}
|
||||
|
||||
this.handle = this.$scope.domainObject && this.telemetryHandler.handle(
|
||||
this.$scope.domainObject,
|
||||
noop,
|
||||
true // Lossless
|
||||
);
|
||||
|
||||
this.handle.request({}, this.addHistoricalData.bind(this));
|
||||
|
||||
this.setup();
|
||||
};
|
||||
|
||||
/**
|
||||
* Add any historical data available
|
||||
*/
|
||||
TelemetryTableController.prototype.addHistoricalData = function(domainObject, series) {
|
||||
var i;
|
||||
for (i=0; i < series.getPointCount(); i++) {
|
||||
this.updateRows(domainObject, this.handle.makeDatum(domainObject, series, i));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup table columns based on domain object metadata
|
||||
*/
|
||||
TelemetryTableController.prototype.setup = function() {
|
||||
var handle = this.handle,
|
||||
table = this.table,
|
||||
self = this;
|
||||
|
||||
if (handle) {
|
||||
handle.promiseTelemetryObjects().then(function (objects) {
|
||||
table.buildColumns(handle.getMetadata());
|
||||
|
||||
self.filterColumns();
|
||||
|
||||
// When table column configuration changes, (due to being
|
||||
// selected or deselected), filter columns appropriately.
|
||||
self.changeListeners.push(self.$scope.$watchCollection(
|
||||
'domainObject.getModel().configuration.table.columns',
|
||||
self.filterColumns.bind(self)
|
||||
));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add data to rows
|
||||
* @param object The object for which data is available (table may
|
||||
* be composed of multiple objects)
|
||||
* @param datum The data received from the telemetry source
|
||||
*/
|
||||
TelemetryTableController.prototype.updateRows = function (object, datum) {
|
||||
this.$scope.rows.push(this.table.getRowValues(object, datum));
|
||||
};
|
||||
|
||||
/**
|
||||
* When column configuration changes, update the visible headers
|
||||
* accordingly.
|
||||
*/
|
||||
TelemetryTableController.prototype.filterColumns = function (columnConfig) {
|
||||
if (!columnConfig){
|
||||
columnConfig = this.table.getColumnConfiguration();
|
||||
this.table.saveColumnConfiguration(columnConfig);
|
||||
}
|
||||
//Populate headers with visible columns (determined by configuration)
|
||||
this.$scope.headers = Object.keys(columnConfig).filter(function(column) {
|
||||
return columnConfig[column];
|
||||
});
|
||||
};
|
||||
|
||||
return TelemetryTableController;
|
||||
}
|
||||
);
|
24
platform/features/table/src/directives/MCTTable.js
Normal file
24
platform/features/table/src/directives/MCTTable.js
Normal file
@ -0,0 +1,24 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
["../controllers/MCTTableController"],
|
||||
function (MCTTableController) {
|
||||
"use strict";
|
||||
|
||||
function MCTTable($timeout) {
|
||||
return {
|
||||
restrict: "E",
|
||||
templateUrl: "platform/features/table/res/templates/mct-data-table.html",
|
||||
controller: ['$scope', '$timeout', '$element', MCTTableController],
|
||||
scope: {
|
||||
headers: "=",
|
||||
rows: "=",
|
||||
enableFilter: "=?",
|
||||
enableSort: "=?"
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return MCTTable;
|
||||
}
|
||||
);
|
84
platform/features/table/test/DomainColumnSpec.js
Normal file
84
platform/features/table/test/DomainColumnSpec.js
Normal file
@ -0,0 +1,84 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,it,expect,beforeEach,waitsFor,jasmine,xit*/
|
||||
|
||||
/**
|
||||
* MergeModelsSpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
["../src/DomainColumn"],
|
||||
function (DomainColumn) {
|
||||
"use strict";
|
||||
|
||||
var TEST_DOMAIN_VALUE = "some formatted domain value";
|
||||
|
||||
describe("A domain column", function () {
|
||||
var mockDataSet,
|
||||
testMetadata,
|
||||
mockFormatter,
|
||||
column;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDataSet = jasmine.createSpyObj(
|
||||
"data",
|
||||
[ "getDomainValue" ]
|
||||
);
|
||||
mockFormatter = jasmine.createSpyObj(
|
||||
"formatter",
|
||||
[ "formatDomainValue", "formatRangeValue" ]
|
||||
);
|
||||
testMetadata = {
|
||||
key: "testKey",
|
||||
name: "Test Name"
|
||||
};
|
||||
mockFormatter.formatDomainValue.andReturn(TEST_DOMAIN_VALUE);
|
||||
|
||||
column = new DomainColumn(testMetadata, mockFormatter);
|
||||
});
|
||||
|
||||
it("reports a column header from domain metadata", function () {
|
||||
expect(column.getTitle()).toEqual("Test Name");
|
||||
});
|
||||
|
||||
xit("looks up data from a data set", function () {
|
||||
column.getValue(undefined, mockDataSet, 42);
|
||||
expect(mockDataSet.getDomainValue)
|
||||
.toHaveBeenCalledWith(42, "testKey");
|
||||
});
|
||||
|
||||
xit("formats domain values as time", function () {
|
||||
mockDataSet.getDomainValue.andReturn(402513731000);
|
||||
|
||||
// Should have just given the value the formatter gave
|
||||
expect(column.getValue(undefined, mockDataSet, 42).text)
|
||||
.toEqual(TEST_DOMAIN_VALUE);
|
||||
|
||||
// Make sure that service interactions were as expected
|
||||
expect(mockFormatter.formatDomainValue)
|
||||
.toHaveBeenCalledWith(402513731000);
|
||||
expect(mockFormatter.formatRangeValue)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
58
platform/features/table/test/NameColumnSpec.js
Normal file
58
platform/features/table/test/NameColumnSpec.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
/**
|
||||
* MergeModelsSpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
["../src/NameColumn"],
|
||||
function (NameColumn) {
|
||||
"use strict";
|
||||
|
||||
describe("A name column", function () {
|
||||
var mockDomainObject,
|
||||
column;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[ "getModel" ]
|
||||
);
|
||||
mockDomainObject.getModel.andReturn({
|
||||
name: "Test object name"
|
||||
});
|
||||
column = new NameColumn();
|
||||
});
|
||||
|
||||
it("reports a column header", function () {
|
||||
expect(column.getTitle()).toEqual("Name");
|
||||
});
|
||||
|
||||
it("looks up name from an object's model", function () {
|
||||
expect(column.getValue(mockDomainObject).text)
|
||||
.toEqual("Test object name");
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
76
platform/features/table/test/RangeColumnSpec.js
Normal file
76
platform/features/table/test/RangeColumnSpec.js
Normal file
@ -0,0 +1,76 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,it,expect,beforeEach,waitsFor,jasmine,xit*/
|
||||
|
||||
/**
|
||||
* MergeModelsSpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
["../src/RangeColumn"],
|
||||
function (RangeColumn) {
|
||||
"use strict";
|
||||
|
||||
var TEST_RANGE_VALUE = "some formatted range value";
|
||||
|
||||
describe("A range column", function () {
|
||||
var testDatum,
|
||||
testMetadata,
|
||||
mockFormatter,
|
||||
mockDomainObject,
|
||||
column;
|
||||
|
||||
beforeEach(function () {
|
||||
testDatum = { testKey: 123, otherKey: 456 };
|
||||
mockFormatter = jasmine.createSpyObj(
|
||||
"formatter",
|
||||
[ "formatDomainValue", "formatRangeValue" ]
|
||||
);
|
||||
testMetadata = {
|
||||
key: "testKey",
|
||||
name: "Test Name"
|
||||
};
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
[ "getModel", "getCapability" ]
|
||||
);
|
||||
mockFormatter.formatRangeValue.andReturn(TEST_RANGE_VALUE);
|
||||
|
||||
column = new RangeColumn(testMetadata, mockFormatter);
|
||||
});
|
||||
|
||||
it("reports a column header from range metadata", function () {
|
||||
expect(column.getTitle()).toEqual("Test Name");
|
||||
});
|
||||
|
||||
it("formats range values as numbers", function () {
|
||||
expect(column.getValue(mockDomainObject, testDatum).text)
|
||||
.toEqual(TEST_RANGE_VALUE);
|
||||
|
||||
// Make sure that service interactions were as expected
|
||||
expect(mockFormatter.formatRangeValue)
|
||||
.toHaveBeenCalledWith(testDatum.testKey);
|
||||
expect(mockFormatter.formatDomainValue)
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
197
platform/features/table/test/TableConfigurationSpec.js
Normal file
197
platform/features/table/test/TableConfigurationSpec.js
Normal file
@ -0,0 +1,197 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,it,expect,beforeEach,waitsFor,jasmine,xit*/
|
||||
|
||||
define(
|
||||
[
|
||||
"../src/TableConfiguration",
|
||||
"../src/DomainColumn"
|
||||
],
|
||||
function (Table, DomainColumn) {
|
||||
"use strict";
|
||||
|
||||
describe("A table", function () {
|
||||
var mockDomainObject,
|
||||
mockTelemetryFormatter,
|
||||
table,
|
||||
mockModel;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject = jasmine.createSpyObj('domainObject',
|
||||
['getModel', 'useCapability', 'getCapability']
|
||||
);
|
||||
mockModel = {};
|
||||
mockDomainObject.getModel.andReturn(mockModel);
|
||||
mockTelemetryFormatter = jasmine.createSpyObj('telemetryFormatter',
|
||||
[
|
||||
'formatDomainValue',
|
||||
'formatRangeValue'
|
||||
]);
|
||||
mockTelemetryFormatter.formatDomainValue.andCallFake(function(valueIn){
|
||||
return valueIn;
|
||||
});
|
||||
mockTelemetryFormatter.formatRangeValue.andCallFake(function(valueIn){
|
||||
return valueIn;
|
||||
});
|
||||
|
||||
table = new Table(mockDomainObject, mockTelemetryFormatter);
|
||||
});
|
||||
|
||||
it("Add column with no index adds new column to the end", function () {
|
||||
var firstColumn = {title: 'First Column'},
|
||||
secondColumn = {title: 'Second Column'},
|
||||
thirdColumn = {title: 'Third Column'};
|
||||
|
||||
table.addColumn(firstColumn);
|
||||
table.addColumn(secondColumn);
|
||||
table.addColumn(thirdColumn);
|
||||
|
||||
expect(table.columns).toBeDefined();
|
||||
expect(table.columns.length).toBe(3);
|
||||
expect(table.columns[0]).toBe(firstColumn);
|
||||
expect(table.columns[1]).toBe(secondColumn);
|
||||
expect(table.columns[2]).toBe(thirdColumn);
|
||||
});
|
||||
|
||||
it("Add column with index adds new column at the specified" +
|
||||
" position", function () {
|
||||
var firstColumn = {title: 'First Column'},
|
||||
secondColumn = {title: 'Second Column'},
|
||||
thirdColumn = {title: 'Third Column'};
|
||||
|
||||
table.addColumn(firstColumn);
|
||||
table.addColumn(thirdColumn);
|
||||
table.addColumn(secondColumn, 1);
|
||||
|
||||
expect(table.columns).toBeDefined();
|
||||
expect(table.columns.length).toBe(3);
|
||||
expect(table.columns[0]).toBe(firstColumn);
|
||||
expect(table.columns[1]).toBe(secondColumn);
|
||||
expect(table.columns[2]).toBe(thirdColumn);
|
||||
});
|
||||
|
||||
describe("Building columns from telemetry metadata", function() {
|
||||
var metadata = [{
|
||||
ranges: [
|
||||
{
|
||||
name: 'Range 1',
|
||||
key: 'range1'
|
||||
},
|
||||
{
|
||||
name: 'Range 2',
|
||||
key: 'range2'
|
||||
}
|
||||
],
|
||||
domains: [
|
||||
{
|
||||
name: 'Domain 1',
|
||||
key: 'domain1',
|
||||
format: 'utc'
|
||||
},
|
||||
{
|
||||
name: 'Domain 2',
|
||||
key: 'domain2',
|
||||
format: 'utc'
|
||||
}
|
||||
]
|
||||
}];
|
||||
|
||||
beforeEach(function() {
|
||||
table.buildColumns(metadata);
|
||||
});
|
||||
|
||||
it("populates the columns attribute", function() {
|
||||
expect(table.columns.length).toBe(4);
|
||||
});
|
||||
|
||||
it("Build columns populates columns with domains to the left", function() {
|
||||
expect(table.columns[0] instanceof DomainColumn).toBeTruthy();
|
||||
expect(table.columns[1] instanceof DomainColumn).toBeTruthy();
|
||||
expect(table.columns[2] instanceof DomainColumn).toBeFalsy();
|
||||
});
|
||||
|
||||
it("Produces headers for each column based on title", function() {
|
||||
var headers,
|
||||
firstColumn = table.columns[0];
|
||||
|
||||
spyOn(firstColumn, 'getTitle');
|
||||
headers = table.getHeaders();
|
||||
expect(headers.length).toBe(4);
|
||||
expect(firstColumn.getTitle).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Provides a default configuration with all columns" +
|
||||
" visible", function() {
|
||||
var configuration = table.getColumnConfiguration();
|
||||
|
||||
expect(configuration).toBeDefined();
|
||||
expect(Object.keys(configuration).every(function(key){
|
||||
return configuration[key];
|
||||
}));
|
||||
});
|
||||
|
||||
it("Column configuration exposes persisted configuration", function() {
|
||||
var tableConfig,
|
||||
modelConfig = {
|
||||
table: {
|
||||
columns : {
|
||||
'Range 1': false
|
||||
}
|
||||
}
|
||||
};
|
||||
mockModel.configuration = modelConfig;
|
||||
|
||||
tableConfig = table.getColumnConfiguration();
|
||||
|
||||
expect(tableConfig).toBeDefined();
|
||||
expect(tableConfig['Range 1']).toBe(false);
|
||||
});
|
||||
|
||||
describe('retrieving row values', function () {
|
||||
var datum,
|
||||
rowValues;
|
||||
|
||||
beforeEach(function() {
|
||||
datum = {
|
||||
'range1': 'range 1 value',
|
||||
'range2': 'range 2 value',
|
||||
'domain1': 0,
|
||||
'domain2': 1
|
||||
};
|
||||
rowValues = table.getRowValues(mockDomainObject, datum);
|
||||
});
|
||||
|
||||
it("Returns a value for every column", function() {
|
||||
expect(rowValues['Range 1'].text).toBeDefined();
|
||||
expect(rowValues['Range 1'].text).toEqual('range 1' +
|
||||
' value');
|
||||
});
|
||||
|
||||
it("Uses the telemetry formatter to appropriately format" +
|
||||
" telemetry values", function() {
|
||||
expect(mockTelemetryFormatter.formatRangeValue).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -0,0 +1,155 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,it,expect,beforeEach,waitsFor,jasmine,xit*/
|
||||
|
||||
define(
|
||||
[
|
||||
"../../src/controllers/MCTTableController"
|
||||
],
|
||||
function (MCTTableController) {
|
||||
"use strict";
|
||||
|
||||
describe('The MCTTable Controller', function() {
|
||||
|
||||
var controller,
|
||||
mockScope,
|
||||
watches,
|
||||
mockTimeout,
|
||||
mockElement;
|
||||
|
||||
function promise(value) {
|
||||
return {
|
||||
then: function (callback){
|
||||
return promise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
watches = {};
|
||||
|
||||
mockScope = jasmine.createSpyObj('scope', [
|
||||
'$watchCollection'
|
||||
]);
|
||||
mockScope.$watchCollection.andCallFake(function(event, callback) {
|
||||
watches[event] = callback;
|
||||
});
|
||||
|
||||
mockElement = jasmine.createSpyObj('element', [
|
||||
'find',
|
||||
'on'
|
||||
]);
|
||||
mockElement.find.andReturn(mockElement);
|
||||
|
||||
mockScope.displayHeaders = true;
|
||||
mockTimeout = jasmine.createSpy('$timeout');
|
||||
|
||||
controller = new MCTTableController(mockScope, mockTimeout, mockElement);
|
||||
});
|
||||
|
||||
it('Reacts to changes to filters, headers, and rows', function() {
|
||||
expect(mockScope.$watchCollection).toHaveBeenCalledWith('filters', jasmine.any(Function));
|
||||
expect(mockScope.$watchCollection).toHaveBeenCalledWith('headers', jasmine.any(Function));
|
||||
expect(mockScope.$watchCollection).toHaveBeenCalledWith('rows', jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe('rows', function() {
|
||||
var testRows = [];
|
||||
beforeEach(function() {
|
||||
testRows = [
|
||||
{
|
||||
'col1': {'text': 'row1 col1 match'},
|
||||
'col2': {'text': 'def'},
|
||||
'col3': {'text': 'row1 col3'}
|
||||
},
|
||||
{
|
||||
'col1': {'text': 'row2 col1 match'},
|
||||
'col2': {'text': 'abc'},
|
||||
'col3': {'text': 'row2 col3'}
|
||||
},
|
||||
{
|
||||
'col1': {'text': 'row3 col1'},
|
||||
'col2': {'text': 'ghi'},
|
||||
'col3': {'text': 'row3 col3'}
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
it('Filters results based on filter input', function() {
|
||||
var filters = {},
|
||||
filteredRows;
|
||||
|
||||
mockScope.filters = filters;
|
||||
|
||||
filteredRows = controller.filterRows(testRows);
|
||||
expect(filteredRows.length).toBe(3);
|
||||
filters.col1 = 'row1';
|
||||
filteredRows = controller.filterRows(testRows);
|
||||
expect(filteredRows.length).toBe(1);
|
||||
filters.col1 = 'match';
|
||||
filteredRows = controller.filterRows(testRows);
|
||||
expect(filteredRows.length).toBe(2);
|
||||
});
|
||||
|
||||
it('Sets rows on scope when rows change', function() {
|
||||
controller.updateRows(testRows);
|
||||
expect(mockScope.displayRows.length).toBe(3);
|
||||
expect(mockScope.displayRows).toEqual(testRows);
|
||||
});
|
||||
|
||||
describe('sorting', function() {
|
||||
var sortedRows;
|
||||
|
||||
it('Sorts rows ascending', function() {
|
||||
mockScope.sortColumn = 'col1';
|
||||
mockScope.sortDirection = 'asc';
|
||||
|
||||
sortedRows = controller.sortRows(testRows);
|
||||
expect(sortedRows[0].col1.text).toEqual('row1 col1 match');
|
||||
expect(sortedRows[1].col1.text).toEqual('row2 col1' +
|
||||
' match');
|
||||
expect(sortedRows[2].col1.text).toEqual('row3 col1');
|
||||
|
||||
});
|
||||
|
||||
it('Sorts rows descending', function() {
|
||||
mockScope.sortColumn = 'col1';
|
||||
mockScope.sortDirection = 'desc';
|
||||
|
||||
sortedRows = controller.sortRows(testRows);
|
||||
expect(sortedRows[0].col1.text).toEqual('row3 col1');
|
||||
expect(sortedRows[1].col1.text).toEqual('row2 col1 match');
|
||||
expect(sortedRows[2].col1.text).toEqual('row1 col1 match');
|
||||
});
|
||||
it('Sorts rows descending based on selected sort column', function() {
|
||||
mockScope.sortColumn = 'col2';
|
||||
mockScope.sortDirection = 'desc';
|
||||
|
||||
sortedRows = controller.sortRows(testRows);
|
||||
expect(sortedRows[0].col2.text).toEqual('ghi');
|
||||
expect(sortedRows[1].col2.text).toEqual('def');
|
||||
expect(sortedRows[2].col2.text).toEqual('abc');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,105 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,it,expect,beforeEach,waitsFor,jasmine,xit*/
|
||||
|
||||
define(
|
||||
[
|
||||
"../../src/controllers/TableOptionsController"
|
||||
],
|
||||
function (TableOptionsController) {
|
||||
"use strict";
|
||||
|
||||
describe('The Table Options Controller', function() {
|
||||
var mockDomainObject,
|
||||
mockCapability,
|
||||
controller,
|
||||
mockScope;
|
||||
|
||||
function promise(value) {
|
||||
return {
|
||||
then: function (callback){
|
||||
return promise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
mockCapability = jasmine.createSpyObj('mutationCapability', [
|
||||
'listen'
|
||||
]);
|
||||
mockDomainObject = jasmine.createSpyObj('domainObject', [
|
||||
'getCapability'
|
||||
]);
|
||||
mockDomainObject.getCapability.andReturn(mockCapability);
|
||||
mockScope = jasmine.createSpyObj('scope', [
|
||||
'$watchCollection'
|
||||
]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
controller = new TableOptionsController(mockScope);
|
||||
});
|
||||
|
||||
it('Registers a listener for mutation events on the object', function() {
|
||||
expect(mockCapability.listen).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Listens for changes to object composition and updates' +
|
||||
' options accordingly', function() {
|
||||
expect(mockScope.$watchCollection).toHaveBeenCalledWith('configuration.table.columns', jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe('Populates scope with a form definition based on provided' +
|
||||
' column configuration', function() {
|
||||
var mockModel;
|
||||
|
||||
beforeEach(function() {
|
||||
mockModel = {
|
||||
configuration: {
|
||||
table: {
|
||||
columns: {
|
||||
'column1': true,
|
||||
'column2': true,
|
||||
'column3': false,
|
||||
'column4': true,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
controller.populateForm(mockModel);
|
||||
});
|
||||
|
||||
it('creates form on scope', function() {
|
||||
expect(mockScope.columnsForm).toBeDefined();
|
||||
expect(mockScope.columnsForm.sections[0]).toBeDefined();
|
||||
expect(mockScope.columnsForm.sections[0].rows).toBeDefined();
|
||||
expect(mockScope.columnsForm.sections[0].rows.length).toBe(4);
|
||||
});
|
||||
|
||||
it('presents columns as checkboxes', function() {
|
||||
expect(mockScope.columnsForm.sections[0].rows.every(function(row){
|
||||
return row.control === 'checkbox';
|
||||
})).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,222 @@
|
||||
/*****************************************************************************
|
||||
* 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,describe,it,expect,beforeEach,waitsFor,jasmine,xit*/
|
||||
|
||||
define(
|
||||
[
|
||||
"../../src/controllers/TelemetryTableController"
|
||||
],
|
||||
function (TableController) {
|
||||
"use strict";
|
||||
|
||||
describe('The Table Controller', function() {
|
||||
var mockScope,
|
||||
mockTelemetryHandler,
|
||||
mockTelemetryHandle,
|
||||
mockTelemetryFormatter,
|
||||
mockDomainObject,
|
||||
mockTable,
|
||||
mockConfiguration,
|
||||
watches,
|
||||
controller;
|
||||
|
||||
function promise(value) {
|
||||
return {
|
||||
then: function (callback){
|
||||
return promise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
watches = {};
|
||||
mockScope = jasmine.createSpyObj('scope', [
|
||||
'$on',
|
||||
'$watch',
|
||||
'$watchCollection'
|
||||
]);
|
||||
|
||||
mockScope.$on.andCallFake(function(expression, callback){
|
||||
watches[expression] = callback;
|
||||
});
|
||||
mockScope.$watch.andCallFake(function(expression, callback){
|
||||
watches[expression] = callback;
|
||||
});
|
||||
mockScope.$watchCollection.andCallFake(function(expression, callback){
|
||||
watches[expression] = callback;
|
||||
});
|
||||
|
||||
mockConfiguration = {
|
||||
'range1': true,
|
||||
'range2': true,
|
||||
'domain1': true
|
||||
};
|
||||
|
||||
mockTable = jasmine.createSpyObj('table',
|
||||
[
|
||||
'buildColumns',
|
||||
'getColumnConfiguration',
|
||||
'getRowValues',
|
||||
'saveColumnConfiguration'
|
||||
]
|
||||
);
|
||||
mockTable.columns = [];
|
||||
mockTable.getColumnConfiguration.andReturn(mockConfiguration);
|
||||
|
||||
mockDomainObject= jasmine.createSpyObj('domainObject', [
|
||||
'getCapability',
|
||||
'useCapability',
|
||||
'getModel'
|
||||
]);
|
||||
mockDomainObject.getModel.andReturn({});
|
||||
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
mockTelemetryHandle = jasmine.createSpyObj('telemetryHandle', [
|
||||
'request',
|
||||
'promiseTelemetryObjects',
|
||||
'getMetadata',
|
||||
'unsubscribe',
|
||||
'makeDatum'
|
||||
]);
|
||||
mockTelemetryHandle.promiseTelemetryObjects.andReturn(promise(undefined));
|
||||
|
||||
mockTelemetryHandler = jasmine.createSpyObj('telemetryHandler', [
|
||||
'handle'
|
||||
]);
|
||||
mockTelemetryHandler.handle.andReturn(mockTelemetryHandle);
|
||||
|
||||
controller = new TableController(mockScope, mockTelemetryHandler, mockTelemetryFormatter);
|
||||
controller.table = mockTable;
|
||||
controller.handle = mockTelemetryHandle;
|
||||
});
|
||||
|
||||
it('subscribes to telemetry handler for telemetry updates', function() {
|
||||
controller.subscribe();
|
||||
expect(mockTelemetryHandler.handle).toHaveBeenCalled();
|
||||
expect(mockTelemetryHandle.request).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Unsubscribes from telemetry when scope is destroyed',function() {
|
||||
controller.handle = mockTelemetryHandle;
|
||||
watches.$destroy();
|
||||
expect(mockTelemetryHandle.unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('the controller makes use of the table', function() {
|
||||
|
||||
it('to create column definitions from telemetry' +
|
||||
' metadata', function() {
|
||||
controller.setup();
|
||||
expect(mockTable.buildColumns).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('to create column configuration, which is written to the' +
|
||||
' object model', function() {
|
||||
var mockModel = {};
|
||||
|
||||
controller.setup();
|
||||
expect(mockTable.getColumnConfiguration).toHaveBeenCalled();
|
||||
expect(mockTable.saveColumnConfiguration).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('updates the rows on scope when historical telemetry is received', function(){
|
||||
var mockSeries = {
|
||||
getPointCount: function() {
|
||||
return 5;
|
||||
},
|
||||
getDomainValue: function() {
|
||||
return 'Domain Value';
|
||||
},
|
||||
getRangeValue: function() {
|
||||
return 'Range Value';
|
||||
}
|
||||
},
|
||||
mockRow = {'domain': 'Domain Value', 'range': 'Range' +
|
||||
' Value'};
|
||||
|
||||
mockTelemetryHandle.makeDatum.andCallFake(function(){
|
||||
return mockRow;
|
||||
});
|
||||
mockTable.getRowValues.andReturn(mockRow);
|
||||
controller.addHistoricalData(mockDomainObject, mockSeries);
|
||||
|
||||
expect(controller.$scope.rows.length).toBe(5);
|
||||
expect(controller.$scope.rows[0]).toBe(mockRow);
|
||||
});
|
||||
|
||||
it('filters the visible columns based on configuration', function(){
|
||||
controller.filterColumns();
|
||||
expect(controller.$scope.headers.length).toBe(3);
|
||||
expect(controller.$scope.headers[2]).toEqual('domain1');
|
||||
|
||||
mockConfiguration.domain1 = false;
|
||||
controller.filterColumns();
|
||||
expect(controller.$scope.headers.length).toBe(2);
|
||||
expect(controller.$scope.headers[2]).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('creates event listeners', function(){
|
||||
beforeEach(function() {
|
||||
spyOn(controller,'subscribe');
|
||||
spyOn(controller, 'filterColumns');
|
||||
});
|
||||
|
||||
it('triggers telemetry subscription update when domain' +
|
||||
' object changes', function() {
|
||||
controller.registerChangeListeners();
|
||||
//'watches' object is populated by fake scope watch and
|
||||
// watchCollection functions defined above
|
||||
expect(watches.domainObject).toBeDefined();
|
||||
watches.domainObject(mockDomainObject);
|
||||
expect(controller.subscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('triggers telemetry subscription update when domain' +
|
||||
' object composition changes', function() {
|
||||
controller.registerChangeListeners();
|
||||
expect(watches['domainObject.getModel().composition']).toBeDefined();
|
||||
watches['domainObject.getModel().composition']();
|
||||
expect(controller.subscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('triggers telemetry subscription update when time' +
|
||||
' conductor bounds change', function() {
|
||||
controller.registerChangeListeners();
|
||||
expect(watches['telemetry:display:bounds']).toBeDefined();
|
||||
watches['telemetry:display:bounds']();
|
||||
expect(controller.subscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('triggers refiltering of the columns when configuration' +
|
||||
' changes', function() {
|
||||
controller.setup();
|
||||
expect(watches['domainObject.getModel().configuration.table.columns']).toBeDefined();
|
||||
watches['domainObject.getModel().configuration.table.columns']();
|
||||
expect(controller.filterColumns).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
Loading…
Reference in New Issue
Block a user