From 066502d40870a51c48801cf24c5956ba0d1761b5 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Tue, 29 Sep 2020 16:46:56 -0700 Subject: [PATCH] Make the topo viz denser when there are >50 nodes By hiding node details and making nodes interactive instead, we can pack more allocations on a screen. --- ui/app/components/topo-viz.js | 27 ++++++++ ui/app/components/topo-viz/node.js | 7 ++ ui/app/controllers/topology.js | 30 ++++++++ ui/app/styles/charts/topo-viz-node.scss | 12 ++++ ui/app/templates/components/topo-viz.hbs | 2 + .../components/topo-viz/datacenter.hbs | 4 +- ui/app/templates/components/topo-viz/node.hbs | 14 ++-- ui/app/templates/topology.hbs | 68 ++++++++++++++++++- 8 files changed, 154 insertions(+), 10 deletions(-) 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 @@ diff --git a/ui/app/templates/components/topo-viz/datacenter.hbs b/ui/app/templates/components/topo-viz/datacenter.hbs index 810f6e810..2798fbe91 100644 --- a/ui/app/templates/components/topo-viz/datacenter.hbs +++ b/ui/app/templates/components/topo-viz/datacenter.hbs @@ -10,8 +10,10 @@ + @onAllocationSelect={{@onAllocationSelect}} + @onNodeSelect={{@onNodeSelect}}/> diff --git a/ui/app/templates/components/topo-viz/node.hbs b/ui/app/templates/components/topo-viz/node.hbs index 0e60e9742..8a756fd03 100644 --- a/ui/app/templates/components/topo-viz/node.hbs +++ b/ui/app/templates/components/topo-viz/node.hbs @@ -1,16 +1,18 @@
-

- {{@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}} - + {{#if this.allocations.length}}
-
{{if this.activeAllocation "Allocation" "Cluster"}} Details
+
+ {{#if this.activeNode}}Client{{else if this.activeAllocation}}Allocation{{else}}Cluster{{/if}} Details +
- {{#if this.activeAllocation}} + {{#if this.activeNode}} +
+

{{this.activeNode.allocations.length}} Allocations

+
+
+

+ Client: + + {{this.activeNode.node.shortId}} + +

+

Name: {{this.activeNode.node.name}}

+

Address: {{this.activeNode.node.httpAddr}}

+
+
+

{{this.nodeUtilization.totalMemoryFormatted}} {{this.nodeUtilization.totalMemoryUnits}} of memory

+
+
+
+ + {{this.nodeUtilization.reservedMemoryPercent}} + +
+
+
+ {{format-percentage this.nodeUtilization.reservedMemoryPercent total=1}} +
+
+
+ {{format-bytes this.nodeUtilization.totalReservedMemory}} / {{format-bytes this.nodeUtilization.totalMemory}} reserved +
+
+
+

{{this.nodeUtilization.totalCPU}} Mhz of CPU

+
+
+
+ + {{this.nodeUtilization.reservedCPUPercent}} + +
+
+
+ {{format-percentage this.nodeUtilization.reservedCPUPercent total=1}} +
+
+
+ {{this.nodeUtilization.totalReservedCPU}} Mhz / {{this.nodeUtilization.totalCPU}} Mhz reserved +
+
+ {{else if this.activeAllocation}}

Allocation: @@ -121,7 +179,11 @@

- +