@maestrodimateo/ngx-workflow
v0.5.1
Published
Angular library for configuring Laravel Workflow circuits, baskets, transitions, actions and conditions
Maintainers
Readme
@maestrodimateo/ngx-workflow
Angular library for configuring Laravel Workflow circuits, baskets, transitions, actions and conditions.
Drop a single <wf-workflow-admin /> component into your app and get a full visual workflow designer built with Angular Material.
Table of contents
- Requirements
- Installation
- Setup
- Usage
- Component reference
- Theming
- Laravel backend setup
- API endpoints
- License
Requirements
- Angular >= 20
- Angular Material >= 20
- A Laravel backend with
maestrodimateo/laravel-workflowinstalled
Installation
npm install @maestrodimateo/ngx-workflowMake sure Angular Material is set up in your project:
ng add @angular/materialSetup
1. Provide the library configuration
// app.config.ts
import { provideHttpClient } from '@angular/common/http';
import { provideWorkflow } from '@maestrodimateo/ngx-workflow';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideWorkflow({ apiBaseUrl: 'https://api.example.com/workflow' }),
],
};The apiBaseUrl must point to the Laravel route prefix where the workflow API is mounted (typically /workflow).
2. Authentication
The library sends HTTP requests via Angular's HttpClient. To attach your auth token, add an interceptor:
// auth.interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('token'); // or your auth service
if (token) {
req = req.clone({ setHeaders: { Authorization: `Bearer ${token}` } });
}
return next(req);
};
// app.config.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authInterceptor } from './auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withInterceptors([authInterceptor])),
provideWorkflow({ apiBaseUrl: 'https://api.example.com/workflow' }),
],
};Usage
Full admin (one component does everything)
import { Component } from '@angular/core';
import { WorkflowAdminComponent } from '@maestrodimateo/ngx-workflow';
@Component({
imports: [WorkflowAdminComponent],
template: `<wf-workflow-admin />`,
styles: `:host { display: block; height: 100vh; }`,
})
export class WorkflowPage {}This single component gives you:
- Circuit list — create, edit, delete, import/export JSON
- Visual canvas designer — drag-and-drop baskets, SVG arrows, pan, zoom
- Basket forms — create/edit with colors, roles
- Transition configuration — attach actions and conditions
- Message template editor — with variable interpolation
You can also use it inside a route:
// app.routes.ts
import { WorkflowPage } from './workflow.page';
export const routes: Routes = [
{ path: 'admin/workflow', component: WorkflowPage },
];Individual components
For custom layouts, use each component independently:
import {
CircuitListComponent,
CircuitFormComponent,
BasketFormComponent,
TransitionConfigComponent,
MessageEditorComponent,
WorkflowCanvasComponent,
WorkflowApiService,
WorkflowConfig,
} from '@maestrodimateo/ngx-workflow';Circuit list
<wf-circuit-list
(selected)="openCircuit($event)"
(createClicked)="showCreateForm()"
(editClicked)="showEditForm($event)"
(deleted)="onDeleted($event)"
(imported)="onImported($event)"
/>| Output | Type | Description |
|---|---|---|
| selected | Circuit | A circuit was clicked |
| createClicked | void | "New circuit" button was clicked |
| editClicked | Circuit | Edit button was clicked |
| deleted | Circuit | A circuit was deleted |
| imported | Circuit | A circuit was imported from JSON |
Circuit form
<wf-circuit-form
[circuit]="existingCircuit"
[config]="workflowConfig"
(saved)="onCircuitSaved($event)"
(cancelled)="goBack()"
/>| Input | Type | Description |
|---|---|---|
| circuit | Circuit \| undefined | Pass existing circuit to edit, omit to create |
| config | WorkflowConfig \| undefined | Designer metadata (from GET /config) |
Canvas designer
<wf-canvas
[circuitId]="circuit.id"
(basketSelected)="selectBasket($event)"
(transitionSelected)="configureTransition($event)"
(connectionCreated)="createConnection($event)"
/>| Input | Type | Description |
|---|---|---|
| circuitId | string | Required. The circuit to display |
| Output | Type | Description |
|---|---|---|
| basketSelected | Basket | A basket node was clicked |
| transitionSelected | { from: Basket, to: Basket } | A transition arrow was clicked |
| connectionCreated | { from: Basket, to: Basket } | A new connection was drawn port-to-port |
Canvas features:
- Drag baskets to reposition (positions auto-saved to API)
- Pan by clicking and dragging the background
- Zoom with scroll wheel or +/− buttons
- Create transitions by dragging from the right port (●) to a left port
- Click arrows to configure transitions
Basket form
<wf-basket-form
[circuitId]="circuit.id"
[basket]="existingBasket"
[config]="workflowConfig"
(saved)="onBasketSaved($event)"
(cancelled)="goBack()"
/>Transition config
<wf-transition-config
[fromId]="sourceBasket.id"
[toId]="targetBasket.id"
[config]="workflowConfig"
(saved)="onTransitionSaved($event)"
(cancelled)="goBack()"
/>Message editor
<wf-message-editor
[circuitId]="circuit.id"
[message]="existingMessage"
[config]="workflowConfig"
(saved)="onMessageSaved($event)"
(cancelled)="goBack()"
/>Click on variable chips to insert {{ variable }} into the content field.
API service
For fully custom integrations, inject WorkflowApiService directly:
import { WorkflowApiService } from '@maestrodimateo/ngx-workflow';
@Component({ ... })
export class MyComponent {
private readonly api = inject(WorkflowApiService);
ngOnInit() {
// Fetch designer metadata
this.api.getConfig().subscribe(config => { ... });
// CRUD circuits
this.api.getCircuits().subscribe(circuits => { ... });
this.api.createCircuit({ name: 'Invoice approval', targetModel: 'App\\Models\\Invoice' });
// Baskets
this.api.getBaskets(circuitId).subscribe(baskets => { ... });
this.api.createBasket({ name: 'Review', status: 'REVIEW', color: '#2563eb', circuit_id: circuitId });
// Transitions
this.api.updateTransition(fromId, toId, { label: 'Approve', actions: [...], conditions: [...] });
// Connect two baskets
this.api.connectBaskets(targetBasket, sourceBasketId);
// Messages
this.api.getMessages(circuitId).subscribe(messages => { ... });
// Export / Import
this.api.exportCircuit(circuitId).subscribe(json => { ... });
this.api.importCircuit(file).subscribe(circuit => { ... });
}
}Component reference
| Selector | Description |
|---|---|
| <wf-workflow-admin> | Full admin — all-in-one component |
| <wf-circuit-list> | Circuit list with CRUD, import/export |
| <wf-circuit-form> | Circuit create/edit form |
| <wf-canvas> | Visual drag-and-drop designer canvas |
| <wf-basket-form> | Basket create/edit form |
| <wf-transition-config> | Transition actions & conditions config |
| <wf-message-editor> | Message template editor |
Theming
The library uses Angular Material components and respects your app's Material theme. The canvas uses Material Design CSS tokens (--mat-sys-primary, --mat-sys-surface, --mat-sys-outline, etc.) so it adapts automatically to your theme, including dark mode.
No additional CSS is needed beyond your standard Angular Material setup.
Laravel backend setup
Install the Laravel package:
composer require maestrodimateo/laravel-workflow
php artisan vendor:publish --tag=workflow-config
php artisan vendor:publish --tag=workflow-migrations
php artisan migrateThe API routes are automatically registered under the configured prefix (default: /workflow). Make sure the route middleware is set to api + your auth guard:
// config/workflow.php
'routes' => [
'prefix' => 'workflow',
'middleware' => ['api', 'auth:sanctum'],
],API endpoints
All endpoints are relative to the configured apiBaseUrl.
| Method | Endpoint | Description |
|---|---|---|
| GET | /config | Designer metadata (colors, actions, conditions, models, roles) |
| GET | /circuits | List all circuits |
| POST | /circuits | Create a circuit |
| GET | /circuits/{id} | Get a circuit |
| PUT | /circuits/{id} | Update a circuit |
| DELETE | /circuits/{id} | Delete a circuit |
| GET | /circuits/{id}/baskets | List baskets of a circuit |
| POST | /baskets | Create a basket |
| PUT | /baskets/{id} | Update a basket |
| DELETE | /baskets/{id} | Delete a basket |
| PATCH | /circuits/{id}/positions | Save canvas basket positions |
| PUT | /transitions/{from}/{to} | Configure transition (actions, conditions) |
| GET | /circuits/{id}/messages | List messages of a circuit |
| POST | /circuits/{id}/messages | Create a message |
| PUT | /circuits/{id}/messages/{mid} | Update a message |
| DELETE | /circuits/{id}/messages/{mid} | Delete a message |
| GET | /circuits/{id}/export | Export circuit as JSON |
| POST | /circuits/import | Import circuit from JSON file |
License
MIT
