[Question] Support for groups?
shazz opened this issue · 9 comments
Hi,
I was looking at the NodeParser
code (1.2.1) and it looks like for Tasks
, Groups
are not yet supported. But Positions
and Lanes
are.
I'd like to try to add it but maybe better to ask before :)
I guess the trick would be to get the goups postions from the XML then check the Task positions and find out which one is around ?
Thanks !
In the NodeParser, I tried to browse the bpmn:group
elements but it looks like they are not in tree, did I miss something?
It looks like groups are a way of visually representing something called a Category, and Categories can be "used for documentation or analysis purposes", as a way of grouping a set of Flow Elements (such as tasks).
When I create a simple model in the BPMN.io editor like this one:
It creates a bpmn:category entity in the XML - and it's value attribute references back to the name given to the group.
<bpmn:category id="Category_1qjs3te">
<bpmn:categoryValue id="CategoryValue_0jddzsz" value="my_group" />
</bpmn:category>
Out of curiosity, what you hoping to do with groups?
And the visual component is also connected to the "my_group", which will allow you to grab the coordinates.
<bpmndi:BPMNShape id="Group_0n9d0e3_di" bpmnElement="my_group">
<dc:Bounds x="425" y="55" width="210" height="230" />
<bpmndi:BPMNLabel>
<dc:Bounds x="506" y="62" width="49" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
Thanks :) Yes this is what I'm trying to get from the NodeParser for a Task:
NodeParser
class NodeParser:
def __init__(self, node, filename, doc_xpath, lane=None):
self.node = node
self.filename = filename
self.doc_xpath = doc_xpath
self.xpath = xpath_eval(node)
self.lane = self._get_lane() or lane
self.position = self._get_position() or {'x': 0.0, 'y': 0.0}
self.group = self._get_group()
def _get_group(self):
shape = first(self.doc_xpath(f".//bpmndi:BPMNShape[@bpmnElement='{self.get_id()}']//dc:Bounds"))
if shape is not None:
node_bounds = {
'x': float(shape.get('x', 0)),
'y': float(shape.get('y', 0)),
'w': float(shape.get('width', 0)),
'h': float(shape.get('height', 0))}
p = self.xpath('..')[0]
children = p.getchildren()
for child in children:
if 'group' in child.tag:
g_id = child.get('id')
cref = child.get('categoryValueRef')
cat_val = first(self.doc_xpath(f".//bpmn:categoryValue[@id='{cref}']"))
group_name = cat_val.get('value')
bounds = first(self.doc_xpath(f".//bpmndi:BPMNShape[@bpmnElement='{g_id}']//dc:Bounds"))
x = float(bounds.get('x', 0))
y = float(bounds.get('y', 0))
w = float(bounds.get('width', 0))
h = float(bounds.get('height', 0))
if node_bounds['x'] > x and node_bounds['x']+node_bounds['w'] < (x+w) and node_bounds['y'] > y and node_bounds['y']+node_bounds['h'] < (y+h):
return group_name
return "no group"
TaskParser
def create_task(self):
"""
Create an instance of the task appropriately. A subclass can override
this method to get extra information from the node.
"""
return self.spec_class(self.spec, self.get_task_spec_name(),
lane=self.lane,
description=self.node.get('name', None),
position=self.position,
group=self.group)
BpmnSpecMixin
class BpmnSpecMixin(TaskSpec):
"""
All BPMN spec classes should mix this superclass in. It adds a number of
methods that are BPMN specific to the TaskSpec.
"""
def __init__(self, wf_spec, name, lane=None, position=None, group=None, **kwargs):
"""
Constructor.
:param lane: Indicates the name of the lane that this task belongs to
(optional).
"""
super(BpmnSpecMixin, self).__init__(wf_spec, name, **kwargs)
self.outgoing_sequence_flows = {}
self.outgoing_sequence_flows_by_id = {}
self.lane = lane
self.position = position or {'x': 0, 'y': 0}
self.loopTask = False
self.documentation = None
self.data_input_associations = []
self.data_output_associations = []
self.group = group
(I'm sure it can be done if a better way... learning while trying :) )
Out of curiosity, what you hoping to do with groups?
Just that I have laaaarge BPMN/DMN processes (not very complex but fairly long) and I'm using groups just to define some "sections" of the process and when running the process I'd like to show in which section I am (kind of progress bar)
then I create a simple model in the BPMN.io editor
OH! I did not know this editor, I was still using the Camunda Modeler. Looks pretty nice! But I did not find a way to edit the Script Task properties (I'm using Expressions)
EDIT: ok, got it :) Interesting!
I created a fork and added the code to retrieve the groups. If you find it interesting: https://github.com/Grain-Ecosystem/SpiffWorkflow
Hey @shazz - sorry I let this languish, I thing there is real value in the effort - and I would like to see this functionality in SpiffWorkflow -- would you be willing to create a Pull Request on this -- with all tests passing, and new tests to assure groups are working?
Definitively yes :)