Skip to content

Workflow building blocks

Build workflow diagrams from operations, human tasks and control-flow blocks.

Loading interactive example…Open in new tab ↗
Opening the live canvas…

Choose a block from the palette, edit its label and inputs, then connect its ports. The example builds workflow drafts; it does not execute them.

Available blocks

BlockUse it for
Start / EndMark the entry and exit of a workflow.
OperationA registered automated task.
Human workA task with named responses, such as approve or revise.
Wait for eventWait for an external event.
Sleep / timerContinue after a delay.
Decision / switchChoose a path based on a value.
Parallel / Race / QuorumRun branches until all, the first, or a required number finish.
Branch endFinish one branch.
Call / Spawn / Join workflowRun a child workflow and optionally wait for it.
SagaPair steps with compensating actions.
For eachRepeat a branch for each item.
Continue as newStart another run with new input.
QueryRead a registered query.

Set it up

Register the standard blocks and attach the session to a Flutter canvas:

dart
import 'package:vyuh_diagram_kit/vyuh_diagram_kit.dart';
import 'package:vyuh_diagram_workflow/vyuh_diagram_workflow.dart';

final registry = WorkflowAuthoringRegistry([
  WorkflowStart(),
  ...defaultWorkflowPrimitives(),
]);
final documentSession = registry.createSession(
  textLayout: FlutterDiagramTextLayoutEngine(),
);
final canvasSession = DrawingSession.fromSession(documentSession);
final canvas = DrawingCanvas(session: canvasSession);

Use registry.entries for your palette. Create a node with its registered shape type:

dart
canvasSession.createShape(
  type: registry.entries.first.shapeType,
  worldCenter: const DiagramPoint(100, 100),
);

Unmount the canvas, then dispose canvasSession followed by documentSession. For headless authoring, use registry.createSession() without the Flutter adapter.

Add your own tasks

Add WorkflowOperation and WorkflowWork entries to the registry using your workflow engine contracts. Use WorkflowResponse to name the outcomes of human work.

The example registers Send notification and Review proposal. Expand its source for a complete registration example.

Task registration source
dart
import 'package:json_schema_builder/json_schema_builder.dart' as json;
import 'package:vyuh_diagram_workflow/vyuh_diagram_workflow.dart';
import 'package:vyuh_workflow_engine/vyuh_workflow_runtime.dart' as runtime;

/// Example business contracts compose with the durable control primitives.
/// No handlers are installed and no execution service is created.
WorkflowAuthoringRegistry exampleWorkflowRegistry() {
  final attachment = json.Schema.object(
    properties: {'name': json.Schema.string(), 'url': json.Schema.string()},
    required: ['name', 'url'],
  );
  final request = runtime.Schema.identity<Map<String, Object?>>(
    name: 'notification-request',
    jsonSchema: json.Schema.fromMap({
      ...json.Schema.object(
        properties: {
          'recipient': json.Schema.string(),
          'message': json.Schema.string(),
          'priority': json.Schema.string(enumValues: ['normal', 'urgent']),
          'cc': json.Schema.list(items: json.Schema.string()),
          'delivery': json.Schema.object(
            properties: {'sender': json.Schema.string()},
          ),
          'attachments': json.Schema.list(
            items: json.Schema.fromMap({r'$ref': r'#/$defs/attachment'}),
          ),
        },
        required: ['recipient', 'message'],
      ).value,
      r'$defs': {'attachment': attachment.value},
    }),
  );
  final receipt = runtime.Schema.identity<Map<String, Object?>>(
    name: 'notification-receipt',
    jsonSchema: json.Schema.object(
      properties: {'messageId': json.Schema.string()},
      required: ['messageId'],
    ),
  );
  final review = runtime.Schema.identity<Map<String, Object?>>(
    name: 'review-request',
    jsonSchema: json.Schema.object(
      properties: {
        'title': json.Schema.string(),
        'summary': json.Schema.string(),
      },
      required: ['title', 'summary'],
    ),
  );
  runtime.Schema<Map<String, Object?>> response(
    String name,
    List<String> decisions,
  ) => runtime.Schema.identity<Map<String, Object?>>(
    name: name,
    jsonSchema: json.Schema.object(
      properties: {
        'decision': json.Schema.string(enumValues: decisions),
        'comment': json.Schema.string(),
      },
      required: ['decision', 'comment'],
    ),
  );
  return WorkflowAuthoringRegistry([
    WorkflowOperation<Map<String, Object?>, Map<String, Object?>, Never>(
      label: 'Send notification',
      description: 'System work: send a message and return its receipt.',
      operation: runtime.Operation(
        name: 'send-notification',
        input: request,
        output: receipt,
      ),
    ),
    WorkflowWork<Map<String, Object?>, Map<String, Object?>>(
      label: 'Review proposal',
      description: 'Human work: approve the proposal or request a revision.',
      work: runtime.Work(
        name: 'review-proposal',
        input: review,
        response: response('review-response', ['approve', 'revise']),
      ),
      responses: [
        WorkflowResponse(
          id: 'approve',
          label: 'Approve',
          payload: response('approval', ['approve']),
        ),
        WorkflowResponse(
          id: 'revise',
          label: 'Request revision',
          payload: response('revision', ['revise']),
        ),
      ],
    ),
    WorkflowStart(),
    ...defaultWorkflowPrimitives(),
  ]);
}