blob: 3bb54bd7f0f546bd7388dd5650e7a5b8f8a53011 [file] [log] [blame]
class DashboardPage extends PageWithHeading {
constructor(name, table, toolbar)
{
console.assert(toolbar instanceof DashboardToolbar);
super(name, toolbar);
this._table = table;
this._charts = [];
this._needsTableConstruction = true;
this._needsStatusUpdate = true;
this._statusViews = [];
this._startTime = Date.now() - 60 * 24 * 3600 * 1000;
this._endTime = Date.now();
this._tableGroups = null;
}
routeName() { return `dashboard/${this._name}`; }
serializeState()
{
return {numberOfDays: this.toolbar().numberOfDays()};
}
updateFromSerializedState(state, isOpen)
{
if (!isOpen || state.numberOfDays)
this.toolbar().setNumberOfDays(state.numberOfDays);
var startTime = this.toolbar().startTime();
var endTime = this.toolbar().endTime();
for (var chart of this._charts)
chart.setDomain(startTime, endTime);
this._needsTableConstruction = true;
if (!isOpen)
this.enqueueToRender();
}
open(state)
{
if (!this._tableGroups) {
var columnCount = 0;
var tableGroups = [];
for (var row of this._table) {
if (!row.some(function (cell) { return cell instanceof Array; })) {
tableGroups.push([]);
row = [''].concat(row);
}
tableGroups[tableGroups.length - 1].push(row);
columnCount = Math.max(columnCount, row.length);
}
for (var group of tableGroups) {
for (var row of group) {
for (var i = 0; i < row.length; i++) {
if (row[i] instanceof Array)
row[i] = this._createChartForCell(row[i]);
}
while (row.length < columnCount)
row.push([]);
}
}
this._tableGroups = tableGroups;
}
super.open(state);
}
render()
{
super.render();
console.assert(this._tableGroups);
var element = ComponentBase.createElement;
var link = ComponentBase.createLink;
if (this._needsTableConstruction) {
var tree = [];
var router = this.router();
var startTime = this.toolbar().startTime();
for (var group of this._tableGroups) {
tree.push(element('thead', element('tr',
group[0].map(function (cell, cellIndex) {
if (!cellIndex)
return element('th', {class: 'heading-column'});
return element('td', cell.content || cell);
}))));
tree.push(element('tbody', group.slice(1).map(function (row) {
return element('tr', row.map(function (cell, cellIndex) {
if (!cellIndex)
return element('th', element('span', {class: 'vertical-label'}, cell));
if (!cell.chart)
return element('td', cell);
var url = router.url('charts',
ChartsPage.createStateForDashboardItem(cell.platform.id(), cell.metric.id(), startTime));
return element('td', [cell.statusView, link(cell.chart.element(), cell.label, url)]);
}));
})));
}
this.renderReplace(this.content().querySelector('.dashboard-table'), tree);
this._needsTableConstruction = false;
}
for (var chart of this._charts)
chart.enqueueToRender();
if (this._needsStatusUpdate) {
for (var statusView of this._statusViews)
statusView.enqueueToRender();
this._needsStatusUpdate = false;
}
}
_createChartForCell(cell)
{
console.assert(this.router());
var platformId = cell[0];
var metricId = cell[1];
if (!platformId || !metricId)
return '';
var result = ChartStyles.resolveConfiguration(platformId, metricId);
if (result.error)
return result.error;
var options = ChartStyles.dashboardOptions(result.metric.makeFormatter(3));
let chart = new TimeSeriesChart(ChartStyles.createSourceList(result.platform, result.metric, false, false, true), options);
chart.listenToAction('dataChange', () => this._fetchedData())
this._charts.push(chart);
var statusView = new DashboardChartStatusView(result.metric, chart);
this._statusViews.push(statusView);
return {
chart: chart,
statusView: statusView,
platform: result.platform,
metric: result.metric,
label: result.metric.fullName() + ' on ' + result.platform.label()
};
}
_fetchedData()
{
if (this._needsStatusUpdate)
return;
this._needsStatusUpdate = true;
setTimeout(() => { this.enqueueToRender(); }, 10);
}
static htmlTemplate()
{
return `<section class="page-with-heading"><table class="dashboard-table"></table></section>`;
}
static cssTemplate()
{
return `
.dashboard-table {
table-layout: fixed;
}
.dashboard-table td,
.dashboard-table th {
border: none;
text-align: center;
}
.dashboard-table th,
.dashboard-table thead td {
color: #f96;
font-weight: inherit;
font-size: 1.1rem;
text-align: center;
padding: 0.2rem 0.4rem;
}
.dashboard-table th {
height: 10rem;
width: 2rem;
position: relative;
}
.dashboard-table .heading-column {
width: 2rem;
height: 1rem;
}
.dashboard-table th .vertical-label {
position: absolute;
left: 0;
right: 0;
display: block;
-webkit-transform: rotate(-90deg) translate(-50%, 0);
-webkit-transform-origin: 0 0;
transform: rotate(-90deg) translate(-50%, 0);
transform-origin: 0 0;
width: 10rem;
height: 2rem;
line-height: 1.8rem;
}
table.dashboard-table {
width: 100%;
height: 100%;
border: 0;
}
.dashboard-table td time-series-chart {
height: 10rem;
}
.dashboard-table td > chart-status-view {
display: block;
width: 100%;
}
.dashboard-table td *:first-child {
margin: 0 0 0.2rem 0;
}
`;
}
}