Skip to content

BPMN Allowed Items Processing

This document explains how toolbar items from panel.graph.toolbar.items are processed and converted to @mes/bpmn configuration.

Overview

The mapToolbarItem function in use-bpmn-widget-config.ts converts toolbar items into AllowedEntry objects that @mes/bpmn understands. This conversion process handles three types of toolbar items:

  1. String shortcuts - Simple strings like "startEvent" and "endEvent"
  2. ToolbarNodeItem objects - Event-driven node creation configuration and card metadata
  3. ToolbarEdgeItem objects - Full edge configurations with backend request details

Processing Logic

1. String Shortcuts for Start/End Events

typescript
if (typeof item === 'string') {
  if (item === BPMN_NODE_KINDS.START_EVENT || item === BPMN_NODE_KINDS.END_EVENT) {
    return item as AllowedEntry;
  }
  return undefined;
}

Supported values:

  • "startEvent" → Passed directly to @mes/bpmn as "startEvent"
  • "endEvent" → Passed directly to @mes/bpmn as "endEvent"

Why these are special: Start and end events are built into @mes/bpmn and don't require additional configuration. The string is passed through unchanged to the widget.

2. Object Shortcuts for Start/End Events

typescript
if (
  typeof item === 'object' &&
  'bpmnType' in item &&
  (item.bpmnType === BPMN_NODE_KINDS.START_EVENT || item.bpmnType === BPMN_NODE_KINDS.END_EVENT)
) {
  return item.bpmnType as AllowedEntry;
}

Example:

json
{
  "bpmnType": "startEvent",
  "icon": "pi pi-play"
}

Conversion: The object is converted to the string "startEvent" before passing to @mes/bpmn. This allows you to:

  • Keep one config format for all toolbar items (events, ids, metadata)
  • Execute the same onObjectCreate pipeline as tasks
  • Preserve compatibility with @mes/bpmn basic start/end entries

Important: Only bpmnType is sent to @mes/bpmn as palette entry. Other properties (events, ids, custom metadata) are still used in panel-side creation handling.

3. ToolbarNodeItem Processing

For full node configurations, the function:

  1. Finds the corresponding node config by:
    • typeName (preferred)
    • fallback by bpmnType
  2. Extracts card fields from nodeConfig.card.fields
  3. Builds field attributes and labels for the creation form
  4. Adds _bpmnTaskId to emitted node data for toolbar matching
  5. Constructs an AllowedEntry with:
    • kind: 'task'
    • id - Toolbar item identifier
    • fieldAttrs - Array of field keys for the card
    • labels - Map of field keys to display labels
    • data - Custom data merged with _bpmnTaskId
    • size - Optional size override for created nodes

Important: _bpmnTaskId is used by request-create-nodes.ts to match created nodes back to the exact toolbar item and execute onObjectCreate actions.

Example conversion:

json
// Input (ToolbarNodeItem)
{
  "id": "task-WorkOrderOperation",
  "bpmnType": "task",
  "typeName": "WorkOrderOperation",
  "placeholderCard": { "title": "New Instruction" },
  "events": [{
    "name": "onObjectCreate",
    "actions": [{ "name": "create", "editor": { "mode": "direct-request" } }]
  }]
}

// Output (AllowedEntry passed to @mes/bpmn)
{
  "kind": "task",
  "id": "task-WorkOrderOperation",
  "fieldAttrs": ["itemId", "name"],
  "labels": { "itemId": "ID", "name": "Name" },
  "data": {
    "_bpmnTaskId": "task-WorkOrderOperation"
  }
}

Node data after creation in BPMN canvas:

json
{
  "id": "Activity_abc123", // Generated by BPMN library
  "type": "task",
  "data": {
    "_bpmnTaskId": "task-WorkOrderOperation"
  }
}

4. ToolbarEdgeItem Processing

For edge configurations, the function:

  1. Extracts the request.linkName - This is REQUIRED for backend edge creation
  2. Merges user-provided data with the request configuration
  3. Constructs an AllowedEntry with:
    • kind: 'connector'
    • bpmnType - BPMN edge type (e.g., "bpmn:SequenceFlow")
    • data.request.linkName - Backend link entity name
    • Additional data fields for theme resolution

Example conversion:

json
// Input (ToolbarEdgeItem)
{
  "id": "connection-critical",
  "bpmnType": "bpmn:SequenceFlow",
  "request": { "linkName": "WFConnectorInstance" },
  "data": { "connectorType": "critical" }
}

// Output (AllowedEntry passed to @mes/bpmn)
{
  "kind": "connector",
  "id": "connection-critical",
  "bpmnType": "bpmn:SequenceFlow",
  "data": {
    "connectorType": "critical",
    "request": { "linkName": "WFConnectorInstance" }
  }
}

Data Flow Summary

Configuration to Widget

panel.graph.toolbar.items

mapToolbarItem() for each item
  ↓ (adds _bpmnTaskId to emitted palette node data)
AllowedEntry[] array

WidgetConfig.palette.allowed

@mes/bpmn widget

Node Creation to Object Creation

1. User drags toolbar item to canvas

2. @mes/bpmn creates node with data._bpmnTaskId

3. bpmn:changed event fired

4. processBpmnChanges() detects new node

5. requestCreateNodes() called with node

6. Matches toolbar item by: item.id === node.data._bpmnTaskId

7. Executes toolbar item's `onObjectCreate` actions

8. If action editor mode is `direct-request`, creation runs without modal

9. Object/method request is executed and graph is refetched

Important Notes

Start/End Event Conversion

We allow toolbar items to specify start and end events as objects (with bpmnType property), but we convert them to strings before passing to @mes/bpmn:

typescript
// Both of these inputs:
"startEvent"
{ "bpmnType": "startEvent", "events": [...] }

// Result in this @mes/bpmn config:
"startEvent"

This design:

  • Maintains flexibility - Users can specify onObjectCreate actions for start/end events
  • Preserves @mes/bpmn API - The widget still receives simple strings
  • Keeps creation behavior consistent - start/end and task use the same event pipeline

Creation Request Data

For ToolbarNodeItem, creation is configured via panel.graph.toolbar.items[].events[].actions[] (usually onObjectCreate). This is separate from node display configuration in panel.graph.nodes[].

For ToolbarEdgeItem, we use panel.graph.toolbar.items[].request.linkName directly. The linkName is embedded in the data.request object passed to @mes/bpmn.

Field Resolution Priority

When determining which fields to show on a node card:

  1. Primary source: nodeConfig.card.fields (node configuration from graph.nodes[])
  2. Placeholder scope: item.placeholderCard.title only (title override)
  3. Fallback: Empty field array

This keeps placeholder behavior minimal and predictable while preserving field layout from node card configuration.