Skip to content
This repository was archived by the owner on Mar 4, 2022. It is now read-only.

Commit 74ab60f

Browse files
authored
Merge pull request #87 from jjasonclark/panel_class
Support layouts in layouts
2 parents dfeaec1 + a08165b commit 74ab60f

File tree

8 files changed

+510
-397
lines changed

8 files changed

+510
-397
lines changed

lib/dashboard.js

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
var _ = require("lodash");
44
var blessed = require("blessed");
5-
65
var HelpView = require("./views/help");
76
var generateLayouts = require("./generate-layouts");
87
var LogProvider = require("./providers/log-provider");
@@ -14,7 +13,7 @@ var THROTTLE_TIMEOUT = 150;
1413

1514
var Dashboard = function Dashboard(options) {
1615
this.options = options || {};
17-
this.views = {};
16+
this.settings = this.options.settings;
1817

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

3231
Dashboard.prototype._createViews = function () {
33-
this.layouts = generateLayouts(this.options.layoutsFile, this.options.settings);
34-
this.views = [];
32+
this.layouts = generateLayouts(this.options.layoutsFile);
3533

3634
// container prevents stream view scrolling from interfering with side views
3735
this.container = blessed.box();
3836
this.screen.append(this.container);
39-
40-
this.helpView = new HelpView({
41-
parent: this.container
42-
});
43-
44-
this.gotoTimeView = new GotoTimeView({
45-
metricsProvider: this.metricsProvider,
37+
this.viewOptions = {
38+
screen: this.screen,
4639
parent: this.container,
47-
screen: this.screen
48-
});
40+
logProvider: this.logProvider,
41+
metricsProvider: this.metricsProvider
42+
};
43+
44+
this.helpView = new HelpView(this.viewOptions);
45+
this.gotoTimeView = new GotoTimeView(this.viewOptions);
4946

5047
this._showLayout(0);
5148
};
@@ -125,26 +122,15 @@ Dashboard.prototype._showLayout = function (id) {
125122
if (this.currentLayout === id) {
126123
return;
127124
}
128-
_.each(this.views, function (view) {
129-
view.destroy();
130-
});
131-
132-
this.views = [];
133-
134-
_.each(this.layouts[id], function (layoutConfig) {
135-
var View = views.getConstructor(layoutConfig.view);
136125

137-
if (View) {
138-
var view = new View({
139-
parent: this.container,
140-
logProvider: this.logProvider,
141-
metricsProvider: this.metricsProvider,
142-
layoutConfig: layoutConfig
143-
});
126+
// Remove current layout
127+
if (this.panel) {
128+
this.panel.destroy();
129+
delete this.panel;
130+
}
144131

145-
this.views.push(view);
146-
}
147-
}.bind(this));
132+
// create new layout
133+
this.panel = views.create(this.layouts[id], this.viewOptions, this.settings);
148134

149135
this.currentLayout = id;
150136
this.helpView.node.setFront();

lib/default-layout-config.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,47 @@ module.exports = [
120120
}
121121
]
122122
}
123+
],
124+
[
125+
{
126+
views: [
127+
{
128+
position: {
129+
grow: 2
130+
},
131+
type: "panel",
132+
views: [
133+
{
134+
type: "panel",
135+
views: [
136+
{
137+
type: "nodeDetails"
138+
},
139+
{
140+
type: "systemDetails"
141+
}
142+
]
143+
},
144+
{
145+
type: "panel",
146+
views: [
147+
{
148+
type: "cpuDetails"
149+
},
150+
{
151+
type: "userDetails"
152+
}
153+
]
154+
}
155+
]
156+
},
157+
{
158+
position: {
159+
grow: 5
160+
},
161+
type: "envDetails"
162+
}
163+
]
164+
}
123165
]
124166
];

lib/generate-layouts.js

Lines changed: 10 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -7,108 +7,7 @@ var defaultLayoutConfig = require("./default-layout-config");
77
var validate = require("jsonschema").validate;
88
var layoutConfigSchema = require("./layout-config-schema.json");
99

10-
// Each layout consists of vertical panels, that contains its position and horizontal views.
11-
// Flex-like positions of panels and views defined by 'grow' and 'size' parameters.
12-
// View or panel with 'size' has exactly <size> height or width respectively.
13-
// View or panel with 'grow' fills <grow> part of the residuary space (it works like flex-grow).
14-
// By default, position = { grow: 1 }
15-
16-
var normalizePosition = function (position) {
17-
if (!_.has(position, "grow") && !_.has(position, "size")) {
18-
position = { grow: 1 };
19-
}
20-
21-
return position;
22-
};
23-
24-
var concatPosition = function (position1, position2) {
25-
position1 = normalizePosition(position1);
26-
position2 = normalizePosition(position2);
27-
28-
return {
29-
grow: (position1.grow || 0) + (position2.grow || 0),
30-
size: (position1.size || 0) + (position2.size || 0)
31-
};
32-
};
33-
34-
var getSummaryPosition = function (items) {
35-
return items.map(function (item) { return item.position; })
36-
.reduce(concatPosition, { grow: 0, size: 0 });
37-
};
38-
39-
var getSize = function (parentSize, itemPosition) {
40-
var position = normalizePosition(itemPosition.position);
41-
if (_.has(position, "size")) {
42-
return position.size;
43-
}
44-
45-
// Prevent last growing view from overflowing screen
46-
var round = itemPosition.offset.grow + position.grow === itemPosition.summary.grow ?
47-
Math.floor : Math.ceil;
48-
49-
return round(
50-
(parentSize - itemPosition.summary.size) * position.grow / itemPosition.summary.grow
51-
);
52-
};
53-
54-
var getOffset = function (parentSize, itemPosition) {
55-
return itemPosition.summary.grow ? Math.ceil(
56-
itemPosition.offset.size +
57-
(parentSize - itemPosition.summary.size) * itemPosition.offset.grow / itemPosition.summary.grow
58-
) : 0;
59-
};
60-
61-
var createViewLayout = function (view, viewPosition, panelPosition) {
62-
return {
63-
view: view,
64-
getPosition: function (parent) {
65-
return {
66-
width: getSize(parent.width, panelPosition),
67-
height: getSize(parent.height, viewPosition),
68-
left: getOffset(parent.width, panelPosition),
69-
top: getOffset(parent.height, viewPosition)
70-
};
71-
}
72-
};
73-
};
74-
75-
var createPanelLayout = function (panelPosition, views) {
76-
var viewSummaryPosition = getSummaryPosition(views);
77-
var offsetPosition = { size: 0, grow: 0 };
78-
79-
return views.map(function (view) {
80-
var viewPosition = {
81-
summary: viewSummaryPosition,
82-
offset: offsetPosition,
83-
position: view.position
84-
};
85-
86-
offsetPosition = concatPosition(view.position, offsetPosition);
87-
88-
return createViewLayout(view, viewPosition, panelPosition);
89-
});
90-
};
91-
92-
var createLayout = function (panelsConfig) {
93-
var panelSummaryPosition = getSummaryPosition(panelsConfig);
94-
var offsetPosition = { size: 0, grow: 0 };
95-
96-
return panelsConfig.reduce(function (layouts, panelConfig) {
97-
var panelPosition = {
98-
summary: panelSummaryPosition,
99-
offset: offsetPosition,
100-
position: panelConfig.position
101-
};
102-
103-
var viewLayouts = createPanelLayout(panelPosition, panelConfig.views);
104-
105-
offsetPosition = concatPosition(panelConfig.position, offsetPosition);
106-
107-
return layouts.concat(viewLayouts);
108-
}, []);
109-
};
110-
111-
var loadConfigs = function (layoutsFile) {
10+
module.exports = function generateLayouts(layoutsFile) {
11211
var layoutConfig = defaultLayoutConfig;
11312
if (layoutsFile) {
11413
/* eslint-disable global-require */
@@ -124,23 +23,14 @@ var loadConfigs = function (layoutsFile) {
12423
"Layout config is invalid:\n\n * " + validationResult.errors.join("\n * ") + "\n"
12524
);
12625
}
127-
return layoutConfig;
128-
};
12926

130-
var applyCustomizations = function (customizations) {
131-
return function (panelsConfig) {
132-
return panelsConfig.map(function (view) {
133-
var customization = customizations[view.type];
134-
if (!customization) {
135-
return view;
136-
}
137-
return _.merge(view, { view: customization });
138-
});
139-
};
140-
};
141-
142-
module.exports = function generateLayouts(layoutsFile, customizations) {
143-
return loadConfigs(layoutsFile)
144-
.map(applyCustomizations(customizations || {}))
145-
.map(createLayout);
27+
return layoutConfig.map(function (layouts) {
28+
return {
29+
view: {
30+
type: "panel",
31+
views: layouts.map(function (config) { return _.merge(config, { type: "panel" }); })
32+
},
33+
getPosition: _.identity
34+
};
35+
});
14636
};

lib/layout-config-schema.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
"type": "array",
2121
"items": {
2222
"oneOf": [{
23+
"$ref": "#/definitions/panel"
24+
}, {
2325
"$ref": "#/definitions/streamView"
2426
}, {
2527
"$ref": "#/definitions/memoryView"

lib/views/index.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use strict";
22

3+
var _ = require("lodash");
34
var StreamView = require("./stream-view");
45
var EventLoopView = require("./eventloop-view");
56
var MemoryGaugeView = require("./memory-gauge-view");
@@ -11,6 +12,7 @@ var EnvDetailsView = require("./env-details-view");
1112
var NodeDetailsView = require("./node-details-view");
1213
var SystemDetailsView = require("./system-details-view");
1314
var UserDetailsView = require("./user-details-view");
15+
var Panel = require("./panel");
1416

1517
var VIEW_MAP = {
1618
cpuDetails: CpuDetailsView,
@@ -22,7 +24,17 @@ var VIEW_MAP = {
2224
cpu: CpuView,
2325
memory: MemoryGaugeView,
2426
memoryGraph: MemoryGraphView,
25-
eventLoop: EventLoopView
27+
eventLoop: EventLoopView,
28+
panel: Panel
29+
};
30+
31+
// Customize view types based on a settings class
32+
var applyCustomizations = function (customizations, layoutConfig) {
33+
var customization = customizations[layoutConfig.view.type];
34+
if (!customization) {
35+
return layoutConfig;
36+
}
37+
return _.merge(layoutConfig, { view: customization });
2638
};
2739

2840
var getConstructor = function (options) {
@@ -36,6 +48,23 @@ var getConstructor = function (options) {
3648
return null;
3749
};
3850

39-
module.exports = {
40-
getConstructor: getConstructor
51+
/**
52+
* Creates a view
53+
*
54+
* @param {Object} layoutConfig raw layout { type, views, position }
55+
* @param {Object} options startup options for views
56+
* @param {Object} customizations view type customiztaions
57+
*
58+
* @returns {Object} created view oject
59+
*/
60+
module.exports.create = function create(layoutConfig, options, customizations) {
61+
var customized = applyCustomizations(customizations, layoutConfig);
62+
var viewOptions = Object.assign({}, options, {
63+
layoutConfig: customized,
64+
creator: function (layout) {
65+
return create(layout, options, customizations);
66+
}
67+
});
68+
var View = getConstructor(customized.view);
69+
return View ? new View(viewOptions) : null;
4170
};

0 commit comments

Comments
 (0)