From 448c0e0fc4118fbf042fe31d8a40a898f28bd669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 30 Jun 2015 14:27:48 +0200 Subject: [PATCH] admin: style workflow graph with colours (#7708) --- wcs/admin/workflows.py | 82 +++++++++++++++++++++++-------------- wcs/qommon/static/css/dc2/admin.css | 19 ++++----- 2 files changed, 58 insertions(+), 43 deletions(-) diff --git a/wcs/admin/workflows.py b/wcs/admin/workflows.py index 30ee073..2be9f71 100644 --- a/wcs/admin/workflows.py +++ b/wcs/admin/workflows.py @@ -59,30 +59,30 @@ def remove_attribute(node, att): del node.attrib[att] -def remove_style(node, top): +def remove_style(node, top, colours, white_text=False): remove_tag(node, TITLE) if node.get('fill') == 'white' and node.get('stroke') == 'white': # this is the general white background, wipe it to be transparent node.attrib['fill'] = 'transparent' node.attrib['stroke'] = 'transparent' + if node.tag == svg('text') and white_text: + node.attrib['fill'] = 'white' for child in node: remove_attribute(child, XLINK_TITLE) - style = child.get('style', None) - # Beware ! HACK ! salmon is matched and converted to class="page-subject" - if style: - m = re.search('(?:stroke|fill):salmon', style) - if m: - top.set('class', top.get('class','') + ' page-subject') - if child.get('fill') == 'salmon': - top.set('class', top.get('class', '') + ' page-subject') + if child.get('fill') in colours: + matching_hexa = colours.get(child.get('fill')) + child.attrib['fill'] = '#' + matching_hexa + del child.attrib['stroke'] + if misc.get_foreground_colour(matching_hexa) == 'white': + white_text = True if child.get('font-family'): del child.attrib['font-family'] if child.get('font-size'): child.attrib['font-size'] = str(float(child.attrib['font-size'])*0.8) remove_attribute(child, 'style') - remove_style(child, top) + remove_style(child, top, colours, white_text=white_text) -def graphviz_post_treatment(content): +def graphviz_post_treatment(content, colours): ''' Remove all svg:title and top-level svg:polygon nodes, remove style attributes and xlink:title attributes. @@ -90,17 +90,44 @@ def graphviz_post_treatment(content): part on as class selector on the top level svg:g element. ''' tree = ET.fromstring(content) + style = ET.SubElement(tree, svg('style')) + style.attrib['type'] = 'text/css' + css_url = '%s%s%s' % (get_publisher().get_root_url(), + get_publisher().qommon_static_dir, + get_publisher().qommon_admin_css) + style.text = '@import url(%s);' % css_url for root in tree: remove_tag(root, TITLE) # remove_tag(root, POLYGON) for child in root: - remove_style(child, child) + remove_style(child, child, colours) return ET.tostring(tree) def graphviz(workflow, url_prefix='', select=None, svg=True, include=False): out = StringIO() + # a list of colours known to graphviz, they will serve as key to get back + # to the colours defined in wcs. + graphviz_colours = [ + 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', + 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', + 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', + 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', + 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', + 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', + 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', + 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', + 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', + 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', + 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green', + 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', + 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', + 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', + 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', ] + + colours = {} + revert_colours = {} print >>out, 'digraph main {' # print >>out, 'graph [ rankdir=LR ];' print >>out, 'node [shape=box,style=filled];' @@ -110,7 +137,12 @@ def graphviz(workflow, url_prefix='', select=None, svg=True, print >>out, 'status%s' % i, print >>out, '[label="%s"' % status.name, if select == str(i): - print >>out, ',color=salmon' + print >>out, ',id=current_status' + if status.colour: + if status.colour not in colours: + colours[status.colour] = graphviz_colours.pop() + revert_colours[colours[status.colour]] = status.colour + print >>out, ',color=%s' % colours[status.colour] print >>out, ' URL="%sstatus/%s/"];' % (url_prefix, i) for status in workflow.possible_status: @@ -118,26 +150,14 @@ def graphviz(workflow, url_prefix='', select=None, svg=True, for item in status.items: next_status_ids = [x.id for x in item.get_target_status()] if not next_status_ids: - next_status_ids = [status.id] + continue for next_id in next_status_ids: print >>out, 'status%s -> status%s' % (i, next_id) + if item.key == 'timeout' or (item.key == 'jump' and ( + item.condition or item.trigger or item.timeout)): + print >> out, ' [style=dotted]' url = 'status/%s/items/%s/' % (i, item.id) - if getattr(item, 'label', None): - label = item.label - if getattr(item, 'by', None): - roles = workflow.render_list_of_roles(item.by) - label += ' %s %s' % (_('by'), roles) - else: - label = item.render_as_line() - label = label.replace('"', '\\"') - label = label.decode('utf8') - label = textwrap.fill(label, 20, break_long_words=False) - label = label.encode('utf8') - label = label.replace('\n', '\\n') - print >>out, '[label="%s"' % label, - if select == '%s-%s' % (i, item.id): - print >>out, ',color=salmon' - print >>out, ',URL="%s%s"]' % (url_prefix, url) + continue print >>out, '}' out = out.getvalue() if svg: @@ -146,8 +166,8 @@ def graphviz(workflow, url_prefix='', select=None, svg=True, out, err = process.communicate(out) except OSError: return '' + out = graphviz_post_treatment(out, revert_colours) if include: - out = graphviz_post_treatment(out) # It seems webkit refuse to accept SVG when using its proper namespace, # and xlink namespace prefix must be xlink: to be acceptable out = out.replace('ns0:', '') diff --git a/wcs/qommon/static/css/dc2/admin.css b/wcs/qommon/static/css/dc2/admin.css index 089b81b..3e4df9d 100644 --- a/wcs/qommon/static/css/dc2/admin.css +++ b/wcs/qommon/static/css/dc2/admin.css @@ -720,21 +720,23 @@ svg { width: 100%; height: 100%; margin: auto; + font-family: sans-serif; } svg .node polygon { - stroke:black; - fill:#EEE; + stroke: #444; + stroke-width: 1px; } svg .node path { - fill:none; + fill: none; stroke: black; } svg .edge path { fill:none; stroke: black; + stroke: #666; } svg .edge polygon { stroke: black; @@ -745,15 +747,8 @@ svg .edge text { svg .edge text { font-size: 60%; } -svg .page-subject.edge text { - fill: #91a9b2; -} -svg .page-subject polygon { - fill: #91a9b2; - stroke: #91a9b2; -} -svg .page-subject path { - stroke: #91a9b2; +svg #current_status polygon { + stroke-width: 2px; } .foldable { -- 2.1.4