mirror of
https://github.com/nasa/openmct.git
synced 2025-01-31 00:23:54 +00:00
[Tables] Refactoring for consolidation of historical and real-time tables
Added batch processing of large historical queries. #1077
This commit is contained in:
parent
3544caf4be
commit
2a4944d6ee
@ -217,8 +217,8 @@ define(
|
||||
if (handle) {
|
||||
handle.unsubscribe();
|
||||
handle = undefined;
|
||||
conductor.off("timeOfInterest", changeTimeOfInterest);
|
||||
}
|
||||
conductor.off("timeOfInterest", changeTimeOfInterest);
|
||||
}
|
||||
|
||||
function requery() {
|
||||
|
@ -87,7 +87,7 @@ define([
|
||||
{
|
||||
"key": "TelemetryTableController",
|
||||
"implementation": TelemetryTableController,
|
||||
"depends": ["$scope", "openmct"]
|
||||
"depends": ["$scope", "$timeout", "openmct"]
|
||||
},
|
||||
{
|
||||
"key": "TableOptionsController",
|
||||
|
@ -5,7 +5,7 @@
|
||||
Export
|
||||
</a>
|
||||
</div>
|
||||
<div class="l-view-section scrolling" style="overflow: auto;" mct-resize="resize()">
|
||||
<div class="l-view-section scrolling" style="overflow: auto;">
|
||||
<table class="sizing-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
@ -32,8 +32,7 @@
|
||||
enableSort ? 'sortable' : '',
|
||||
sortColumn === header ? 'sort' : '',
|
||||
sortDirection || ''
|
||||
].join(' ')"
|
||||
ng-click="toggleSort(header)">
|
||||
].join(' ')">
|
||||
{{ header }}
|
||||
</th>
|
||||
</tr>
|
||||
@ -59,8 +58,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-repeat-end
|
||||
ng-style="{ top: visibleRow.offsetY + 'px' }"
|
||||
ng-click="table.onRowClick($event, visibleRow.rowIndex) ">
|
||||
ng-style="{ top: visibleRow.offsetY + 'px' }">
|
||||
<td ng-repeat="header in displayHeaders"
|
||||
ng-style=" {
|
||||
width: columnWidths[$index] + 'px',
|
||||
|
@ -6,7 +6,7 @@
|
||||
rows="rows"
|
||||
enableFilter="true"
|
||||
enableSort="true"
|
||||
sort-column="defaultSort"
|
||||
default-sort="defaultSort"
|
||||
class="tabular-holder has-control-bar">
|
||||
</mct-table>
|
||||
</div>
|
@ -53,6 +53,7 @@ define(
|
||||
var formatter = telemetryApi.getValueFormatter(metadatum);
|
||||
|
||||
self.addColumn({
|
||||
metadata: metadatum,
|
||||
getTitle: function () {
|
||||
return metadatum.name;
|
||||
},
|
||||
|
@ -12,12 +12,12 @@ define(
|
||||
* @param element
|
||||
* @constructor
|
||||
*/
|
||||
function MCTTableController($scope, $timeout, element, exportService, formatService, openmct) {
|
||||
function MCTTableController($scope, $window, element, exportService, formatService, openmct) {
|
||||
var self = this;
|
||||
|
||||
this.$scope = $scope;
|
||||
this.element = $(element[0]);
|
||||
this.$timeout = $timeout;
|
||||
this.$window = $window;
|
||||
this.maxDisplayRows = 50;
|
||||
|
||||
this.scrollable = this.element.find('.l-view-section.scrolling').first();
|
||||
@ -27,15 +27,39 @@ define(
|
||||
this.conductor = openmct.conductor;
|
||||
this.toiFormatter = undefined;
|
||||
this.formatService = formatService;
|
||||
this.callbacks = {};
|
||||
|
||||
//Bind all class functions to 'this'
|
||||
Object.keys(MCTTableController.prototype).filter(function (key) {
|
||||
return typeof MCTTableController.prototype[key] === 'function';
|
||||
}).forEach(function (key) {
|
||||
this[key] = MCTTableController.prototype[key].bind(this);
|
||||
}.bind(this));
|
||||
_.bindAll(this, [
|
||||
'destroyConductorListeners',
|
||||
'changeTimeSystem',
|
||||
'scrollToBottom',
|
||||
'addRow',
|
||||
'removeRow',
|
||||
'onScroll',
|
||||
'firstVisible',
|
||||
'lastVisible',
|
||||
'setVisibleRows',
|
||||
'setHeaders',
|
||||
'setElementSizes',
|
||||
'binarySearch',
|
||||
'insertSorted',
|
||||
'sortComparator',
|
||||
'sortRows',
|
||||
'buildLargestRow',
|
||||
'resize',
|
||||
'filterAndSort',
|
||||
'setRows',
|
||||
'filterRows',
|
||||
'scrollToRow',
|
||||
'setTimeOfInterestRow',
|
||||
'changeTimeOfInterest',
|
||||
'changeBounds',
|
||||
'onRowClick',
|
||||
'digest'
|
||||
]);
|
||||
|
||||
this.scrollable.on('scroll', this.onScroll.bind(this));
|
||||
this.scrollable.on('scroll', this.onScroll);
|
||||
|
||||
$scope.visibleRows = [];
|
||||
|
||||
@ -86,7 +110,7 @@ define(
|
||||
$scope.sortDirection = 'asc';
|
||||
}
|
||||
self.setRows($scope.rows);
|
||||
self.setTimeOfInterest(self.conductor.timeOfInterest());
|
||||
self.setTimeOfInterestRow(self.conductor.timeOfInterest());
|
||||
};
|
||||
|
||||
/*
|
||||
@ -108,7 +132,11 @@ define(
|
||||
* Populated from the default-sort attribute on MctTable
|
||||
* directive tag.
|
||||
*/
|
||||
$scope.$watch('sortColumn', $scope.toggleSort);
|
||||
$scope.$watch('defaultSort', function (newColumn, oldColumn) {
|
||||
if (newColumn !== oldColumn) {
|
||||
$scope.toggleSort(newColumn)
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Listen for resize events to trigger recalculation of table width
|
||||
@ -125,7 +153,7 @@ define(
|
||||
this.destroyConductorListeners();
|
||||
|
||||
this.conductor.on('timeSystem', this.changeTimeSystem);
|
||||
this.conductor.on('timeOfInterest', this.setTimeOfInterest);
|
||||
this.conductor.on('timeOfInterest', this.changeTimeOfInterest);
|
||||
this.conductor.on('bounds', this.changeBounds);
|
||||
|
||||
// If time system defined, set initially
|
||||
@ -135,12 +163,22 @@ define(
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
$scope.$on('$destroy', this.destroyConductorListeners);
|
||||
}
|
||||
console.log('constructed');
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
this.scrollable.off('scroll', this.onScroll);
|
||||
this.destroyConductorListeners();
|
||||
|
||||
// In case for some reason this controller instance lingers around,
|
||||
// destroy scope as it can be extremely large for large tables.
|
||||
delete this.$scope;
|
||||
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
MCTTableController.prototype.destroyConductorListeners = function () {
|
||||
this.conductor.off('timeSystem', this.changeTimeSystem);
|
||||
this.conductor.off('timeOfInterest', this.setTimeOfInterest);
|
||||
this.conductor.off('timeOfInterest', this.changeTimeOfInterest);
|
||||
this.conductor.off('bounds', this.changeBounds);
|
||||
};
|
||||
|
||||
@ -160,7 +198,7 @@ define(
|
||||
//Use timeout to defer execution until next digest when any
|
||||
// pending UI changes have completed, eg. a new row in the table.
|
||||
if (this.$scope.autoScroll) {
|
||||
this.$timeout(function () {
|
||||
this.digest(function () {
|
||||
self.scrollable[0].scrollTop = self.scrollable[0].scrollHeight;
|
||||
});
|
||||
}
|
||||
@ -183,6 +221,12 @@ define(
|
||||
this.resize([this.$scope.sizingRow, row])
|
||||
.then(this.setVisibleRows.bind(this))
|
||||
.then(this.scrollToBottom.bind(this));
|
||||
|
||||
var toi = this.conductor.timeOfInterest();
|
||||
if (toi !== -1) {
|
||||
this.setTimeOfInterestRow(toi);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@ -193,8 +237,8 @@ define(
|
||||
*/
|
||||
MCTTableController.prototype.removeRow = function (event, rowIndex) {
|
||||
var row = this.$scope.rows[rowIndex],
|
||||
// Do a sequential search here. Only way of finding row is by
|
||||
// object equality, so array is in effect unsorted.
|
||||
// Do a sequential search here. Only way of finding row is by
|
||||
// object equality, so array is in effect unsorted.
|
||||
indexInDisplayRows = this.$scope.displayRows.indexOf(row);
|
||||
if (indexInDisplayRows !== -1) {
|
||||
this.$scope.displayRows.splice(indexInDisplayRows, 1);
|
||||
@ -522,6 +566,27 @@ define(
|
||||
return largestRow;
|
||||
};
|
||||
|
||||
MCTTableController.prototype.digest = function (callback) {
|
||||
var scope = this.$scope;
|
||||
var callbacks = this.callbacks;
|
||||
var requestAnimationFrame = this.$window.requestAnimationFrame;
|
||||
|
||||
var promise = callbacks[callback];
|
||||
|
||||
if (!promise){
|
||||
promise = new Promise(function (resolve) {
|
||||
requestAnimationFrame(function() {
|
||||
scope.$digest();
|
||||
delete callbacks[callback];
|
||||
resolve(callback && callback());
|
||||
});
|
||||
});
|
||||
callbacks[callback] = promise;
|
||||
}
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the widest row in the table, and if necessary, resizes
|
||||
* the table accordingly
|
||||
@ -533,7 +598,7 @@ define(
|
||||
*/
|
||||
MCTTableController.prototype.resize = function (rows) {
|
||||
this.$scope.sizingRow = this.buildLargestRow(rows);
|
||||
return this.$timeout(this.setElementSizes.bind(this));
|
||||
return this.digest(this.setElementSizes);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -566,15 +631,15 @@ define(
|
||||
.then(this.setVisibleRows)
|
||||
//Timeout following setVisibleRows to allow digest to
|
||||
// perform DOM changes, otherwise scrollTo won't work.
|
||||
.then(this.$timeout)
|
||||
.then(this.digest)
|
||||
.then(function () {
|
||||
//If TOI specified, scroll to it
|
||||
var timeOfInterest = this.conductor.timeOfInterest();
|
||||
if (timeOfInterest) {
|
||||
this.setTimeOfInterest(timeOfInterest);
|
||||
this.setTimeOfInterestRow(timeOfInterest);
|
||||
this.scrollToRow(this.$scope.toiRowIndex);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -635,7 +700,7 @@ define(
|
||||
* Update rows with new data. If filtering is enabled, rows
|
||||
* will be sorted before display.
|
||||
*/
|
||||
MCTTableController.prototype.setTimeOfInterest = function (newTOI) {
|
||||
MCTTableController.prototype.setTimeOfInterestRow = function (newTOI) {
|
||||
var isSortedByTime =
|
||||
this.$scope.timeColumns &&
|
||||
this.$scope.timeColumns.indexOf(this.$scope.sortColumn) !== -1;
|
||||
@ -652,17 +717,22 @@ define(
|
||||
|
||||
if (rowIndex > 0 && rowIndex < this.$scope.displayRows.length) {
|
||||
this.$scope.toiRowIndex = rowIndex;
|
||||
this.scrollToRow(this.$scope.toiRowIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MCTTableController.prototype.changeTimeOfInterest = function (newTOI) {
|
||||
this.setTimeOfInterestRow(newTOI);
|
||||
this.scrollToRow(this.$scope.toiRowIndex);
|
||||
};
|
||||
|
||||
/**
|
||||
* On zoom, pan, etc. reset TOI
|
||||
* @param bounds
|
||||
*/
|
||||
MCTTableController.prototype.changeBounds = function (bounds) {
|
||||
this.setTimeOfInterest(this.conductor.timeOfInterest());
|
||||
this.setTimeOfInterestRow(this.conductor.timeOfInterest());
|
||||
this.scrollToRow(this.$scope.toiRowIndex);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -42,43 +42,47 @@ define(
|
||||
*/
|
||||
function TelemetryTableController(
|
||||
$scope,
|
||||
$timeout,
|
||||
openmct
|
||||
) {
|
||||
var self = this;
|
||||
|
||||
this.$scope = $scope;
|
||||
this.$timeout = $timeout;
|
||||
this.openmct = openmct;
|
||||
this.batchSize = 1000;
|
||||
|
||||
/*
|
||||
* Initialization block
|
||||
*/
|
||||
this.columns = {}; //Range and Domain columns
|
||||
this.handle = undefined;
|
||||
this.deregisterListeners = [];
|
||||
this.subscriptions = [];
|
||||
this.timeColumns = [];
|
||||
$scope.rows = [];
|
||||
this.table = new TableConfiguration($scope.domainObject,
|
||||
openmct);
|
||||
this.changeListeners = [];
|
||||
this.conductor = openmct.conductor;
|
||||
this.openmct = openmct;
|
||||
this.newObject = objectUtils.toNewFormat($scope.domainObject.getModel(), $scope.domainObject.getId());
|
||||
this.lastBounds = this.openmct.conductor.bounds();
|
||||
this.requestTime = 0;
|
||||
|
||||
$scope.rows = [];
|
||||
/*
|
||||
* Create a new format object from legacy object, and replace it
|
||||
* when it changes
|
||||
*/
|
||||
this.newObject = objectUtils.toNewFormat($scope.domainObject.getModel(),
|
||||
$scope.domainObject.getId());
|
||||
|
||||
// Subscribe to telemetry when a domain object becomes available
|
||||
this.$scope.$watch('domainObject', function () {
|
||||
self.subscribe();
|
||||
self.registerChangeListeners();
|
||||
});
|
||||
this.mutationListener = openmct.objects.observe(this.newObject, "*", function (domainObject){
|
||||
self.newObject = domainObject;
|
||||
});
|
||||
_.bindAll(this, [
|
||||
'destroy',
|
||||
'sortByTimeSystem',
|
||||
'loadColumns',
|
||||
'getHistoricalData',
|
||||
'subscribeToNewData',
|
||||
'changeBounds'
|
||||
]);
|
||||
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.getData();
|
||||
this.registerChangeListeners();
|
||||
|
||||
// Unsubscribe when the plot is destroyed
|
||||
this.$scope.$on("$destroy", this.destroy);
|
||||
this.timeColumns = [];
|
||||
|
||||
|
||||
this.sortByTimeSystem = this.sortByTimeSystem.bind(this);
|
||||
this.conductor.on('timeSystem', this.sortByTimeSystem);
|
||||
this.conductor.off('timeSystem', this.sortByTimeSystem);
|
||||
|
||||
this.subscriptions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,133 +95,254 @@ define(
|
||||
scope.defaultSort = undefined;
|
||||
if (timeSystem) {
|
||||
this.table.columns.forEach(function (column) {
|
||||
if (column.domainMetadata && column.domainMetadata.key === timeSystem.metadata.key) {
|
||||
if (column.metadata.key === timeSystem.metadata.key) {
|
||||
scope.defaultSort = column.getTitle();
|
||||
}
|
||||
});
|
||||
this.$scope.rows = _.sortBy(this.$scope.rows, function (row) {
|
||||
return row[this.$scope.defaultSort];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TelemetryTableController.prototype.unregisterChangeListeners = function () {
|
||||
this.changeListeners.forEach(function (listener) {
|
||||
return listener && listener();
|
||||
});
|
||||
this.changeListeners = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Defer registration of change listeners until domain object is
|
||||
* available in order to avoid race conditions
|
||||
* Attach listeners to domain object to respond to changes due to
|
||||
* composition, etc.
|
||||
* @private
|
||||
*/
|
||||
TelemetryTableController.prototype.registerChangeListeners = function () {
|
||||
var self = this;
|
||||
this.unregisterChangeListeners();
|
||||
this.deregisterListeners.forEach(function (deregister){
|
||||
deregister();
|
||||
});
|
||||
this.deregisterListeners = [];
|
||||
|
||||
// When composition changes, re-subscribe to the various
|
||||
// telemetry subscriptions
|
||||
this.changeListeners.push(this.$scope.$watchCollection(
|
||||
'domainObject.getModel().composition',
|
||||
function (newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
self.subscribe();
|
||||
}
|
||||
})
|
||||
this.deregisterListeners.push(
|
||||
this.openmct.objects.observe(this.newObject, "*",
|
||||
function (domainObject){
|
||||
this.newObject = domainObject;
|
||||
this.getData();
|
||||
}.bind(this)
|
||||
)
|
||||
);
|
||||
this.openmct.conductor.on('timeSystem', this.sortByTimeSystem);
|
||||
this.openmct.conductor.on('bounds', this.changeBounds);
|
||||
};
|
||||
|
||||
TelemetryTableController.prototype.tick = function (bounds) {
|
||||
// Can't do ticking until we change how data is handled
|
||||
// Pass raw values to table, with format function
|
||||
|
||||
/*if (this.$scope.defaultSort) {
|
||||
this.$scope.rows.filter(function (row){
|
||||
return row[]
|
||||
})
|
||||
}*/
|
||||
};
|
||||
|
||||
TelemetryTableController.prototype.changeBounds = function (bounds) {
|
||||
var follow = this.openmct.conductor.follow();
|
||||
var isTick = follow &&
|
||||
bounds.start !== this.lastBounds.start &&
|
||||
bounds.end !== this.lastBounds.end;
|
||||
var isDeltaChange = follow &&
|
||||
!isTick &&
|
||||
(bounds.start !== this.lastBounds.start ||
|
||||
bounds.end !== this.lastBounds.end);
|
||||
|
||||
if (isTick){
|
||||
// Treat it as a realtime tick
|
||||
// Drop old data that falls outside of bounds
|
||||
this.tick(bounds);
|
||||
} else if (isDeltaChange){
|
||||
// No idea...
|
||||
// Historical query for bounds, then tick on
|
||||
this.getData();
|
||||
} else {
|
||||
// Is fixed bounds change
|
||||
this.getData();
|
||||
}
|
||||
this.lastBounds = bounds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Release the current subscription (called when scope is destroyed)
|
||||
*/
|
||||
TelemetryTableController.prototype.destroy = function () {
|
||||
|
||||
this.openmct.conductor.off('timeSystem', this.sortByTimeSystem);
|
||||
this.openmct.conductor.off('bounds', this.changeBounds);
|
||||
|
||||
this.subscriptions.forEach(function (subscription) {
|
||||
subscription()
|
||||
subscription();
|
||||
});
|
||||
this.mutationListener();
|
||||
this.deregisterListeners.forEach(function (deregister){
|
||||
deregister();
|
||||
});
|
||||
this.subscriptions = [];
|
||||
this.deregisterListeners = [];
|
||||
|
||||
if (this.timeoutHandle) {
|
||||
this.$timeout.cancel(this.timeoutHandle);
|
||||
}
|
||||
|
||||
// In case controller instance lingers around (currently there is a
|
||||
// temporary memory leak with PlotController), clean up scope as it
|
||||
// can be extremely large.
|
||||
this.$scope = null;
|
||||
this.table = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param objects
|
||||
* @returns {*}
|
||||
*/
|
||||
TelemetryTableController.prototype.loadColumns = function (objects) {
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
|
||||
if (objects.length > 0) {
|
||||
var metadatas = objects.map(telemetryApi.getMetadata.bind(telemetryApi));
|
||||
var allColumns = telemetryApi.commonValuesForHints(metadatas, []);
|
||||
|
||||
this.table.populateColumns(allColumns);
|
||||
|
||||
this.timeColumns = telemetryApi.commonValuesForHints(metadatas, ['x']).map(function (metadatum) {
|
||||
return metadatum.name;
|
||||
});
|
||||
|
||||
this.filterColumns();
|
||||
|
||||
var timeSystem = this.openmct.conductor.timeSystem();
|
||||
if (timeSystem) {
|
||||
this.sortByTimeSystem(timeSystem);
|
||||
}
|
||||
}
|
||||
return objects;
|
||||
};
|
||||
|
||||
/**
|
||||
Create a new subscription. This can be overridden by children to
|
||||
change default behaviour (which is to retrieve historical telemetry
|
||||
only).
|
||||
* @private
|
||||
* @param objects The domain objects to request telemetry for
|
||||
* @returns {*|{configFile}|app|boolean|Route|Object}
|
||||
*/
|
||||
TelemetryTableController.prototype.subscribe = function () {
|
||||
var self = this;
|
||||
TelemetryTableController.prototype.getHistoricalData = function (objects) {
|
||||
var openmct = this.openmct;
|
||||
var bounds = openmct.conductor.bounds();
|
||||
var scope = this.$scope;
|
||||
var processedObjects = 0;
|
||||
var requestTime = this.lastRequestTime = Date.now();
|
||||
|
||||
return new Promise(function (resolve, reject){
|
||||
console.log('Created promise');
|
||||
function finishProcessing(tableRows){
|
||||
scope.rows = tableRows;
|
||||
scope.loading = false;
|
||||
console.log('Resolved promise');
|
||||
resolve(tableRows);
|
||||
}
|
||||
|
||||
function processData(historicalData, index, rowData, limitEvaluator){
|
||||
console.log("Processing batch");
|
||||
if (index >= historicalData.length) {
|
||||
processedObjects++;
|
||||
|
||||
if (processedObjects === objects.length) {
|
||||
finishProcessing(rowData);
|
||||
}
|
||||
} else {
|
||||
rowData = rowData.concat(historicalData.slice(index, index + this.batchSize)
|
||||
.map(this.table.getRowValues.bind(this.table, limitEvaluator)));
|
||||
this.timeoutHandle = this.$timeout(processData.bind(
|
||||
this,
|
||||
historicalData,
|
||||
index + this.batchSize,
|
||||
rowData,
|
||||
limitEvaluator
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function makeTableRows(object, historicalData) {
|
||||
// Only process one request at a time
|
||||
if (requestTime === this.lastRequestTime) {
|
||||
console.log('Processing request');
|
||||
var limitEvaluator = openmct.telemetry.limitEvaluator(object);
|
||||
processData.call(this, historicalData, 0, [], limitEvaluator);
|
||||
} else {
|
||||
console.log('Ignoring returned data because of staleness');
|
||||
resolve([]);
|
||||
}
|
||||
}
|
||||
|
||||
function requestData (object) {
|
||||
return openmct.telemetry.request(object, {
|
||||
start: bounds.start,
|
||||
end: bounds.end
|
||||
}).then(makeTableRows.bind(this, object))
|
||||
.catch(reject);
|
||||
}
|
||||
this.$timeout.cancel(this.timeoutHandle);
|
||||
|
||||
if (objects.length > 0){
|
||||
objects.forEach(requestData.bind(this));
|
||||
} else {
|
||||
scope.loading = false;
|
||||
console.log('Resolved promise');
|
||||
resolve([]);
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param objects
|
||||
* @returns {*}
|
||||
*/
|
||||
TelemetryTableController.prototype.subscribeToNewData = function (objects) {
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
//Set table max length to avoid unbounded growth.
|
||||
var maxRows = 100000;
|
||||
|
||||
this.subscriptions.forEach(function (subscription) {
|
||||
subscription();
|
||||
});
|
||||
this.subscriptions = [];
|
||||
|
||||
function newData(domainObject, datum) {
|
||||
this.$scope.rows.push(this.table.getRowValues(
|
||||
telemetryApi.limitEvaluator(domainObject), datum));
|
||||
|
||||
//Inform table that a new row has been added
|
||||
if (this.$scope.rows.length > maxRows) {
|
||||
this.$scope.$broadcast('remove:row', 0);
|
||||
this.$scope.rows.shift();
|
||||
}
|
||||
|
||||
this.$scope.$broadcast('add:row',
|
||||
this.$scope.rows.length - 1);
|
||||
|
||||
}
|
||||
|
||||
objects.forEach(function (object){
|
||||
this.subscriptions.push(
|
||||
telemetryApi.subscribe(object, newData.bind(this, object), {}));
|
||||
console.log('subscribed');
|
||||
}.bind(this));
|
||||
|
||||
return objects;
|
||||
};
|
||||
|
||||
TelemetryTableController.prototype.getData = function () {
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
var compositionApi = this.openmct.composition;
|
||||
var subscriptions = this.subscriptions;
|
||||
var tableConfiguration = this.table;
|
||||
var scope = this.$scope;
|
||||
var maxRows = 100000;
|
||||
var conductor = this.conductor;
|
||||
var newObject = this.newObject;
|
||||
|
||||
this.$scope.loading = true;
|
||||
|
||||
function makeTableRows(object, historicalData){
|
||||
var limitEvaluator = telemetryApi.limitEvaluator(object);
|
||||
return historicalData.map(tableConfiguration.getRowValues.bind(tableConfiguration, limitEvaluator));
|
||||
}
|
||||
|
||||
function requestData(objects) {
|
||||
var bounds = conductor.bounds();
|
||||
|
||||
return Promise.all(
|
||||
objects.map(function (object) {
|
||||
return telemetryApi.request(object, {
|
||||
start: bounds.start,
|
||||
end: bounds.end
|
||||
}).then(
|
||||
makeTableRows.bind(this, object)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function addHistoricalData(historicalData){
|
||||
scope.rows = Array.prototype.concat.apply([], historicalData);
|
||||
scope.loading = false;
|
||||
}
|
||||
|
||||
function newData(domainObject, datum) {
|
||||
scope.rows.push(tableConfiguration.getRowValues(datum, telemetryApi.limitEvaluator(domainObject)));
|
||||
|
||||
//Inform table that a new row has been added
|
||||
if (scope.rows.length > maxRows) {
|
||||
scope.$broadcast('remove:row', 0);
|
||||
scope.rows.shift();
|
||||
}
|
||||
|
||||
scope.$broadcast('add:row',
|
||||
scope.rows.length - 1);
|
||||
|
||||
}
|
||||
|
||||
function subscribe(objects) {
|
||||
objects.forEach(function (object){
|
||||
subscriptions.push(telemetryApi.subscribe(object, newData.bind(this, object), {}));
|
||||
});
|
||||
return objects;
|
||||
}
|
||||
|
||||
function error(e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
function loadColumns(objects) {
|
||||
var metadatas = objects.map(telemetryApi.getMetadata.bind(telemetryApi));
|
||||
var allColumns = telemetryApi.commonValuesForHints(metadatas, []);
|
||||
|
||||
tableConfiguration.populateColumns(allColumns);
|
||||
|
||||
this.timeColumns = telemetryApi.commonValuesForHints(metadatas, ['x']).map(function (metadatum){
|
||||
return metadatum.name;
|
||||
});
|
||||
|
||||
self.filterColumns();
|
||||
|
||||
return Promise.resolve(objects);
|
||||
scope.loading = false;
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
function filterForTelemetry(objects){
|
||||
@ -248,18 +373,10 @@ define(
|
||||
|
||||
getDomainObjects()
|
||||
.then(filterForTelemetry)
|
||||
.then(this.loadColumns)
|
||||
//.then(this.subscribeToNewData)
|
||||
.then(this.getHistoricalData)
|
||||
.catch(error)
|
||||
.then(function (objects){
|
||||
if (objects.length > 0){
|
||||
return loadColumns(objects)
|
||||
.then(subscribe)
|
||||
.then(requestData)
|
||||
.then(addHistoricalData)
|
||||
.catch(error);
|
||||
} else {
|
||||
scope.loading = false;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -77,13 +77,13 @@ define(
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function MCTTable($timeout) {
|
||||
function MCTTable() {
|
||||
return {
|
||||
restrict: "E",
|
||||
template: TableTemplate,
|
||||
controller: [
|
||||
'$scope',
|
||||
'$timeout',
|
||||
'$window',
|
||||
'$element',
|
||||
'exportService',
|
||||
'formatService',
|
||||
@ -104,7 +104,7 @@ define(
|
||||
timeColumns: "=?",
|
||||
// Indicate a column to sort on. Allows control of sort
|
||||
// via configuration (eg. for default sort column).
|
||||
sortColumn: "=?"
|
||||
defaultSort: "=?"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -28,6 +28,18 @@ define([
|
||||
|
||||
// TODO: needs reference to formatService;
|
||||
function TelemetryValueFormatter(valueMetadata, formatService) {
|
||||
var numberFormatter = {
|
||||
parse: function (x) {
|
||||
return Number(x);
|
||||
},
|
||||
format: function (x) {
|
||||
return x;
|
||||
},
|
||||
validate: function (x) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.valueMetadata = valueMetadata;
|
||||
this.parseCache = new WeakMap();
|
||||
this.formatCache = new WeakMap();
|
||||
@ -36,17 +48,7 @@ define([
|
||||
.getFormat(valueMetadata.format, valueMetadata);
|
||||
} catch (e) {
|
||||
// TODO: Better formatting
|
||||
this.formatter = {
|
||||
parse: function (x) {
|
||||
return Number(x);
|
||||
},
|
||||
format: function (x) {
|
||||
return x;
|
||||
},
|
||||
validate: function (x) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
this.formatter = numberFormatter;
|
||||
}
|
||||
|
||||
if (valueMetadata.type === 'enum') {
|
||||
|
Loading…
x
Reference in New Issue
Block a user