Author: eallen
Date: 2010-08-23 12:02:10 -0400 (Mon, 23 Aug 2010)
New Revision: 4217
Modified:
mgmt/newdata/cumin/python/cumin/charts.py
mgmt/newdata/cumin/python/cumin/grid/pool.strings
mgmt/newdata/cumin/python/cumin/grid/slot.py
mgmt/newdata/cumin/python/cumin/grid/slot.strings
mgmt/newdata/cumin/resources/slots.swf
Log:
Changes for BZ 625213:
- Remove treemap and replace with State / Activity legend
- Highlight slots when State / Activity is moused over in legend
- Start with no systems / accounting groups expanded
- Add a back button when a system / accounting group is expanded
Modified: mgmt/newdata/cumin/python/cumin/charts.py
===================================================================
--- mgmt/newdata/cumin/python/cumin/charts.py 2010-08-23 15:24:21 UTC (rev 4216)
+++ mgmt/newdata/cumin/python/cumin/charts.py 2010-08-23 16:02:10 UTC (rev 4217)
@@ -25,16 +25,45 @@
self.min_shadow = 14
self.surface = None
- def plot_dot(self, interior, width, height):
+ def plot_colored_rect(self, interior, width, height):
surface = ImageSurface(FORMAT_ARGB32, int(width), int(height))
cr = Context(surface)
cr.set_line_width(1)
cr.set_source_rgb(*interior)
- cr.rectangle(0, 0, width - 1, width - 1)
+ cr.rectangle(0, 0, width - 1, height - 1)
cr.fill()
return surface
+ def plot_state(self, state, width, height):
+ surface = ImageSurface(FORMAT_ARGB32, int(width), int(height))
+ cr = Context(surface)
+ cr.set_line_width(2)
+
+ self._plot_square(cr, (0.7, 0.7, 0.7), state, 0, 0, width, height)
+ return surface
+
+ def _plot_square(self, cr, colors, state, x, y, width, height):
+ cr.set_source_rgb(*colors)
+ #cr.move_to(x, y)
+ cr.rectangle(x, y, width - 1, height - 1)
+
+ if state == "Unclaimed": # leave empty
+ cr.stroke()
+ elif state == "Claimed": # solid fill
+ cr.fill()
+ elif state == "Owner": # diagonal line
+ cr.move_to(x, y)
+ cr.line_to(x + width - 1, y + height - 1)
+ cr.stroke()
+ elif state in ("Matched", "Preempting",
"Preempting/Matched"): # triangle
+ cr.stroke()
+ cr.move_to(x + width - 1, y)
+ cr.line_to(x, y + height - 1)
+ cr.line_to(x + width - 1, y + height - 1)
+ cr.close_path()
+ cr.fill()
+
def plot_slots(self, slots, zl):
count = len(slots)
slot_size = self.slot_size(count, zl)
@@ -46,36 +75,18 @@
self.surface = ImageSurface(FORMAT_ARGB32, int(self.width), int(self.height))
cr = Context(self.surface)
cr.set_line_width(1)
- i = 0
+
for slot in slots:
- i = i + 1
interior, state = slot[:2]
- #if x + slot_size >= self.width:
if col >= self.cols:
x = 0
y = y + slot_size
col = 0
self.rows = self.rows + 1
- cr.set_source_rgb(*interior)
- cr.rectangle(x, y, slot_size - 1, slot_size - 1)
- cr.fill()
+ self._plot_square(cr, interior, state, x, y, slot_size, slot_size)
- # draw the state if the slots are big enough
- if state and slot_size >= self.min_font:
- cr.set_source_rgb(interior[0]/10, interior[1]/10, interior[2]/10)
- cr.select_font_face("verdana", FONT_SLANT_NORMAL,
FONT_WEIGHT_BOLD)
- cr.set_font_size(slot_size/3)
- width, height = cr.text_extents(state[0])[2:4]
- dx = (slot_size / 2) - (width / 2)
- dy = (slot_size / 2) + (height / 2)
-
- if slot_size < self.min_sphere_size:
- cr.set_source_rgb(1,1,1)
- cr.move_to(x + dx, y + dy)
- cr.show_text(state[0])
-
x = x + slot_size
col = col + 1
return slot_size
Modified: mgmt/newdata/cumin/python/cumin/grid/pool.strings
===================================================================
--- mgmt/newdata/cumin/python/cumin/grid/pool.strings 2010-08-23 15:24:21 UTC (rev 4216)
+++ mgmt/newdata/cumin/python/cumin/grid/pool.strings 2010-08-23 16:02:10 UTC (rev 4217)
@@ -45,7 +45,7 @@
<h2>{title}</h2>
<div class="duration">{group_by}</div>
<div id="{id}_chart"></div>
- <div id="{id}ctrl_chart"></div>
+ {slot_legend}
</div>
</div>
<script type="text/javascript">
@@ -81,6 +81,9 @@
}
}
function vis_expand(parent) {
+ if (parent == null) {
+ parent = "None";
+ }
var chart = cumin.getFlashChart("{id}");
var src = chart.src;
var branch = wooly.session.branch(src);
@@ -88,13 +91,20 @@
chart.src = branch.marshal();
updatePoolSlotVis("{id}", "reload");
}
+ function vis_back() {
+ var chart = cumin.getFlashChart("{id}");
+ var src = chart.src;
+ var branch = wooly.session.branch(src);
+ if (typeof branch.expanded != "undefined")
+ delete branch.expanded;
+ chart.src = branch.marshal();
+ updatePoolSlotVis("{id}", "reload");
+ }
function vis_treemap_over(type, value) {
var chart = cumin.getFlashChart("{id}");
if (chart) {
if (typeof chart.highlight != "undefined")
chart.highlight(type, value);
- else
- wooly.log("highlight not definded for " + id);
}
}
function vis_treemap_out(type, value) {
@@ -102,8 +112,6 @@
if (chart) {
if (typeof chart.lowlight != "undefined")
chart.lowlight(type, value);
- else
- wooly.log("lowlight not definded for " + id);
}
}
function slot_vis(state, a, id, href) {
Modified: mgmt/newdata/cumin/python/cumin/grid/slot.py
===================================================================
--- mgmt/newdata/cumin/python/cumin/grid/slot.py 2010-08-23 15:24:21 UTC (rev 4216)
+++ mgmt/newdata/cumin/python/cumin/grid/slot.py 2010-08-23 16:02:10 UTC (rev 4217)
@@ -131,14 +131,18 @@
self.zoom_level.default = 1
self.add_parameter(self.zoom_level)
- self.dot = Parameter(app, "dot")
- self.add_parameter(self.dot)
+ self.activity = Parameter(app, "act")
+ self.add_parameter(self.activity)
+ self.state = Parameter(app, "state")
+ self.add_parameter(self.state)
+
self.json = Parameter(app, "json")
self.add_parameter(self.json)
self.expanded = Parameter(app, "expanded")
- self.expanded.default = "all"
+ self.expanded.default = ""
+ self.expanded.all = "all"
self.add_parameter(self.expanded)
group = Parameter(app, "agroup")
@@ -154,18 +158,29 @@
def get_cache_control(self, session):
return "no-cache"
- def render_dot(self, session, dot):
+ def render_activity(self, session, activity):
map = HeatMapChart()
- surface = map.plot_dot(self.interiors[dot], 12, 12)
+ surface = map.plot_colored_rect(self.interiors[activity], 12, 12)
writer = Writer()
surface.write_to_png(writer)
return writer.to_string()
+ def render_state(self, session, state):
+ map = HeatMapChart()
+ surface = map.plot_state(state, 12, 12)
+ writer = Writer()
+ surface.write_to_png(writer)
+ return writer.to_string()
+
def do_render(self, session):
- dot = self.dot.get(session)
- if dot:
- return self.render_dot(session, dot)
+ activity = self.activity.get(session)
+ if activity:
+ return self.render_activity(session, activity)
+ state = self.state.get(session)
+ if state:
+ return self.render_state(session, state)
+
if self.json.get(session):
return self.render_json(session)
@@ -242,7 +257,7 @@
expanded = self.expanded.get(session)
json = self.json.get(session)
leaves = True
- root.tree = self.treeify(records, range(slot_count), groups, 0,
+ (root.tree, root.back) = self.treeify(records, range(slot_count), groups, 0,
expanded, leaves, slot_count, json)
return "[%s]" % root.create()
@@ -252,9 +267,9 @@
# leaf
if level == len(groups):
if leaves:
- #for i in sorted(plist, key=lambda x:records[x]["name"]):
- for i in sorted(plist, key=lambda x:"%s%s%s" %
- (records[x]["Activity"],
records[x]["State"], records[x]["Name"])):
+ #for i in sorted(plist, key=lambda x:"%s%s%s" %
+ # (records[x]["Activity"],
records[x]["State"], records[x]["Name"])):
+ for i in sorted(plist, key=lambda x: records[x]["Name"]):
el = Element()
el.job_id = records[i]["JobId"] and
records[i]["JobId"] or ""
el.activity = records[i]["Activity"] and
records[i]["Activity"] or "Unknown"
@@ -264,17 +279,19 @@
el.name = "slot"
el.slot_id = records[i]["_id"]
level_list.append(el)
+ return (level_list, True)
else:
- # display summary info for all the slots under this grouping
- activityStates = self.get_activityStates(records, plist)
- for activityState in activityStates:
- el = Element()
- el.name = "slot_info"
- el.a_s = activityState
- el.count = activityStates[activityState]
- el.value = "%s.%s" % (records[plist[0]][groups[level-1]],
activityState) # uid
- level_list.append(el)
- return level_list
+ if not expanded:
+ # display summary info for all the slots under this grouping
+ activityStates = self.get_activityStates(records, plist)
+ for activityState in activityStates:
+ el = Element()
+ el.name = "slot_info"
+ el.a_s = activityState
+ el.count = activityStates[activityState]
+ el.value = "%s.%s" %
(records[plist[0]][groups[level-1]], activityState) # uid
+ level_list.append(el)
+ return (level_list, False)
# not a leaf
group = groups[level]
@@ -288,25 +305,19 @@
el.level = level
if level < len(groups):
if json == "slots":
- if expanded == self.expanded.default:
- # expand the 1st group if there are too many slots
- if slot_count >= self.max_visible_slots:
- if first:
- leaves = True
- first = False
- else:
- leaves = False
- else:
- leaves = True
- elif expanded == key:
+ if expanded == key:
leaves = True
+ elif expanded == "None" and key is None:
+ leaves = True
else:
leaves = False
- el.tree = self.treeify(records, level_dict[key], groups, level + 1,
+ (el.tree, el.back) = self.treeify(records, level_dict[key], groups, level
+ 1,
expanded, leaves, slot_count, json)
- level_list.append(el)
+
+ if len(el.tree):
+ level_list.append(el)
- return level_list
+ return (level_list, False)
def get_cached(self, session, zl):
filename = self.gen_filename(session)
@@ -364,24 +375,12 @@
def __init__(self, app, name):
super(SlotMap.SlotLegend, self).__init__(app, name)
- self.states = self.SlotStates(app, "slot_states")
+ self.states = SlotStates(app, "slot_states")
self.add_child(self.states)
self.activities = SlotActivities(app, "slot_activities")
self.add_child(self.activities)
- class SlotStates(ItemSet):
- states = ("Unclaimed", "Claimed", "Owner",
"Matched", "Preempting")
-
- def do_get_items(self, session):
- return self.states
-
- def render_item_initial(self, session, state):
- return state[0]
-
- def render_item_title(self, session, state):
- return state
-
class SlotInfo(ItemSet):
display_names = {"JobId": ("Job ID", "",
""),
"System": ("System", "",
""),
@@ -450,6 +449,24 @@
def render_item_row_class(self, session, item):
return item[0][2] and "class='%s'" % item[0][2] or
""
+class SlotStates(ItemSet):
+ states = ("Unclaimed", "Claimed", "Owner",
"Matched", "Preempting")
+
+ def do_get_items(self, session):
+ return self.states
+
+ def render_item_size(self, session, activity):
+ return 12
+
+ def render_item_title(self, session, state):
+ return state
+
+ def render_item_href(self, session, state):
+ params = list()
+ params.append("state=%s" % state)
+
+ return "poolslots.vis?" + ";".join(params)
+
class SlotActivities(ItemSet):
activities = (("Idle", "clear"),
("Busy", "green"),
@@ -460,18 +477,18 @@
("Retiring", "purple"),
("Unknown", "grey"))
+ def do_get_items(self, session):
+ return self.activities
+
def render_item_size(self, session, activity):
return 12
- def do_get_items(self, session):
- return self.activities
-
def render_item_title(self, session, activity):
return activity[0]
def render_item_href(self, session, activity):
params = list()
- params.append("dot=%s" % activity[0])
+ params.append("act=%s" % activity[0])
return "poolslots.vis?" + ";".join(params)
Modified: mgmt/newdata/cumin/python/cumin/grid/slot.strings
===================================================================
--- mgmt/newdata/cumin/python/cumin/grid/slot.strings 2010-08-23 15:24:21 UTC (rev 4216)
+++ mgmt/newdata/cumin/python/cumin/grid/slot.strings 2010-08-23 16:02:10 UTC (rev 4217)
@@ -1204,14 +1204,18 @@
div.slot_states ul, div.slot_activities ul {
padding: 0;
margin: 0;
- font-size: 0.8em;
+ font-size: 0.9em;
list-style: none;
}
-div.slot_states ul li span {
- font-weight: bold;
+div.slot_states li, div.slot_activities li {
+ padding-bottom: 0.25em;
}
+div.slot_states li:hover, div.slot_activities li:hover {
+ color: red;
+}
+
[SlotLegend.html]
<div class="slot_legend">
{slot_states}
@@ -1236,15 +1240,14 @@
</div>
[SlotStates.item_html]
-<li>
- <span>{item_initial}</span>
-
+<li onmouseover="vis_treemap_over('state', '{item_title}')"
onmouseout="vis_treemap_out('state', '{item_title}')">
+ <img src="{item_href}" width="{item_size}"
height="{item_size}" title="{item_title}"
alt="{item_title}"/>
{item_title}
</li>
[SlotActivities.item_html]
-<li>
- <img src="{item_href}" width="{item_size}"
height="{item_size}" alt="{item_title}"/>
+<li onmouseover="vis_treemap_over('activity',
'{item_title}')" onmouseout="vis_treemap_out('activity',
'{item_title}')">
+ <img src="{item_href}" width="{item_size}"
height="{item_size}" title="{item_title}"
alt="{item_title}"/>
{item_title}
</li>
Modified: mgmt/newdata/cumin/resources/slots.swf
===================================================================
(Binary files differ)