diff --git a/ui/app/components/topo-viz.js b/ui/app/components/topo-viz.js
index f317eca65..a152ac6dc 100644
--- a/ui/app/components/topo-viz.js
+++ b/ui/app/components/topo-viz.js
@@ -13,6 +13,7 @@ export default class TopoViz extends Component {
@tracked element = null;
@tracked topology = { datacenters: [] };
+ @tracked activeNode = null;
@tracked activeAllocation = null;
@tracked activeEdges = [];
@@ -36,6 +37,12 @@ export default class TopoViz extends Component {
return !this.isSingleColumn || (this.isSingleColumn && this.args.nodes.length <= 20);
}
+ // Once a cluster is large enough, the exact details of a node are
+ // typically irrelevant and a waste of space.
+ get isDense() {
+ return this.args.nodes.length > 50;
+ }
+
dataForNode(node) {
return {
node,
@@ -135,6 +142,21 @@ export default class TopoViz extends Component {
this.element = element;
}
+ @action
+ showNodeDetails(node) {
+ if (this.activeNode) {
+ set(this.activeNode, 'isSelected', false);
+ }
+
+ this.activeNode = this.activeNode === node ? null : node;
+
+ if (this.activeNode) {
+ set(this.activeNode, 'isSelected', true);
+ }
+
+ if (this.args.onNodeSelect) this.args.onNodeSelect(this.activeNode);
+ }
+
@action
associateAllocations(allocation) {
if (this.activeAllocation === allocation) {
@@ -151,6 +173,10 @@ export default class TopoViz extends Component {
set(this.topology, 'selectedKey', null);
}
} else {
+ if (this.activeNode) {
+ set(this.activeNode, 'isSelected', false);
+ }
+ this.activeNode = null;
this.activeAllocation = allocation;
const selectedAllocations = this.topology.allocationIndex[this.topology.selectedKey];
if (selectedAllocations) {
@@ -171,6 +197,7 @@ export default class TopoViz extends Component {
}
if (this.args.onAllocationSelect)
this.args.onAllocationSelect(this.activeAllocation && this.activeAllocation.allocation);
+ if (this.args.onNodeSelect) this.args.onNodeSelect(this.activeNode);
}
@action
diff --git a/ui/app/components/topo-viz/node.js b/ui/app/components/topo-viz/node.js
index 48a260647..3bef48ee0 100644
--- a/ui/app/components/topo-viz/node.js
+++ b/ui/app/components/topo-viz/node.js
@@ -98,6 +98,13 @@ export default class TopoVizNode extends Component {
this.activeAllocation = null;
}
+ @action
+ selectNode() {
+ if (this.args.isDense && this.args.onNodeSelect) {
+ this.args.onNodeSelect(this.args.node.isSelected ? null : this.args.node);
+ }
+ }
+
@action
selectAllocation(allocation) {
if (this.args.onAllocationSelect) this.args.onAllocationSelect(allocation);
diff --git a/ui/app/controllers/topology.js b/ui/app/controllers/topology.js
index 200132e40..b676c01c6 100644
--- a/ui/app/controllers/topology.js
+++ b/ui/app/controllers/topology.js
@@ -68,6 +68,31 @@ export default class TopologyControllers extends Controller {
});
}
+ @computed('activeNode')
+ get nodeUtilization() {
+ const node = this.activeNode;
+ const [formattedMemory, memoryUnits] = reduceToLargestUnit(node.memory * 1024 * 1024);
+ const totalReservedMemory = node.allocations
+ .mapBy('memory')
+ .reduce((sum, memory) => sum + (memory || 0), 0);
+ const totalReservedCPU = node.allocations
+ .mapBy('cpu')
+ .reduce((sum, cpu) => sum + (cpu || 0), 0);
+
+ return {
+ totalMemoryFormatted: formattedMemory.toFixed(2),
+ totalMemoryUnits: memoryUnits,
+
+ totalMemory: node.memory * 1024 * 1024,
+ totalReservedMemory: totalReservedMemory * 1024 * 1024,
+ reservedMemoryPercent: totalReservedMemory / node.memory,
+
+ totalCPU: node.cpu,
+ totalReservedCPU,
+ reservedCPUPercent: totalReservedCPU / node.cpu,
+ };
+ }
+
@computed('siblingAllocations.@each.node')
get uniqueActiveAllocationNodes() {
return this.siblingAllocations.mapBy('node').uniq();
@@ -80,4 +105,9 @@ export default class TopologyControllers extends Controller {
allocation.reload();
}
}
+
+ @action
+ setNode(node) {
+ this.set('activeNode', node);
+ }
}
diff --git a/ui/app/styles/charts/topo-viz-node.scss b/ui/app/styles/charts/topo-viz-node.scss
index 61db0702b..3f014450a 100644
--- a/ui/app/styles/charts/topo-viz-node.scss
+++ b/ui/app/styles/charts/topo-viz-node.scss
@@ -11,6 +11,17 @@
fill: $white-ter;
stroke-width: 1;
stroke: $grey-lighter;
+
+ &.is-interactive:hover {
+ fill: $white;
+ stroke: $grey-light;
+ }
+
+ &.is-selected,
+ &.is-selected:hover {
+ fill: $white;
+ stroke: $grey;
+ }
}
.dimension-background {
@@ -42,6 +53,7 @@
alignment-baseline: central;
font-weight: $weight-normal;
fill: $grey;
+ pointer-events: none;
}
}
diff --git a/ui/app/templates/components/topo-viz.hbs b/ui/app/templates/components/topo-viz.hbs
index 76374506e..6a604bf30 100644
--- a/ui/app/templates/components/topo-viz.hbs
+++ b/ui/app/templates/components/topo-viz.hbs
@@ -10,8 +10,10 @@
- {{@node.node.name}} - {{this.count}} Allocs - {{@node.memory}} MiB, {{@node.cpu}} Mhz -
+ {{#unless @isDense}} ++ {{@node.node.name}} + {{this.count}} Allocs + {{@node.memory}} MiB, {{@node.cpu}} Mhz +
+ {{/unless}}{{this.activeNode.allocations.length}} Allocations
+Name: {{this.activeNode.node.name}}
+Address: {{this.activeNode.node.httpAddr}}
+{{this.nodeUtilization.totalMemoryFormatted}} {{this.nodeUtilization.totalMemoryUnits}} of memory
+{{this.nodeUtilization.totalCPU}} Mhz of CPU
+