mirror of
https://github.com/nasa/openmct.git
synced 2025-02-20 17:33:23 +00:00
[Tables] Address performance issues observed in testathon (#2112)
* Use datum key of 'utc' for timestamp * Do not try to get column values for data that does not have those values * Collapse current time system columns * Noop parsing for numbers in LocalTimeFormat * Do not attempt to provide data for columns that object does not have telemetry for. Fixes #2027
This commit is contained in:
parent
3246480f82
commit
8c9fe2d36b
@ -60,8 +60,8 @@ define([
|
||||
"source": "eventGenerator",
|
||||
"domains": [
|
||||
{
|
||||
"key": "time",
|
||||
"name": "Time",
|
||||
"key": "utc",
|
||||
"name": "Timestamp",
|
||||
"format": "utc"
|
||||
}
|
||||
],
|
||||
|
@ -3,7 +3,7 @@
|
||||
<mct-table
|
||||
headers="headers"
|
||||
rows="rows"
|
||||
time-columns="tableController.timeColumns"
|
||||
time-columns="[tableController.table.timeSystemColumnTitle]"
|
||||
format-cell="formatCell"
|
||||
enableFilter="true"
|
||||
enableSort="true"
|
||||
|
69
platform/features/table/src/TableColumn.js
Normal file
69
platform/features/table/src/TableColumn.js
Normal file
@ -0,0 +1,69 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
define(function () {
|
||||
function TableColumn(openmct, telemetryObject, metadatum) {
|
||||
this.openmct = openmct;
|
||||
this.telemetryObject = telemetryObject;
|
||||
this.metadatum = metadatum;
|
||||
this.formatter = openmct.telemetry.getValueFormatter(metadatum);
|
||||
|
||||
this.titleValue = this.metadatum.name;
|
||||
}
|
||||
|
||||
TableColumn.prototype.title = function (title) {
|
||||
if (arguments.length > 0) {
|
||||
this.titleValue = title;
|
||||
}
|
||||
return this.titleValue;
|
||||
};
|
||||
|
||||
TableColumn.prototype.isCurrentTimeSystem = function () {
|
||||
var isCurrentTimeSystem = this.metadatum.hints.hasOwnProperty('domain') &&
|
||||
this.metadatum.key === this.openmct.time.timeSystem().key;
|
||||
|
||||
return isCurrentTimeSystem;
|
||||
};
|
||||
|
||||
TableColumn.prototype.hasValue = function (telemetryObject, telemetryDatum) {
|
||||
var keyStringForDatum = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
var keyStringForColumn = this.openmct.objects.makeKeyString(this.telemetryObject.identifier);
|
||||
return keyStringForDatum === keyStringForColumn && telemetryDatum.hasOwnProperty(this.metadatum.source);
|
||||
};
|
||||
|
||||
TableColumn.prototype.getValue = function (telemetryDatum, limitEvaluator) {
|
||||
var isValueColumn = !!(this.metadatum.hints.y || this.metadatum.hints.range);
|
||||
var alarm = isValueColumn &&
|
||||
limitEvaluator &&
|
||||
limitEvaluator.evaluate(telemetryDatum, this.metadatum);
|
||||
var value = {
|
||||
text: this.formatter.format(telemetryDatum),
|
||||
value: this.formatter.parse(telemetryDatum)
|
||||
};
|
||||
|
||||
if (alarm) {
|
||||
value.cssClass = alarm.cssClass;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
return TableColumn;
|
||||
});
|
@ -19,10 +19,10 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/* global Set */
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
['./TableColumn'],
|
||||
function (TableColumn) {
|
||||
|
||||
/**
|
||||
* Class that manages table metadata, state, and contents.
|
||||
@ -32,62 +32,31 @@ define(
|
||||
*/
|
||||
function TableConfiguration(domainObject, openmct) {
|
||||
this.domainObject = domainObject;
|
||||
this.columns = [];
|
||||
this.openmct = openmct;
|
||||
this.timeSystemColumn = undefined;
|
||||
this.columns = [];
|
||||
this.headers = new Set();
|
||||
this.timeSystemColumnTitle = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build column definitions based on supplied telemetry metadata
|
||||
* Build column definition based on supplied telemetry metadata
|
||||
* @param telemetryObject the telemetry producing object associated with this column
|
||||
* @param metadata Metadata describing the domains and ranges available
|
||||
* @returns {TableConfiguration} This object
|
||||
*/
|
||||
TableConfiguration.prototype.populateColumns = function (metadata) {
|
||||
var self = this;
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
TableConfiguration.prototype.addColumn = function (telemetryObject, metadatum) {
|
||||
var column = new TableColumn(this.openmct, telemetryObject, metadatum);
|
||||
|
||||
this.columns = [];
|
||||
|
||||
if (metadata) {
|
||||
|
||||
metadata.forEach(function (metadatum) {
|
||||
var formatter = telemetryApi.getValueFormatter(metadatum);
|
||||
|
||||
self.columns.push({
|
||||
getKey: function () {
|
||||
return metadatum.key;
|
||||
},
|
||||
getTitle: function () {
|
||||
return metadatum.name;
|
||||
},
|
||||
getValue: function (telemetryDatum, limitEvaluator) {
|
||||
var isValueColumn = !!(metadatum.hints.y || metadatum.hints.range);
|
||||
var alarm = isValueColumn &&
|
||||
limitEvaluator &&
|
||||
limitEvaluator.evaluate(telemetryDatum, metadatum);
|
||||
var value = {
|
||||
text: formatter.format(telemetryDatum),
|
||||
value: formatter.parse(telemetryDatum)
|
||||
};
|
||||
|
||||
if (alarm) {
|
||||
value.cssClass = alarm.cssClass;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
});
|
||||
if (column.isCurrentTimeSystem()) {
|
||||
if (!this.timeSystemColumnTitle) {
|
||||
this.timeSystemColumnTitle = column.title();
|
||||
}
|
||||
column.title(this.timeSystemColumnTitle);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a simple list of column titles
|
||||
* @returns {Array} The titles of the columns
|
||||
*/
|
||||
TableConfiguration.prototype.getHeaders = function () {
|
||||
return this.columns.map(function (column, i) {
|
||||
return column.getTitle() || 'Column ' + (i + 1);
|
||||
});
|
||||
this.columns.push(column);
|
||||
this.headers.add(column.title());
|
||||
};
|
||||
|
||||
/**
|
||||
@ -98,22 +67,32 @@ define(
|
||||
* @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 (limitEvaluator, datum) {
|
||||
return this.columns.reduce(function (rowObject, column, i) {
|
||||
var columnTitle = column.getTitle() || 'Column ' + (i + 1),
|
||||
columnValue = column.getValue(datum, limitEvaluator);
|
||||
|
||||
if (columnValue !== undefined && columnValue.text === undefined) {
|
||||
columnValue.text = '';
|
||||
}
|
||||
// Don't replace something with nothing.
|
||||
// This occurs when there are multiple columns with the same
|
||||
// column title
|
||||
if (rowObject[columnTitle] === undefined ||
|
||||
rowObject[columnTitle].text === undefined ||
|
||||
rowObject[columnTitle].text.length === 0) {
|
||||
TableConfiguration.prototype.getRowValues = function (telemetryObject, limitEvaluator, datum) {
|
||||
return this.columns.reduce(function (rowObject, column) {
|
||||
var columnTitle = column.title();
|
||||
var columnValue = {
|
||||
text: '',
|
||||
value: undefined
|
||||
};
|
||||
if (rowObject[columnTitle] === undefined) {
|
||||
rowObject[columnTitle] = columnValue;
|
||||
}
|
||||
|
||||
if (column.hasValue(telemetryObject, datum)) {
|
||||
columnValue = column.getValue(datum, limitEvaluator);
|
||||
|
||||
if (columnValue.text === undefined) {
|
||||
columnValue.text = '';
|
||||
}
|
||||
// Don't replace something with nothing.
|
||||
// This occurs when there are multiple columns with the same
|
||||
// column title
|
||||
if (rowObject[columnTitle].text === undefined ||
|
||||
rowObject[columnTitle].text.length === 0) {
|
||||
rowObject[columnTitle] = columnValue;
|
||||
}
|
||||
}
|
||||
|
||||
return rowObject;
|
||||
}, {});
|
||||
};
|
||||
@ -164,7 +143,7 @@ define(
|
||||
* specifying whether the column is visible or not. Default to
|
||||
* existing (persisted) configuration if available
|
||||
*/
|
||||
this.getHeaders().forEach(function (columnTitle) {
|
||||
this.headers.forEach(function (columnTitle) {
|
||||
configuration[columnTitle] =
|
||||
typeof defaultConfig[columnTitle] === 'undefined' ? true :
|
||||
defaultConfig[columnTitle];
|
||||
|
@ -93,7 +93,9 @@ define(
|
||||
// Calculate the new index of the last item in bounds
|
||||
endIndex = _.sortedLastIndex(this.highBuffer, testValue, this.sortField);
|
||||
added = this.highBuffer.splice(0, endIndex);
|
||||
this.telemetry = this.telemetry.concat(added);
|
||||
added.forEach(function (datum) {
|
||||
this.telemetry.push(datum);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
if (discarded && discarded.length > 0) {
|
||||
@ -132,6 +134,7 @@ define(
|
||||
// bounds events, so no bounds checking necessary
|
||||
if (this.sortField === undefined) {
|
||||
this.telemetry.push(item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -153,7 +156,6 @@ define(
|
||||
|
||||
// If out of bounds low, disregard data
|
||||
if (!boundsLow) {
|
||||
|
||||
// Going to check for duplicates. Bound the search problem to
|
||||
// items around the given time. Use sortedIndex because it
|
||||
// employs a binary search which is O(log n). Can use binary search
|
||||
|
@ -118,23 +118,18 @@ define(
|
||||
* to sort by. By default will just match on key.
|
||||
*
|
||||
* @private
|
||||
* @param {TimeSystem} timeSystem
|
||||
*/
|
||||
TelemetryTableController.prototype.sortByTimeSystem = function (timeSystem) {
|
||||
TelemetryTableController.prototype.sortByTimeSystem = function () {
|
||||
var scope = this.$scope;
|
||||
var sortColumn;
|
||||
scope.defaultSort = undefined;
|
||||
|
||||
if (timeSystem !== undefined) {
|
||||
this.table.columns.forEach(function (column) {
|
||||
if (column.getKey() === timeSystem.key) {
|
||||
sortColumn = column;
|
||||
}
|
||||
});
|
||||
if (sortColumn) {
|
||||
scope.defaultSort = sortColumn.getTitle();
|
||||
this.telemetry.sort(sortColumn.getTitle() + '.value');
|
||||
}
|
||||
sortColumn = this.table.columns.filter(function (column) {
|
||||
return column.isCurrentTimeSystem();
|
||||
})[0];
|
||||
if (sortColumn) {
|
||||
scope.defaultSort = sortColumn.title();
|
||||
this.telemetry.sort(sortColumn.title() + '.value');
|
||||
}
|
||||
};
|
||||
|
||||
@ -172,9 +167,6 @@ define(
|
||||
* @param rows
|
||||
*/
|
||||
TelemetryTableController.prototype.addRowsToTable = function (rows) {
|
||||
rows.forEach(function (row) {
|
||||
this.$scope.rows.push(row);
|
||||
}, this);
|
||||
this.$scope.$broadcast('add:rows', rows);
|
||||
};
|
||||
|
||||
@ -237,35 +229,21 @@ define(
|
||||
TelemetryTableController.prototype.loadColumns = function (objects) {
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
|
||||
this.table = new TableConfiguration(this.$scope.domainObject,
|
||||
this.openmct);
|
||||
|
||||
this.$scope.headers = [];
|
||||
|
||||
if (objects.length > 0) {
|
||||
var allMetadata = objects.map(telemetryApi.getMetadata.bind(telemetryApi));
|
||||
var allValueMetadata = _.flatten(allMetadata.map(
|
||||
function getMetadataValues(metadata) {
|
||||
return metadata.values();
|
||||
}
|
||||
));
|
||||
|
||||
this.table.populateColumns(allValueMetadata);
|
||||
|
||||
var domainColumns = telemetryApi.commonValuesForHints(allMetadata, ['domain']);
|
||||
this.timeColumns = domainColumns.map(function (metadatum) {
|
||||
return metadatum.name;
|
||||
});
|
||||
objects.forEach(function (object) {
|
||||
var metadataValues = telemetryApi.getMetadata(object).values();
|
||||
metadataValues.forEach(function (metadatum) {
|
||||
this.table.addColumn(object, metadatum);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
this.filterColumns();
|
||||
|
||||
// Default to no sort on underlying telemetry collection. Sorting
|
||||
// is necessary to do bounds filtering, but this is only possible
|
||||
// if data matches selected time system
|
||||
this.telemetry.sort(undefined);
|
||||
|
||||
var timeSystem = this.openmct.time.timeSystem();
|
||||
if (timeSystem !== undefined) {
|
||||
this.sortByTimeSystem(timeSystem);
|
||||
}
|
||||
|
||||
this.sortByTimeSystem();
|
||||
}
|
||||
|
||||
return objects;
|
||||
@ -302,7 +280,7 @@ define(
|
||||
/*
|
||||
* Process a batch of historical data
|
||||
*/
|
||||
function processData(historicalData, index, limitEvaluator) {
|
||||
function processData(object, historicalData, index, limitEvaluator) {
|
||||
if (index >= historicalData.length) {
|
||||
processedObjects++;
|
||||
|
||||
@ -311,14 +289,13 @@ define(
|
||||
}
|
||||
} else {
|
||||
rowData = rowData.concat(historicalData.slice(index, index + self.batchSize)
|
||||
.map(self.table.getRowValues.bind(self.table, limitEvaluator)));
|
||||
|
||||
.map(self.table.getRowValues.bind(self.table, object, limitEvaluator)));
|
||||
/*
|
||||
Use timeout to yield process to other UI activities. On
|
||||
return, process next batch
|
||||
*/
|
||||
self.timeoutHandle = self.$timeout(function () {
|
||||
processData(historicalData, index + self.batchSize, limitEvaluator);
|
||||
processData(object, historicalData, index + self.batchSize, limitEvaluator);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -327,7 +304,7 @@ define(
|
||||
// Only process the most recent request
|
||||
if (requestTime === self.lastRequestTime) {
|
||||
var limitEvaluator = openmct.telemetry.limitEvaluator(object);
|
||||
processData(historicalData, 0, limitEvaluator);
|
||||
processData(object, historicalData, 0, limitEvaluator);
|
||||
} else {
|
||||
resolve(rowData);
|
||||
}
|
||||
@ -367,7 +344,6 @@ define(
|
||||
var telemetryCollection = this.telemetry;
|
||||
//Set table max length to avoid unbounded growth.
|
||||
var limitEvaluator;
|
||||
var added = false;
|
||||
var table = this.table;
|
||||
|
||||
this.subscriptions.forEach(function (subscription) {
|
||||
@ -377,7 +353,7 @@ define(
|
||||
|
||||
function newData(domainObject, datum) {
|
||||
limitEvaluator = telemetryApi.limitEvaluator(domainObject);
|
||||
added = telemetryCollection.add([table.getRowValues(limitEvaluator, datum)]);
|
||||
telemetryCollection.add([table.getRowValues(domainObject, limitEvaluator, datum)]);
|
||||
}
|
||||
|
||||
objects.forEach(function (object) {
|
||||
|
@ -27,31 +27,52 @@ define(
|
||||
function (Table) {
|
||||
|
||||
describe("A table", function () {
|
||||
var mockDomainObject,
|
||||
var mockTableObject,
|
||||
mockTelemetryObject,
|
||||
mockAPI,
|
||||
mockTelemetryAPI,
|
||||
table,
|
||||
mockTimeAPI,
|
||||
mockObjectsAPI,
|
||||
mockModel;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject = jasmine.createSpyObj('domainObject',
|
||||
mockTableObject = jasmine.createSpyObj('domainObject',
|
||||
['getModel', 'useCapability', 'getCapability', 'hasCapability']
|
||||
);
|
||||
mockModel = {};
|
||||
mockDomainObject.getModel.and.returnValue(mockModel);
|
||||
mockDomainObject.getCapability.and.callFake(function (name) {
|
||||
mockTableObject.getModel.and.returnValue(mockModel);
|
||||
mockTableObject.getCapability.and.callFake(function (name) {
|
||||
return name === 'editor' && {
|
||||
isEditContextRoot: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
mockTelemetryObject = {
|
||||
identifier: {
|
||||
namespace: 'mock',
|
||||
key: 'domainObject'
|
||||
}
|
||||
};
|
||||
|
||||
mockTelemetryAPI = jasmine.createSpyObj('telemetryAPI', [
|
||||
'getValueFormatter'
|
||||
]);
|
||||
mockTimeAPI = jasmine.createSpyObj('timeAPI', [
|
||||
'timeSystem'
|
||||
]);
|
||||
mockObjectsAPI = jasmine.createSpyObj('objectsAPI', [
|
||||
'makeKeyString'
|
||||
]);
|
||||
mockObjectsAPI.makeKeyString.and.callFake(function (identifier) {
|
||||
return [identifier.namespace, identifier.key].join(':');
|
||||
});
|
||||
|
||||
mockAPI = {
|
||||
telemetry: mockTelemetryAPI
|
||||
telemetry: mockTelemetryAPI,
|
||||
time: mockTimeAPI,
|
||||
objects: mockObjectsAPI
|
||||
};
|
||||
mockTelemetryAPI.getValueFormatter.and.callFake(function (metadata) {
|
||||
var formatter = jasmine.createSpyObj(
|
||||
@ -69,7 +90,7 @@ define(
|
||||
return formatter;
|
||||
});
|
||||
|
||||
table = new Table(mockDomainObject, mockAPI);
|
||||
table = new Table(mockTableObject, mockAPI);
|
||||
});
|
||||
|
||||
describe("Building columns from telemetry metadata", function () {
|
||||
@ -77,51 +98,57 @@ define(
|
||||
{
|
||||
name: 'Range 1',
|
||||
key: 'range1',
|
||||
source: 'range1',
|
||||
hints: {
|
||||
y: 1
|
||||
range: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Range 2',
|
||||
key: 'range2',
|
||||
source: 'range2',
|
||||
hints: {
|
||||
y: 2
|
||||
range: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Domain 1',
|
||||
key: 'domain1',
|
||||
source: 'domain1',
|
||||
format: 'utc',
|
||||
hints: {
|
||||
x: 1
|
||||
domain: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Domain 2',
|
||||
key: 'domain2',
|
||||
source: 'domain2',
|
||||
format: 'utc',
|
||||
hints: {
|
||||
x: 2
|
||||
domain: 2
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
beforeEach(function () {
|
||||
table.populateColumns(metadata);
|
||||
mockTimeAPI.timeSystem.and.returnValue({
|
||||
key: 'domain1'
|
||||
});
|
||||
metadata.forEach(function (metadatum) {
|
||||
table.addColumn(mockTelemetryObject, metadatum);
|
||||
});
|
||||
});
|
||||
|
||||
it("populates columns", function () {
|
||||
expect(table.columns.length).toBe(4);
|
||||
});
|
||||
|
||||
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("Produces headers for each column based on metadata name", function () {
|
||||
expect(table.headers.size).toBe(4);
|
||||
Array.from(table.headers.values).forEach(function (header, i) {
|
||||
expect(header).toEqual(metadata[i].name);
|
||||
});
|
||||
});
|
||||
|
||||
it("Provides a default configuration with all columns" +
|
||||
@ -169,11 +196,10 @@ define(
|
||||
};
|
||||
}
|
||||
};
|
||||
rowValues = table.getRowValues(limitEvaluator, datum);
|
||||
rowValues = table.getRowValues(mockTelemetryObject, limitEvaluator, datum);
|
||||
});
|
||||
|
||||
it("Returns a value for every column", function () {
|
||||
expect(rowValues['Range 1'].text).toBeDefined();
|
||||
expect(rowValues['Range 1'].text).toEqual(10);
|
||||
});
|
||||
|
||||
|
@ -78,7 +78,8 @@ define(
|
||||
]);
|
||||
|
||||
mockObjectAPI = jasmine.createSpyObj("objectAPI", [
|
||||
"observe"
|
||||
"observe",
|
||||
"makeKeyString"
|
||||
]);
|
||||
unobserve = jasmine.createSpy("unobserve");
|
||||
mockObjectAPI.observe.and.returnValue(unobserve);
|
||||
@ -184,8 +185,7 @@ define(
|
||||
var mockComposition,
|
||||
mockTelemetryObject,
|
||||
mockChildren,
|
||||
unsubscribe,
|
||||
done;
|
||||
unsubscribe;
|
||||
|
||||
beforeEach(function () {
|
||||
mockComposition = jasmine.createSpyObj("composition", [
|
||||
@ -207,8 +207,6 @@ define(
|
||||
mockTelemetryAPI.isTelemetryObject.and.callFake(function (obj) {
|
||||
return obj.identifier.key === mockTelemetryObject.identifier.key;
|
||||
});
|
||||
|
||||
done = false;
|
||||
});
|
||||
|
||||
it('fetches historical data for the time period specified by the conductor bounds', function () {
|
||||
@ -292,40 +290,37 @@ define(
|
||||
});
|
||||
|
||||
describe('populates table columns', function () {
|
||||
var domainMetadata;
|
||||
var allMetadata;
|
||||
var mockTimeSystem;
|
||||
var mockTimeSystem1;
|
||||
var mockTimeSystem2;
|
||||
|
||||
beforeEach(function () {
|
||||
domainMetadata = [{
|
||||
key: "column1",
|
||||
name: "Column 1",
|
||||
hints: {}
|
||||
}];
|
||||
|
||||
allMetadata = [{
|
||||
key: "column1",
|
||||
name: "Column 1",
|
||||
hints: {}
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
}, {
|
||||
key: "column2",
|
||||
name: "Column 2",
|
||||
hints: {}
|
||||
hints: {
|
||||
domain: 2
|
||||
}
|
||||
}, {
|
||||
key: "column3",
|
||||
name: "Column 3",
|
||||
hints: {}
|
||||
}];
|
||||
|
||||
mockTimeSystem = {
|
||||
mockTimeSystem1 = {
|
||||
key: "column1"
|
||||
};
|
||||
mockTimeSystem2 = {
|
||||
key: "column2"
|
||||
};
|
||||
|
||||
mockTelemetryAPI.commonValuesForHints.and.callFake(function (metadata, hints) {
|
||||
if (_.eq(hints, ["domain"])) {
|
||||
return domainMetadata;
|
||||
}
|
||||
});
|
||||
mockConductor.timeSystem.and.returnValue(mockTimeSystem1);
|
||||
|
||||
mockTelemetryAPI.getMetadata.and.returnValue({
|
||||
values: function () {
|
||||
@ -345,9 +340,12 @@ define(
|
||||
});
|
||||
|
||||
it('and sorts by column matching time system', function () {
|
||||
expect(mockScope.defaultSort).not.toEqual("Column 1");
|
||||
controller.sortByTimeSystem(mockTimeSystem);
|
||||
expect(mockScope.defaultSort).toEqual("Column 1");
|
||||
|
||||
mockConductor.timeSystem.and.returnValue(mockTimeSystem2);
|
||||
controller.sortByTimeSystem();
|
||||
|
||||
expect(mockScope.defaultSort).toEqual("Column 2");
|
||||
});
|
||||
|
||||
it('batches processing of rows for performance when receiving historical telemetry', function () {
|
||||
@ -403,25 +401,16 @@ define(
|
||||
|
||||
describe('when telemetry is added', function () {
|
||||
var testRows;
|
||||
var expectedRows;
|
||||
|
||||
beforeEach(function () {
|
||||
testRows = [{ a: 0 }, { a: 1 }, { a: 2 }];
|
||||
mockScope.rows = [{ a: -1 }];
|
||||
expectedRows = mockScope.rows.concat(testRows);
|
||||
|
||||
spyOn(controller.telemetry, "on").and.callThrough();
|
||||
controller.registerChangeListeners();
|
||||
|
||||
controller.telemetry.on.calls.all().forEach(function (call) {
|
||||
if (call.args[0] === 'added') {
|
||||
call.args[1](testRows);
|
||||
}
|
||||
});
|
||||
controller.telemetry.add(testRows);
|
||||
});
|
||||
|
||||
it("adds it to rows in scope", function () {
|
||||
expect(mockScope.rows).toEqual(expectedRows);
|
||||
it("Adds the rows to the MCTTable directive", function () {
|
||||
expect(mockScope.$broadcast).toHaveBeenCalledWith("add:rows", testRows);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -113,6 +113,9 @@ define([
|
||||
};
|
||||
|
||||
LocalTimeFormat.prototype.parse = function (text) {
|
||||
if (typeof text === 'number') {
|
||||
return text;
|
||||
}
|
||||
return moment(text, DATE_FORMATS).valueOf();
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user