Edgewall Software
Modify

Opened 7 years ago

Closed 7 years ago

Last modified 17 months ago

#10270 closed enhancement (fixed)

[PATCH] Workflow graph visualization macro

Reported by: psuter <petsuter@…> Owned by: Peter Suter
Priority: normal Milestone: 1.0
Component: ticket system Version:
Severity: normal Keywords: workflow macro
Cc:
Release Notes:

ticket: Added [[Workflow()]] macro to visualize ticket workflows.

API Changes:

Description

I propose adding a macro to render workflow graphs, similar to the two illustrations on the TracWorkflow page (which could be replaced by this macro).

For example [[Workflow(fix = open -> closed; reopen = closed -> open)]] would expand to this figure: Example rendering of `[[Workflow(fix = open -> closed; reopen = closed -> open)]]`

Most often this would be used in MacroProcessor mode, e.g. to paste the definition from Trac's basic-workflow.ini:

    {{{
    #!Workflow
    leave = * -> *
    leave.operations = leave_status
    leave.default = 1

    accept = new,assigned,accepted,reopened -> accepted
    accept.permissions = TICKET_MODIFY
    accept.operations = set_owner_to_self

    resolve = new,assigned,accepted,reopened -> closed
    resolve.permissions = TICKET_MODIFY
    resolve.operations = set_resolution

    reassign = new,assigned,accepted,reopened -> assigned
    reassign.permissions = TICKET_MODIFY
    reassign.operations = set_owner

    reopen = closed -> reopened
    reopen.permissions = TICKET_CREATE
    reopen.operations = del_resolution
    }}}

This would expand to: Trac basic-workflow.ini example rendering

Attachments (5)

basic-example-workflow.png (59.4 KB ) - added by psuter <petsuter@…> 7 years ago.
Trac basic-workflow.ini example rendering
example-open-closed.png (7.4 KB ) - added by psuter <petsuter@…> 7 years ago.
Example rendering of [[Workflow(fix = open -> closed; reopen = closed -> open)]]
workflowmacro-jscanvas.patch (13.2 KB ) - added by psuter <petsuter@…> 7 years ago.
WorkflowMacro implementation using client-side javascript / canvas rendering
example-basic-workflow.png (59.4 KB ) - added by psuter <petsuter@…> 7 years ago.
Trac basic-workflow.ini example rendering
example-enterprise-opensource.png (383.0 KB ) - added by psuter <petsuter@…> 7 years ago.
enterprise-workflow.ini and opensorce-workflow.ini rendered using force-directed (left) and circular (right) layout

Download all attachments as: .zip

Change History (27)

Changed 7 years ago by psuter <petsuter@…>

Attachment: basic-example-workflow.png added

Trac basic-workflow.ini example rendering

Changed 7 years ago by psuter <petsuter@…>

Attachment: example-open-closed.png added

Example rendering of [[Workflow(fix = open -> closed; reopen = closed -> open)]]

Changed 7 years ago by psuter <petsuter@…>

WorkflowMacro implementation using client-side javascript / canvas rendering

Changed 7 years ago by psuter <petsuter@…>

Attachment: example-basic-workflow.png added

Trac basic-workflow.ini example rendering

comment:1 Changed 7 years ago by psuter <petsuter@…>

(Sorry, I messed up the filename on the first attachment:basic-example-workflow.png, it is the same file as attachment:example-basic-workflow.png and can be deleted.)

comment:2 Changed 7 years ago by psuter <petsuter@…>

BTW, I know this could be done in a plugin and e.g. the th:GraphvizPlugin is similar and probably more versatile. There's also the showworkflow contrib script to convert workflow files to .dot syntax and images.

But TracWorkflow is an important core part of Trac. Visualization is required to understand the implications and subtleties of a workflow, especially for new users implementing their own. I would consider it quite important that this native syntax is supported natively in Trac itself. Also, external dependencies (graphviz, dot) are not required for this comparably simple scenario (only small directed graphs with one kind of nodes and edges).

One could even take this further and integrate it into an admin panel to edit the workflow and see live visualizations or allow interactive graphical editing somehow.

comment:3 Changed 7 years ago by psuter <petsuter@…>

The attached patch is an implementation of this proposed plugin, using client-side JavaScript rendering using the canvas element (inspired by htdocs/js/log_graph.js and Dracula Graph Library).

I'm sure there are a lot of things that could be improved (both in terms of features and implementation), but it already works quite nicely. For example the attached figures were created using it.

Last edited 7 years ago by Remy Blank (previous) (diff)

comment:4 Changed 7 years ago by Remy Blank

Milestone: 0.13
Owner: set to Remy Blank

This looks very nice. I will review the patch, but one question already: when the macro is called without arguments, does it show the current ticket workflow? That would be nice to have, and could be used in the TracGuide.

comment:5 in reply to:  4 ; Changed 7 years ago by psuter <petsuter@…>

Replying to rblank:

when the macro is called without arguments, does it show the current ticket workflow?

Not yet, but that would be trivial to add.

comment:6 in reply to:  5 Changed 7 years ago by psuter <petsuter@…>

Replying to psuter <petsuter@…>:

Replying to rblank:

when the macro is called without arguments, does it show the current ticket workflow?

Not yet, but that would be trivial to add.

Done.

comment:7 Changed 7 years ago by Remy Blank

Ok, I have tested the macro, and it works nicely. I see the following issues:

  • States containing "≠&" show them as HTML entities.
  • In the template, you need to strip the outer <html>, otherwise it appears in the output.
  • Passing the graph data as an HTML table makes for difficult parsing. It could be passed as JSON data instead.
  • The macro should show a message saying that JavaScript is required to display the graph.
  • In JavaScript, try to keep as much as possible private, by defining private functions in an inner scope. Then, attach the functions you want to export to the $ symbol.
  • We try to use a "trac-" prefix for all our id and class names. Unfortunately, we can't just change them everyhwere, as it would break all customizations, but we try to stick to it when introducing new ids and classes.

I have fixed these issues, and refactored the code so that the graph data can be passed with add_script_data() and no additional template is necessary. The result is in rblank@ticket-10270-workflow-macro.

The following additional issues remain, but I'm unsure how to fix them:

  • The layout has some randomness, so it is different every time you refresh. This is quite annoying.
  • The text in nodes could be raised a bit so that it is centered in its frame.
  • Firefox 3.6 seems to have a bug when displaying rotated text. The letters are kept straight, but the text follows the line corresponding to the rotation.
  • IE8 doesn't seem to support the canvas method measureText(). It works fine with IE9.

comment:8 in reply to:  7 ; Changed 7 years ago by Jun Omae

Replying to rblank:

  • IE8 doesn't seem to support the canvas method measureText(). It works fine with IE9.

excanvas.js Release 3 doesn't support measureText() and fillText(), however excanvas.js/trunk supports these methods. See http://explorercanvas.blogspot.com/2009/04/text-support-on-trunk.html.

Update excanvas.js/trunk or use flashcanvas instead of. flashcanvas supports measureText() and fillText().

excanvas.js/trunk and flashcanvas works fine for me.

comment:9 in reply to:  7 ; Changed 7 years ago by psuter <petsuter@…>

Replying to rblank:

Ok, I have tested the macro, and it works nicely. I see the following issues: […] I have fixed these issues

Very nice, thanks!

The following additional issues remain, but I'm unsure how to fix them:

  • The layout has some randomness, so it is different every time you refresh. This is quite annoying.

The layout algorithm starts with all nodes at the same position, then pushes them away from each other. While nodes are at the same position, the push direction is chosen randomly. A simple trick would be to initialize them slightly offset, or push them in predetermined directions.

Maybe an entirely different layout algorithm should be tried.

  • The text in nodes could be raised a bit so that it is centered in its frame.

Unfortunately measureText() does not measure the height of text for some reason. Instead I assume 13px Arial is centered by drawing a h = 14 pixel height (plus border size r) box at the same coordinates as the text. Setting ctx.textBaseline = 'top' seems to help. Alternatively, in drawNode() one could change fillText(... y+h) to e.g. fillText(... y+h-2) to tweak this manually.

comment:10 in reply to:  9 Changed 7 years ago by psuter <petsuter@…>

Replying to psuter <petsuter@…>:

Replying to rblank:

  • The text in nodes could be raised a bit so that it is centered in its frame.

Setting ctx.textBaseline = 'top' seems to help.

Or 'middle', combined with much better edge label positioning here.

comment:11 in reply to:  8 ; Changed 7 years ago by Remy Blank

Replying to jomae:

excanvas.js Release 3 doesn't support measureText() and fillText(), however excanvas.js/trunk supports these methods. See http://explorercanvas.blogspot.com/2009/04/text-support-on-trunk.html.

And we have a winner! I have updated excanvas.js to current trunk (r73), compiled with the Closure Compiler, in [10760]. The graph now works on IE8, and node centering is great. The issue with Firefox 3.6 is probably not worth addressing (unless you have an idea how to fix it). I have pushed the update to my clone.

That leaves the randomness in the positioning and the colors. Would it be possible to just position the nodes in a circle, or will this lead to bad results? And instead of generating colors randomly, generate them with a deterministic algorithm?

comment:12 in reply to:  11 ; Changed 7 years ago by psuter <petsuter@…>

Replying to rblank:

The graph now works on IE8

Sweet.

The issue with Firefox 3.6 is probably not worth addressing (unless you have an idea how to fix it).

No clue, probably not.

That leaves the randomness in the positioning and the colors. Would it be possible to just position the nodes in a circle, or will this lead to bad results? And instead of generating colors randomly, generate them with a deterministic algorithm?

It would be quite boring. :) No, I guess for such graphs with typically less than ten nodes it could work alright. See for yourself, it's now implemented in my branch. (Feel free to get rid of layoutForceDirected if you like layoutCircular.) Both the color generator (slightly tweaked to generate more saturated colors) and layoutForceDirected are also deterministic now, using a primitive custom random number generator.

I also added MacroProcessor arguments width and height. Hm, maybe a layout / randomseed arguments would be nice, too. Or would that just be feature creep?

comment:13 in reply to:  12 ; Changed 7 years ago by Remy Blank

Replying to psuter <petsuter@…>:

The issue with Firefox 3.6 is probably not worth addressing (unless you have an idea how to fix it).

No clue, probably not.

Funnily enough, this issue only appears on Linux. The text is fine on Firefox 3.6 on Windows. So yes, let's drop that.

It would be quite boring. :) No, I guess for such graphs with typically less than ten nodes it could work alright. See for yourself, it's now implemented in my branch.

That looks very nice indeed. There's still a small issue with the centering of the graph, it's located in the top-left corner of the available space. This is probably due to the way you fix node.x and node.y just before drawing, in particular the division by (graph.maxx - graph.minx + 1) feels wrong (maxx is 1 and minx is -1, so the result is 3). You probably want to drop the +1.

I also added MacroProcessor arguments width and height. Hm, maybe a layout / randomseed arguments would be nice, too. Or would that just be feature creep?

Definitely feature creep, I would say. Let's have a single algorithm and tune it until it's fine for most cases. The width and height arguments make sense, though.

Changed 7 years ago by psuter <petsuter@…>

enterprise-workflow.ini and opensorce-workflow.ini rendered using force-directed (left) and circular (right) layout

comment:14 in reply to:  13 ; Changed 7 years ago by psuter <petsuter@…>

Replying to rblank:

That looks very nice indeed. There's still a small issue with the centering of the graph, it's located in the top-left corner of the available space. This is probably due to the way you fix node.x and node.y just before drawing, in particular the division by (graph.maxx - graph.minx + 1) feels wrong (maxx is 1 and minx is -1, so the result is 3). You probably want to drop the +1.

Oops, right. That was in case maxx == minx for some reason. Which reminds me to handle corner cases with one or even zero nodes. Both fixed in my branch.

I tried the other workflows from the contrib directory. The enterprise-workflow.ini and opensorce-workflow.ini have a few more nodes and edges, so they are a bit more challenging as you can see in the attached image.

The force-directed layout algorithm still ends up arranging the nodes more or less in a circle, so the circular layout in a way actually looks a bit cleaner.

The larger node names cause some clipping. Maybe the border size should be adjusted by the text measuring somehow. I'm also still not too happy that the edge labels are sometimes covered / overlapping.

Are there any other popular workflows publicly available? (I found one more: th:TestingWorkflow) Do you know if people typically create much larger workflows?

I'm not sure how I missed the WorkFlow/Examples before now. It contains figures where the edge labels include permissions and operations. Maybe that would be another useful parameter. Something like edgelabels=action,operations,permissions?

comment:15 in reply to:  14 ; Changed 7 years ago by Remy Blank

Replying to psuter <petsuter@…>:

The force-directed layout algorithm still ends up arranging the nodes more or less in a circle, so the circular layout in a way actually looks a bit cleaner.

Good job! The current state is good enough to land on trunk. Done in [10764]. I have removed the force-directed layout altogether. The halo effect on edge labels is a nice touch, it really improves readability when the label overlaps an edge.

The larger node names cause some clipping. Maybe the border size should be adjusted by the text measuring somehow.

Yes, that would indeed be nice to have.

I'm not sure how I missed the WorkFlow/Examples before now. It contains figures where the edge labels include permissions and operations. Maybe that would be another useful parameter. Something like edgelabels=action,operations,permissions?

I wouldn't do that, no. It's lots of duplicated information, as the same actions and permissions are shown below each instance of an edge. That data is more suited for textual display in a table, not in a graph.

I'm leaving this ticket open for the clipping issue.

comment:16 in reply to:  2 Changed 7 years ago by psuter <petsuter@…>

Replying to psuter <petsuter@…>:

One could even take this further and integrate it into an admin panel to edit the workflow and see live visualizations or allow interactive graphical editing somehow.

Just for reference, th:TracWorkflowAdminPlugin (which I somehow managed not to notice until now) does something like that, using graphviz. (There's also th:WorkflowEditorPlugin, but that one doesn't seem to have any graph visualization.)

comment:17 in reply to:  15 ; Changed 7 years ago by psuter <petsuter@…>

Replying to rblank:

The larger node names cause some clipping. Maybe the border size should be adjusted by the text measuring somehow.

Yes, that would indeed be nice to have.

I'm leaving this ticket open for the clipping issue.

Here is an improvement to this. It's not quite perfect, as it ignores edge label size and conservatively uses the maximum node label width as if all node labels were that long, but to get these right seems not worth it.

comment:18 in reply to:  17 Changed 7 years ago by Remy Blank

Release Notes: modified (diff)
Resolution: fixed
Status: newclosed

Replying to psuter <petsuter@…>:

Here is an improvement to this. It's not quite perfect, as it ignores edge label size and conservatively uses the maximum node label width as if all node labels were that long, but to get these right seems not worth it.

Perfect, applied in [10768]. Thanks a lot for your excellent work!

comment:19 Changed 7 years ago by Remy Blank

Owner: changed from Remy Blank to psuter <petsuter@…>

comment:20 Changed 7 years ago by Peter Suter

Owner: changed from psuter <petsuter@…> to Peter Suter

comment:21 Changed 17 months ago by anatoly techtonik <techtonik@…>

@psuter - have you thought about factoring out your state machine drawing in a separate project? This could be useful for other client side projects that still have to rely on server side GraphViz to render graphs. Like https://github.com/jakesgordon/javascript-state-machine/pull/51

comment:22 Changed 17 months ago by Peter Suter

No, I would assume it's too inflexible for general usage, but feel free to do so if it's useful. I thought there was already a full Graphviz Javascript implementation? Maybe try viz.js or visjs or dagre-d3?

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Peter Suter.
The resolution will be deleted.
to The owner will be changed from Peter Suter to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.