mirror of
https://github.com/nasa/openmct.git
synced 2024-12-21 22:17:49 +00:00
[Tables] Support for subscriptions from new Telemetry API
Historical and real-time data flowing Added formatting, and limits. Support telemetry objects themselves and not just composition of telemetry objects Apply default time range if none supplied (15 minutes)
This commit is contained in:
parent
6d5530ba9c
commit
976333d7f7
@ -75,8 +75,7 @@ define([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "delta",
|
"key": "delta",
|
||||||
"name": "Delta",
|
"name": "Delta"
|
||||||
"format": "example.delta"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"priority": -1
|
"priority": -1
|
||||||
@ -103,11 +102,13 @@ define([
|
|||||||
"domains": [
|
"domains": [
|
||||||
{
|
{
|
||||||
"key": "utc",
|
"key": "utc",
|
||||||
"name": "Time"
|
"name": "Time",
|
||||||
|
"format": "utc"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "yesterday",
|
"key": "yesterday",
|
||||||
"name": "Yesterday"
|
"name": "Yesterday",
|
||||||
|
"format": "utc"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "delta",
|
"key": "delta",
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
|
|
||||||
|
var FIFTEEN_MINUTES = 15 * 60 * 1000;
|
||||||
|
|
||||||
var handlers = {
|
var handlers = {
|
||||||
subscribe: onSubscribe,
|
subscribe: onSubscribe,
|
||||||
@ -82,8 +83,11 @@
|
|||||||
|
|
||||||
function onRequest(message) {
|
function onRequest(message) {
|
||||||
var data = message.data;
|
var data = message.data;
|
||||||
if (!data.start || !data.end) {
|
if (data.end == undefined) {
|
||||||
throw new Error('missing start and end!');
|
data.end = Date.now();
|
||||||
|
}
|
||||||
|
if (data.start == undefined){
|
||||||
|
data.start = data.end - FIFTEEN_MINUTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
@ -22,25 +22,21 @@
|
|||||||
|
|
||||||
define([
|
define([
|
||||||
"./src/directives/MCTTable",
|
"./src/directives/MCTTable",
|
||||||
"./src/controllers/RealtimeTableController",
|
"./src/controllers/TelemetryTableController",
|
||||||
"./src/controllers/HistoricalTableController",
|
|
||||||
"./src/controllers/TableOptionsController",
|
"./src/controllers/TableOptionsController",
|
||||||
'../../commonUI/regions/src/Region',
|
'../../commonUI/regions/src/Region',
|
||||||
'../../commonUI/browse/src/InspectorRegion',
|
'../../commonUI/browse/src/InspectorRegion',
|
||||||
"text!./res/templates/table-options-edit.html",
|
"text!./res/templates/table-options-edit.html",
|
||||||
"text!./res/templates/rt-table.html",
|
"text!./res/templates/telemetry-table.html",
|
||||||
"text!./res/templates/historical-table.html",
|
|
||||||
"legacyRegistry"
|
"legacyRegistry"
|
||||||
], function (
|
], function (
|
||||||
MCTTable,
|
MCTTable,
|
||||||
RealtimeTableController,
|
TelemetryTableController,
|
||||||
HistoricalTableController,
|
|
||||||
TableOptionsController,
|
TableOptionsController,
|
||||||
Region,
|
Region,
|
||||||
InspectorRegion,
|
InspectorRegion,
|
||||||
tableOptionsEditTemplate,
|
tableOptionsEditTemplate,
|
||||||
rtTableTemplate,
|
telemetryTableTemplate,
|
||||||
historicalTableTemplate,
|
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
@ -65,9 +61,9 @@ define([
|
|||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"key": "table",
|
"key": "table",
|
||||||
"name": "Historical Telemetry Table",
|
"name": "Telemetry Table",
|
||||||
"cssclass": "icon-tabular",
|
"cssclass": "icon-tabular-realtime",
|
||||||
"description": "A static table of all values over time for all included telemetry elements. Rows are timestamped data values for each telemetry element; columns are data fields. The number of rows is based on the range of your query. New incoming data must be manually re-queried for.",
|
"description": "A table of values over a given time period. The table will be automatically updated with new values as they become available",
|
||||||
"priority": 861,
|
"priority": 861,
|
||||||
"features": "creation",
|
"features": "creation",
|
||||||
"delegates": [
|
"delegates": [
|
||||||
@ -85,42 +81,13 @@ define([
|
|||||||
"views": [
|
"views": [
|
||||||
"table"
|
"table"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "rttable",
|
|
||||||
"name": "Real-time Telemetry Table",
|
|
||||||
"cssclass": "icon-tabular-realtime",
|
|
||||||
"description": "A scrolling table of latest values for all included telemetry elements. Rows are timestamped data values for each telemetry element; columns are data fields. New incoming data is automatically added to the view.",
|
|
||||||
"priority": 860,
|
|
||||||
"features": "creation",
|
|
||||||
"delegates": [
|
|
||||||
"telemetry"
|
|
||||||
],
|
|
||||||
"inspector": tableInspector,
|
|
||||||
"contains": [
|
|
||||||
{
|
|
||||||
"has": "telemetry"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"model": {
|
|
||||||
"composition": []
|
|
||||||
},
|
|
||||||
"views": [
|
|
||||||
"rt-table",
|
|
||||||
"scrolling-table"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"controllers": [
|
"controllers": [
|
||||||
{
|
{
|
||||||
"key": "HistoricalTableController",
|
"key": "TelemetryTableController",
|
||||||
"implementation": HistoricalTableController,
|
"implementation": TelemetryTableController,
|
||||||
"depends": ["$scope", "telemetryHandler", "telemetryFormatter", "$timeout", "openmct"]
|
"depends": ["$scope", "openmct"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "RealtimeTableController",
|
|
||||||
"implementation": RealtimeTableController,
|
|
||||||
"depends": ["$scope", "telemetryHandler", "telemetryFormatter", "openmct"]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "TableOptionsController",
|
"key": "TableOptionsController",
|
||||||
@ -131,21 +98,10 @@ define([
|
|||||||
],
|
],
|
||||||
"views": [
|
"views": [
|
||||||
{
|
{
|
||||||
"name": "Historical Table",
|
"name": "Telemetry Table",
|
||||||
"key": "table",
|
"key": "table",
|
||||||
"template": historicalTableTemplate,
|
|
||||||
"cssclass": "icon-tabular",
|
|
||||||
"needs": [
|
|
||||||
"telemetry"
|
|
||||||
],
|
|
||||||
"delegation": true,
|
|
||||||
"editable": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Real-time Table",
|
|
||||||
"key": "rt-table",
|
|
||||||
"cssclass": "icon-tabular-realtime",
|
"cssclass": "icon-tabular-realtime",
|
||||||
"template": rtTableTemplate,
|
"template": telemetryTableTemplate,
|
||||||
"needs": [
|
"needs": [
|
||||||
"telemetry"
|
"telemetry"
|
||||||
],
|
],
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<div ng-controller="RealtimeTableController as tableController">
|
|
||||||
<mct-table
|
|
||||||
headers="headers"
|
|
||||||
rows="rows"
|
|
||||||
time-columns="tableController.timeColumns"
|
|
||||||
enableFilter="true"
|
|
||||||
enableSort="true"
|
|
||||||
class="tabular-holder has-control-bar"
|
|
||||||
sort-column="defaultSort"
|
|
||||||
auto-scroll="true">
|
|
||||||
</mct-table>
|
|
||||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||||||
<div ng-controller="HistoricalTableController as tableController"
|
<div ng-controller="TelemetryTableController as tableController"
|
||||||
ng-class="{'loading': loading}">
|
ng-class="{'loading': loading}">
|
||||||
<mct-table
|
<mct-table
|
||||||
headers="headers"
|
headers="headers"
|
@ -1,62 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2016, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining DomainColumn.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,52 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2016, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining NameColumn. Created by vwoeltje on 11/18/14.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,65 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2016, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining DomainColumn. Created by vwoeltje on 11/18/14.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -21,12 +21,8 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
[
|
[],
|
||||||
'./DomainColumn',
|
function () {
|
||||||
'./RangeColumn',
|
|
||||||
'./NameColumn'
|
|
||||||
],
|
|
||||||
function (DomainColumn, RangeColumn, NameColumn) {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that manages table metadata, state, and contents.
|
* Class that manages table metadata, state, and contents.
|
||||||
@ -34,10 +30,10 @@ define(
|
|||||||
* @param domainObject
|
* @param domainObject
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function TableConfiguration(domainObject, telemetryFormatter) {
|
function TableConfiguration(domainObject, openmct) {
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
this.columns = [];
|
this.columns = [];
|
||||||
this.telemetryFormatter = telemetryFormatter;
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,26 +43,33 @@ define(
|
|||||||
*/
|
*/
|
||||||
TableConfiguration.prototype.populateColumns = function (metadata) {
|
TableConfiguration.prototype.populateColumns = function (metadata) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var telemetryApi = this.openmct.telemetry;
|
||||||
|
|
||||||
this.columns = [];
|
this.columns = [];
|
||||||
|
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
|
|
||||||
metadata.forEach(function (metadatum) {
|
metadata.forEach(function (metadatum) {
|
||||||
//Push domains first
|
var formatter = telemetryApi.getValueFormatter(metadatum);
|
||||||
(metadatum.domains || []).forEach(function (domainMetadata) {
|
|
||||||
self.addColumn(new DomainColumn(domainMetadata,
|
self.addColumn({
|
||||||
self.telemetryFormatter));
|
getTitle: function () {
|
||||||
});
|
return metadatum.name;
|
||||||
(metadatum.ranges || []).forEach(function (rangeMetadata) {
|
},
|
||||||
self.addColumn(new RangeColumn(rangeMetadata,
|
getValue: function(telemetryDatum, limitEvaluator) {
|
||||||
self.telemetryFormatter));
|
var isValueColumn = !!(metadatum.hints.y || metadatum.hints.range);
|
||||||
|
var alarm = isValueColumn &&
|
||||||
|
limitEvaluator &&
|
||||||
|
limitEvaluator.evaluate(telemetryDatum, metadatum);
|
||||||
|
|
||||||
|
return {
|
||||||
|
cssClass: alarm && alarm.cssClass,
|
||||||
|
text: formatter ? formatter.format(telemetryDatum[metadatum.key])
|
||||||
|
: telemetryDatum[metadatum.key]
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.columns.length > 0) {
|
|
||||||
self.addColumn(new NameColumn(), 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@ -99,9 +102,8 @@ define(
|
|||||||
* @returns {Array} The titles of the columns
|
* @returns {Array} The titles of the columns
|
||||||
*/
|
*/
|
||||||
TableConfiguration.prototype.getHeaders = function () {
|
TableConfiguration.prototype.getHeaders = function () {
|
||||||
var self = this;
|
|
||||||
return this.columns.map(function (column, i) {
|
return this.columns.map(function (column, i) {
|
||||||
return self.getColumnTitle(column) || 'Column ' + (i + 1);
|
return column.getTitle()|| 'Column ' + (i + 1);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -113,11 +115,11 @@ define(
|
|||||||
* @returns {Object} Key value pairs where the key is the column
|
* @returns {Object} Key value pairs where the key is the column
|
||||||
* title, and the value is the formatted value from the provided datum.
|
* title, and the value is the formatted value from the provided datum.
|
||||||
*/
|
*/
|
||||||
TableConfiguration.prototype.getRowValues = function (telemetryObject, datum) {
|
TableConfiguration.prototype.getRowValues = function (limitEvaluator, datum) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.columns.reduce(function (rowObject, column, i) {
|
return this.columns.reduce(function (rowObject, column, i) {
|
||||||
var columnTitle = self.getColumnTitle(column) || 'Column ' + (i + 1),
|
var columnTitle = self.getColumnTitle(column) || 'Column ' + (i + 1),
|
||||||
columnValue = column.getValue(telemetryObject, datum);
|
columnValue = column.getValue(datum, limitEvaluator);
|
||||||
|
|
||||||
if (columnValue !== undefined && columnValue.text === undefined) {
|
if (columnValue !== undefined && columnValue.text === undefined) {
|
||||||
columnValue.text = '';
|
columnValue.text = '';
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2016, 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(
|
|
||||||
[
|
|
||||||
'./TelemetryTableController'
|
|
||||||
],
|
|
||||||
function (TableController) {
|
|
||||||
var BATCH_SIZE = 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends TelemetryTableController and adds real-time streaming
|
|
||||||
* support.
|
|
||||||
* @memberof platform/features/table
|
|
||||||
* @param $scope
|
|
||||||
* @param telemetryHandler
|
|
||||||
* @param telemetryFormatter
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function HistoricalTableController($scope, telemetryHandler, telemetryFormatter, $timeout, openmct) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.$timeout = $timeout;
|
|
||||||
this.timeoutHandle = undefined;
|
|
||||||
this.batchSize = BATCH_SIZE;
|
|
||||||
|
|
||||||
$scope.$on("$destroy", function () {
|
|
||||||
if (self.timeoutHandle) {
|
|
||||||
self.$timeout.cancel(self.timeoutHandle);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
TableController.call(this, $scope, telemetryHandler, telemetryFormatter, openmct);
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoricalTableController.prototype = Object.create(TableController.prototype);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set provided row data on scope, and cancel loading spinner
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
HistoricalTableController.prototype.doneProcessing = function (rowData) {
|
|
||||||
this.$scope.rows = rowData;
|
|
||||||
this.$scope.loading = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
HistoricalTableController.prototype.registerChangeListeners = function () {
|
|
||||||
TableController.prototype.registerChangeListeners.call(this);
|
|
||||||
//Change of bounds in time conductor
|
|
||||||
this.changeListeners.push(this.$scope.$on('telemetry:display:bounds',
|
|
||||||
this.boundsChange.bind(this))
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
HistoricalTableController.prototype.boundsChange = function (event, bounds, follow) {
|
|
||||||
// If in follow mode, don't bother re-subscribing, data will be
|
|
||||||
// received from existing subscription.
|
|
||||||
if (follow !== true) {
|
|
||||||
this.subscribe();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes an array of objects, formatting the telemetry available
|
|
||||||
* for them and setting it on scope when done
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
HistoricalTableController.prototype.processTelemetryObjects = function (objects, offset, start, rowData) {
|
|
||||||
var telemetryObject = objects[offset],
|
|
||||||
series,
|
|
||||||
i = start,
|
|
||||||
pointCount,
|
|
||||||
end;
|
|
||||||
|
|
||||||
//No more objects to process
|
|
||||||
if (!telemetryObject) {
|
|
||||||
return this.doneProcessing(rowData);
|
|
||||||
}
|
|
||||||
|
|
||||||
series = this.handle.getSeries(telemetryObject);
|
|
||||||
|
|
||||||
pointCount = series.getPointCount();
|
|
||||||
end = Math.min(start + this.batchSize, pointCount);
|
|
||||||
|
|
||||||
//Process rows in a batch with size not exceeding a maximum length
|
|
||||||
for (; i < end; i++) {
|
|
||||||
rowData.push(this.table.getRowValues(telemetryObject,
|
|
||||||
this.handle.makeDatum(telemetryObject, series, i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Done processing all rows for this object.
|
|
||||||
if (end >= pointCount) {
|
|
||||||
offset++;
|
|
||||||
end = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done processing either a batch or an object, yield process
|
|
||||||
// before continuing processing
|
|
||||||
this.timeoutHandle = this.$timeout(this.processTelemetryObjects.bind(this, objects, offset, end, rowData));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populates historical data on scope when it becomes available from
|
|
||||||
* the telemetry API
|
|
||||||
*/
|
|
||||||
HistoricalTableController.prototype.addHistoricalData = function () {
|
|
||||||
if (this.timeoutHandle) {
|
|
||||||
this.$timeout.cancel(this.timeoutHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.timeoutHandle = this.$timeout(this.processTelemetryObjects.bind(this, this.handle.getTelemetryObjects(), 0, 0, []));
|
|
||||||
};
|
|
||||||
|
|
||||||
return HistoricalTableController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,76 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2016, 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(
|
|
||||||
[
|
|
||||||
'./TelemetryTableController'
|
|
||||||
],
|
|
||||||
function (TableController) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends TelemetryTableController and adds real-time streaming
|
|
||||||
* support.
|
|
||||||
* @memberof platform/features/table
|
|
||||||
* @param $scope
|
|
||||||
* @param telemetryHandler
|
|
||||||
* @param telemetryFormatter
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function RealtimeTableController($scope, telemetryHandler, telemetryFormatter, openmct) {
|
|
||||||
TableController.call(this, $scope, telemetryHandler, telemetryFormatter, openmct);
|
|
||||||
|
|
||||||
this.maxRows = 100000;
|
|
||||||
}
|
|
||||||
|
|
||||||
RealtimeTableController.prototype = Object.create(TableController.prototype);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides method on TelemetryTableController providing handling
|
|
||||||
* for realtime data.
|
|
||||||
*/
|
|
||||||
RealtimeTableController.prototype.addRealtimeData = function () {
|
|
||||||
var self = this,
|
|
||||||
datum,
|
|
||||||
row;
|
|
||||||
this.handle.getTelemetryObjects().forEach(function (telemetryObject) {
|
|
||||||
datum = self.handle.getDatum(telemetryObject);
|
|
||||||
if (datum) {
|
|
||||||
//Populate row values from telemetry datum
|
|
||||||
row = self.table.getRowValues(telemetryObject, datum);
|
|
||||||
self.$scope.rows.push(row);
|
|
||||||
|
|
||||||
//Inform table that a new row has been added
|
|
||||||
if (self.$scope.rows.length > self.maxRows) {
|
|
||||||
self.$scope.$broadcast('remove:row', 0);
|
|
||||||
self.$scope.rows.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.$scope.$broadcast('add:row',
|
|
||||||
self.$scope.rows.length - 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.$scope.loading = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
return RealtimeTableController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -38,14 +38,10 @@ define(
|
|||||||
* configuration, and telemetry subscriptions.
|
* configuration, and telemetry subscriptions.
|
||||||
* @memberof platform/features/table
|
* @memberof platform/features/table
|
||||||
* @param $scope
|
* @param $scope
|
||||||
* @param telemetryHandler
|
|
||||||
* @param telemetryFormatter
|
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function TelemetryTableController(
|
function TelemetryTableController(
|
||||||
$scope,
|
$scope,
|
||||||
telemetryHandler,
|
|
||||||
telemetryFormatter,
|
|
||||||
openmct
|
openmct
|
||||||
) {
|
) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -53,9 +49,8 @@ define(
|
|||||||
this.$scope = $scope;
|
this.$scope = $scope;
|
||||||
this.columns = {}; //Range and Domain columns
|
this.columns = {}; //Range and Domain columns
|
||||||
this.handle = undefined;
|
this.handle = undefined;
|
||||||
this.telemetryHandler = telemetryHandler;
|
|
||||||
this.table = new TableConfiguration($scope.domainObject,
|
this.table = new TableConfiguration($scope.domainObject,
|
||||||
telemetryFormatter);
|
openmct);
|
||||||
this.changeListeners = [];
|
this.changeListeners = [];
|
||||||
this.conductor = openmct.conductor;
|
this.conductor = openmct.conductor;
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
@ -68,6 +63,9 @@ define(
|
|||||||
self.subscribe();
|
self.subscribe();
|
||||||
self.registerChangeListeners();
|
self.registerChangeListeners();
|
||||||
});
|
});
|
||||||
|
this.mutationListener = openmct.objects.observe(this.newObject, "*", function (domainObject){
|
||||||
|
self.newObject = domainObject;
|
||||||
|
});
|
||||||
|
|
||||||
this.destroy = this.destroy.bind(this);
|
this.destroy = this.destroy.bind(this);
|
||||||
|
|
||||||
@ -79,6 +77,8 @@ define(
|
|||||||
this.sortByTimeSystem = this.sortByTimeSystem.bind(this);
|
this.sortByTimeSystem = this.sortByTimeSystem.bind(this);
|
||||||
this.conductor.on('timeSystem', this.sortByTimeSystem);
|
this.conductor.on('timeSystem', this.sortByTimeSystem);
|
||||||
this.conductor.off('timeSystem', this.sortByTimeSystem);
|
this.conductor.off('timeSystem', this.sortByTimeSystem);
|
||||||
|
|
||||||
|
this.subscriptions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,29 +130,12 @@ define(
|
|||||||
* Release the current subscription (called when scope is destroyed)
|
* Release the current subscription (called when scope is destroyed)
|
||||||
*/
|
*/
|
||||||
TelemetryTableController.prototype.destroy = function () {
|
TelemetryTableController.prototype.destroy = function () {
|
||||||
if (this.handle) {
|
this.subscriptions.forEach(function (subscription) {
|
||||||
this.handle.unsubscribe();
|
subscription()
|
||||||
this.handle = undefined;
|
});
|
||||||
}
|
this.mutationListener();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for handling realtime data when it is available. This
|
|
||||||
* will be called by the telemetry framework when new data is
|
|
||||||
* available.
|
|
||||||
*
|
|
||||||
* Method should be overridden by specializing class.
|
|
||||||
*/
|
|
||||||
TelemetryTableController.prototype.addRealtimeData = function () {
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for handling historical data. Will be called by
|
|
||||||
* telemetry framework when requested historical data is available.
|
|
||||||
* Should be overridden by specializing class.
|
|
||||||
*/
|
|
||||||
TelemetryTableController.prototype.addHistoricalData = function () {
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a new subscription. This can be overridden by children to
|
Create a new subscription. This can be overridden by children to
|
||||||
@ -160,94 +143,123 @@ define(
|
|||||||
only).
|
only).
|
||||||
*/
|
*/
|
||||||
TelemetryTableController.prototype.subscribe = function () {
|
TelemetryTableController.prototype.subscribe = function () {
|
||||||
|
var self = this;
|
||||||
var telemetryApi = this.openmct.telemetry;
|
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;
|
||||||
|
|
||||||
if (this.handle) {
|
|
||||||
this.handle.unsubscribe();
|
|
||||||
}
|
|
||||||
this.$scope.loading = true;
|
this.$scope.loading = true;
|
||||||
|
|
||||||
function map(func){
|
function makeTableRows(object, historicalData){
|
||||||
return function (objects) {
|
var limitEvaluator = telemetryApi.limitEvaluator(object);
|
||||||
return Promise.all(objects.map(func));
|
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 add(object){
|
function subscribe(objects) {
|
||||||
return function (objects) {
|
objects.forEach(function (object){
|
||||||
objects.unshift(object);
|
subscriptions.push(telemetryApi.subscribe(object, newData.bind(this, object), {}));
|
||||||
return objects;
|
});
|
||||||
}
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
function subscribeTo(object) {
|
function error(e) {
|
||||||
return telemetryApi.request(object, {});
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
function error() {
|
function loadColumns(objects) {
|
||||||
console.log("Unable to subscribe");
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.openmct.composition.get(this.newObject)
|
function filterForTelemetry(objects){
|
||||||
.load()
|
return objects.filter(telemetryApi.canProvideTelemetry.bind(telemetryApi));
|
||||||
.then(add(this.newObject))
|
|
||||||
.then(map(subscribeTo))
|
|
||||||
.then(function (telemetry) {
|
|
||||||
console.log(telemetry.length);
|
|
||||||
}).catch(error);
|
|
||||||
|
|
||||||
this.handle = this.$scope.domainObject && this.telemetryHandler.handle(
|
|
||||||
this.$scope.domainObject,
|
|
||||||
this.addRealtimeData.bind(this),
|
|
||||||
true // Lossless
|
|
||||||
);
|
|
||||||
|
|
||||||
this.handle.request({}).then(this.addHistoricalData.bind(this));
|
|
||||||
|
|
||||||
this.setup();
|
|
||||||
};
|
|
||||||
|
|
||||||
TelemetryTableController.prototype.populateColumns = function (telemetryMetadata) {
|
|
||||||
this.table.populateColumns(telemetryMetadata);
|
|
||||||
|
|
||||||
//Identify time columns
|
|
||||||
telemetryMetadata.forEach(function (metadatum) {
|
|
||||||
//Push domains first
|
|
||||||
(metadatum.domains || []).forEach(function (domainMetadata) {
|
|
||||||
this.timeColumns.push(domainMetadata.name);
|
|
||||||
}.bind(this));
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
var timeSystem = this.conductor.timeSystem();
|
|
||||||
if (timeSystem) {
|
|
||||||
this.sortByTimeSystem(timeSystem);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
function getDomainObjects() {
|
||||||
* Setup table columns based on domain object metadata
|
return new Promise(function (resolve, reject){
|
||||||
*/
|
var objects = [newObject];
|
||||||
TelemetryTableController.prototype.setup = function () {
|
var composition = compositionApi.get(newObject);
|
||||||
var handle = this.handle,
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
if (handle) {
|
if (composition) {
|
||||||
this.timeColumns = [];
|
composition
|
||||||
handle.promiseTelemetryObjects().then(function () {
|
.load()
|
||||||
self.$scope.headers = [];
|
.then(function (children) {
|
||||||
self.$scope.rows = [];
|
return objects.concat(children);
|
||||||
|
})
|
||||||
self.populateColumns(handle.getMetadata());
|
.then(resolve)
|
||||||
self.filterColumns();
|
.catch(reject);
|
||||||
|
} else {
|
||||||
// When table column configuration changes, (due to being
|
return resolve(objects);
|
||||||
// selected or deselected), filter columns appropriately.
|
}
|
||||||
self.changeListeners.push(self.$scope.$watchCollection(
|
|
||||||
'domainObject.getModel().configuration.table.columns',
|
|
||||||
self.filterColumns.bind(self)
|
|
||||||
));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.headers = [];
|
||||||
|
scope.rows = [];
|
||||||
|
|
||||||
|
getDomainObjects()
|
||||||
|
.then(filterForTelemetry)
|
||||||
|
.catch(error)
|
||||||
|
.then(function (objects){
|
||||||
|
if (objects.length > 0){
|
||||||
|
return loadColumns(objects)
|
||||||
|
.then(subscribe)
|
||||||
|
.then(requestData)
|
||||||
|
.then(addHistoricalData)
|
||||||
|
.catch(error);
|
||||||
|
} else {
|
||||||
|
scope.loading = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user