Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Support for groups? #255

Closed
shazz opened this issue Oct 19, 2022 · 9 comments
Closed

[Question] Support for groups? #255

shazz opened this issue Oct 19, 2022 · 9 comments
Assignees

Comments

@shazz
Copy link

shazz commented Oct 19, 2022

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 !

@shazz
Copy link
Author

shazz commented Oct 19, 2022

In the NodeParser, I tried to browse the bpmn:group elements but it looks like they are not in tree, did I miss something?

@danfunk
Copy link
Collaborator

danfunk commented Oct 20, 2022

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:
image

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?

@danfunk
Copy link
Collaborator

danfunk commented Oct 20, 2022

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>

@shazz
Copy link
Author

shazz commented Oct 20, 2022

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 :) )

@shazz
Copy link
Author

shazz commented Oct 20, 2022

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)

@shazz
Copy link
Author

shazz commented Oct 20, 2022

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!

@shazz
Copy link
Author

shazz commented Oct 31, 2022

I created a fork and added the code to retrieve the groups. If you find it interesting: https://github.com/Grain-Ecosystem/SpiffWorkflow

@danfunk
Copy link
Collaborator

danfunk commented Nov 18, 2022

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?

@shazz
Copy link
Author

shazz commented Nov 19, 2022

Definitively yes :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Resolved
Development

No branches or pull requests

2 participants