Skip to content
This repository was archived by the owner on Mar 4, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 17 additions & 31 deletions lib/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

var _ = require("lodash");
var blessed = require("blessed");

var HelpView = require("./views/help");
var generateLayouts = require("./generate-layouts");
var LogProvider = require("./providers/log-provider");
Expand All @@ -14,7 +13,7 @@ var THROTTLE_TIMEOUT = 150;

var Dashboard = function Dashboard(options) {
this.options = options || {};
this.views = {};
this.settings = this.options.settings;

this.screen = blessed.screen({
smartCSR: true,
Expand All @@ -30,22 +29,20 @@ var Dashboard = function Dashboard(options) {
};

Dashboard.prototype._createViews = function () {
this.layouts = generateLayouts(this.options.layoutsFile, this.options.settings);
this.views = [];
this.layouts = generateLayouts(this.options.layoutsFile);

// container prevents stream view scrolling from interfering with side views
this.container = blessed.box();
this.screen.append(this.container);

this.helpView = new HelpView({
parent: this.container
});

this.gotoTimeView = new GotoTimeView({
metricsProvider: this.metricsProvider,
this.viewOptions = {
screen: this.screen,
parent: this.container,
screen: this.screen
});
logProvider: this.logProvider,
metricsProvider: this.metricsProvider
};

this.helpView = new HelpView(this.viewOptions);
this.gotoTimeView = new GotoTimeView(this.viewOptions);

this._showLayout(0);
};
Expand Down Expand Up @@ -125,26 +122,15 @@ Dashboard.prototype._showLayout = function (id) {
if (this.currentLayout === id) {
return;
}
_.each(this.views, function (view) {
view.destroy();
});

this.views = [];

_.each(this.layouts[id], function (layoutConfig) {
var View = views.getConstructor(layoutConfig.view);

if (View) {
var view = new View({
parent: this.container,
logProvider: this.logProvider,
metricsProvider: this.metricsProvider,
layoutConfig: layoutConfig
});
// Remove current layout
if (this.panel) {
this.panel.destroy();
delete this.panel;
}

this.views.push(view);
}
}.bind(this));
// create new layout
this.panel = views.create(this.layouts[id], this.viewOptions, this.settings);

this.currentLayout = id;
this.helpView.node.setFront();
Expand Down
42 changes: 42 additions & 0 deletions lib/default-layout-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,47 @@ module.exports = [
}
]
}
],
[
{
views: [
{
position: {
grow: 2
},
type: "panel",
views: [
{
type: "panel",
views: [
{
type: "nodeDetails"
},
{
type: "systemDetails"
}
]
},
{
type: "panel",
views: [
{
type: "cpuDetails"
},
{
type: "userDetails"
}
]
}
]
},
{
position: {
grow: 5
},
type: "envDetails"
}
]
}
]
];
130 changes: 10 additions & 120 deletions lib/generate-layouts.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,108 +7,7 @@ var defaultLayoutConfig = require("./default-layout-config");
var validate = require("jsonschema").validate;
var layoutConfigSchema = require("./layout-config-schema.json");

// Each layout consists of vertical panels, that contains its position and horizontal views.
// Flex-like positions of panels and views defined by 'grow' and 'size' parameters.
// View or panel with 'size' has exactly <size> height or width respectively.
// View or panel with 'grow' fills <grow> part of the residuary space (it works like flex-grow).
// By default, position = { grow: 1 }

var normalizePosition = function (position) {
if (!_.has(position, "grow") && !_.has(position, "size")) {
position = { grow: 1 };
}

return position;
};

var concatPosition = function (position1, position2) {
position1 = normalizePosition(position1);
position2 = normalizePosition(position2);

return {
grow: (position1.grow || 0) + (position2.grow || 0),
size: (position1.size || 0) + (position2.size || 0)
};
};

var getSummaryPosition = function (items) {
return items.map(function (item) { return item.position; })
.reduce(concatPosition, { grow: 0, size: 0 });
};

var getSize = function (parentSize, itemPosition) {
var position = normalizePosition(itemPosition.position);
if (_.has(position, "size")) {
return position.size;
}

// Prevent last growing view from overflowing screen
var round = itemPosition.offset.grow + position.grow === itemPosition.summary.grow ?
Math.floor : Math.ceil;

return round(
(parentSize - itemPosition.summary.size) * position.grow / itemPosition.summary.grow
);
};

var getOffset = function (parentSize, itemPosition) {
return itemPosition.summary.grow ? Math.ceil(
itemPosition.offset.size +
(parentSize - itemPosition.summary.size) * itemPosition.offset.grow / itemPosition.summary.grow
) : 0;
};

var createViewLayout = function (view, viewPosition, panelPosition) {
return {
view: view,
getPosition: function (parent) {
return {
width: getSize(parent.width, panelPosition),
height: getSize(parent.height, viewPosition),
left: getOffset(parent.width, panelPosition),
top: getOffset(parent.height, viewPosition)
};
}
};
};

var createPanelLayout = function (panelPosition, views) {
var viewSummaryPosition = getSummaryPosition(views);
var offsetPosition = { size: 0, grow: 0 };

return views.map(function (view) {
var viewPosition = {
summary: viewSummaryPosition,
offset: offsetPosition,
position: view.position
};

offsetPosition = concatPosition(view.position, offsetPosition);

return createViewLayout(view, viewPosition, panelPosition);
});
};

var createLayout = function (panelsConfig) {
var panelSummaryPosition = getSummaryPosition(panelsConfig);
var offsetPosition = { size: 0, grow: 0 };

return panelsConfig.reduce(function (layouts, panelConfig) {
var panelPosition = {
summary: panelSummaryPosition,
offset: offsetPosition,
position: panelConfig.position
};

var viewLayouts = createPanelLayout(panelPosition, panelConfig.views);

offsetPosition = concatPosition(panelConfig.position, offsetPosition);

return layouts.concat(viewLayouts);
}, []);
};

var loadConfigs = function (layoutsFile) {
module.exports = function generateLayouts(layoutsFile) {
var layoutConfig = defaultLayoutConfig;
if (layoutsFile) {
/* eslint-disable global-require */
Expand All @@ -124,23 +23,14 @@ var loadConfigs = function (layoutsFile) {
"Layout config is invalid:\n\n * " + validationResult.errors.join("\n * ") + "\n"
);
}
return layoutConfig;
};

var applyCustomizations = function (customizations) {
return function (panelsConfig) {
return panelsConfig.map(function (view) {
var customization = customizations[view.type];
if (!customization) {
return view;
}
return _.merge(view, { view: customization });
});
};
};

module.exports = function generateLayouts(layoutsFile, customizations) {
return loadConfigs(layoutsFile)
.map(applyCustomizations(customizations || {}))
.map(createLayout);
return layoutConfig.map(function (layouts) {
return {
view: {
type: "panel",
views: layouts.map(function (config) { return _.merge(config, { type: "panel" }); })
},
getPosition: _.identity
};
});
};
2 changes: 2 additions & 0 deletions lib/layout-config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"type": "array",
"items": {
"oneOf": [{
"$ref": "#/definitions/panel"
}, {
"$ref": "#/definitions/streamView"
}, {
"$ref": "#/definitions/memoryView"
Expand Down
35 changes: 32 additions & 3 deletions lib/views/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";

var _ = require("lodash");
var StreamView = require("./stream-view");
var EventLoopView = require("./eventloop-view");
var MemoryGaugeView = require("./memory-gauge-view");
Expand All @@ -11,6 +12,7 @@ var EnvDetailsView = require("./env-details-view");
var NodeDetailsView = require("./node-details-view");
var SystemDetailsView = require("./system-details-view");
var UserDetailsView = require("./user-details-view");
var Panel = require("./panel");

var VIEW_MAP = {
cpuDetails: CpuDetailsView,
Expand All @@ -22,7 +24,17 @@ var VIEW_MAP = {
cpu: CpuView,
memory: MemoryGaugeView,
memoryGraph: MemoryGraphView,
eventLoop: EventLoopView
eventLoop: EventLoopView,
panel: Panel
};

// Customize view types based on a settings class
var applyCustomizations = function (customizations, layoutConfig) {
var customization = customizations[layoutConfig.view.type];
if (!customization) {
return layoutConfig;
}
return _.merge(layoutConfig, { view: customization });
};

var getConstructor = function (options) {
Expand All @@ -36,6 +48,23 @@ var getConstructor = function (options) {
return null;
};

module.exports = {
getConstructor: getConstructor
/**
* Creates a view
*
* @param {Object} layoutConfig raw layout { type, views, position }
* @param {Object} options startup options for views
* @param {Object} customizations view type customiztaions
*
* @returns {Object} created view oject
*/
module.exports.create = function create(layoutConfig, options, customizations) {
var customized = applyCustomizations(customizations, layoutConfig);
var viewOptions = Object.assign({}, options, {
layoutConfig: customized,
creator: function (layout) {
return create(layout, options, customizations);
}
});
var View = getConstructor(customized.view);
return View ? new View(viewOptions) : null;
};
Loading