Skip to content

hadyfayed/filament-workflow-canvas

Repository files navigation

Laravel Workflow Canvas

A visual workflow builder and canvas component for Laravel applications. Built on top of the React Wrapper package, providing a drag-and-drop interface for creating complex workflows.

Features

  • 🎨 Visual Workflow Builder - Drag-and-drop interface for building workflows
  • 🔗 Node-based System - Trigger, Condition, Transform, and Analytics nodes
  • 📊 Real-time Preview - Live workflow execution preview
  • 💾 Auto-save - Automatic saving of workflow changes
  • 🔄 State Management - Advanced state management with persistence
  • 🎯 Type Safe - Full TypeScript support
  • 🖥️ Fullscreen Mode - Expandable canvas for complex workflows
  • 🔍 Validation - Built-in workflow validation and error detection
  • 📱 Responsive - Works on desktop and tablet devices

Installation

Option 1: Using as Distributed Packages (Recommended)

composer require hadyfayed/filament-workflow-canvas
npm install @hadyfayed/filament-workflow-canvas

Dependencies:

This package requires the React Wrapper v3.1.0+ as a base:

composer require hadyfayed/filament-react-wrapper:"^3.1.0"
npm install @hadyfayed/filament-react-wrapper@"^3.1.0"

Option 2: Using as Local Development Packages

# Copy package files to your resources directory
cp -r packages/react-wrapper/resources/js/* resources/js/react-wrapper/
cp -r packages/workflow-canvas/resources/js/* resources/js/workflow-canvas/

Setup

Publish the configuration files:

php artisan vendor:publish --tag=workflow-canvas-config

Publish the assets:

php artisan vendor:publish --tag=workflow-canvas-assets

Run the migrations:

php artisan migrate

✨ No Plugin Registration Required!

React Wrapper v3.1.0+ provides direct Filament integration:

  • No plugin registration needed in your Filament panel
  • Components work directly with Filament forms and resources
  • Automatic asset loading and dependency management
  • Just install the packages and start using the components!

Vite Configuration (Standard Laravel Approach)

// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
                'resources/js/bootstrap-react.tsx'
            ],
            refresh: true,
        }),
        react(),
    ],
    resolve: {
        alias: {
            '@': '/resources/js',
        },
    },
});

Bootstrap Configuration

For distributed packages:

// resources/js/bootstrap-react.tsx
import React from 'react';

// Initialize the React wrapper core system
import '@hadyfayed/filament-react-wrapper/bootstrap';

// Initialize workflow canvas components
import '@hadyfayed/filament-workflow-canvas/bootstrap';

console.log('React Wrapper and Workflow Canvas bootstrapped for Filament integration');

export default function bootstrap() {
    return true;
}

For local development:

// resources/js/bootstrap-react.tsx
import React from 'react';

// Initialize the React wrapper core system
import './react-wrapper/core';

// Initialize workflow canvas components
import './workflow-canvas/index';

console.log('React Wrapper and Workflow Canvas bootstrapped for Filament integration');

export default function bootstrap() {
    return true;
}

Basic Usage

Blade Component

<x-workflow-canvas::workflow-canvas 
    :workflow="$workflow"
    :readonly="false"
    height="600px"
    state-path="workflow.canvas_data"
/>

Livewire Integration

use HadyFayed\WorkflowCanvas\Models\Workflow;

class WorkflowBuilder extends Component
{
    public Workflow $workflow;
    public array $canvasData = [];
    
    public function mount(Workflow $workflow)
    {
        $this->workflow = $workflow;
        $this->canvasData = $workflow->canvas_data ?? [];
    }
    
    public function updatedCanvasData()
    {
        $this->workflow->update(['canvas_data' => $this->canvasData]);
    }
    
    public function render()
    {
        return view('livewire.workflow-builder');
    }
}
<!-- livewire.workflow-builder.blade.php -->
<div>
    <x-workflow-canvas::workflow-canvas 
        :workflow="$workflow"
        state-path="canvasData"
    />
</div>

Filament Integration (React Wrapper v3.1.0+ Direct Integration)

Form Field Integration

use HadyFayed\WorkflowCanvas\Forms\Components\WorkflowCanvasField;

// In your Filament Resource
WorkflowCanvasField::make('canvas_data')
    ->reactive()           // Enable real-time React-PHP state sync
    ->lazy()              // Load component when visible (performance optimization)
    ->enableAutoSave()    // Auto-save workflow changes
    ->showMinimap()       // Show workflow minimap
    ->enableFullscreen()  // Allow fullscreen editing
    ->nodeTypes(config('workflow-canvas.node_types'))
    ->onWorkflowChange(fn($state) => $this->processWorkflow($state));

Widget Integration

use HadyFayed\WorkflowCanvas\Widgets\WorkflowStatsWidget;

// In your Filament Panel
class WorkflowStatsWidget extends ReactWidget
{
    protected string $componentName = 'WorkflowStatsWidget';
    
    public function getData(): array
    {
        return $this->getWorkflowStats(); // Data automatically shared with React
    }
}

No Plugin Required!

React Wrapper v3.1.0+ provides direct Filament integration without requiring plugin registration:

  • Components work directly with Filament forms and resources
  • Lazy loading and asset management handled automatically
  • 90%+ React-PHP function mapping for seamless integration

Node Types

The package comes with four built-in node types:

Trigger Nodes

  • Entry points for workflows
  • Support event, webhook, schedule, and manual triggers
  • Configuration options for event types and filters

Condition Nodes

  • Filter data based on configurable conditions
  • Support multiple operators (equals, contains, exists, etc.)
  • AND/OR logic for multiple conditions

Transform Nodes

  • Modify and map data between workflow steps
  • Support field mapping, JavaScript code, and templates
  • Built-in transformations (uppercase, lowercase, hash, base64)

Analytics Driver Nodes

  • Send data to analytics platforms
  • Support for GA4, Meta Pixel, Mixpanel, and more
  • Configurable async processing and error handling

Configuration

Customize the workflow canvas in config/workflow-canvas.php:

return [
    'canvas' => [
        'default_height' => '600px',
        'fullscreen_enabled' => true,
        'auto_save' => true,
        'auto_save_delay' => 500,
    ],
    
    'node_types' => [
        'trigger' => [
            'label' => 'Trigger',
            'icon' => '',
            'color' => 'blue',
            'processor' => TriggerProcessor::class,
        ],
        // ... more node types
    ],
    
    'validation' => [
        'max_nodes' => 100,
        'max_connections' => 200,
        'required_trigger' => true,
        'prevent_cycles' => true,
    ],
];

Custom Node Types

Create custom node types by extending the base processor:

use HadyFayed\WorkflowCanvas\Processors\BaseNodeProcessor;

class CustomProcessor extends BaseNodeProcessor
{
    public function process(mixed $node, array $inputData, WorkflowExecution $execution): array
    {
        // Your custom processing logic
        return $outputData;
    }
    
    public function getConfigSchema(): array
    {
        return [
            'custom_field' => [
                'type' => 'text',
                'label' => 'Custom Field',
                'required' => true,
            ],
        ];
    }
}

Register the custom node type:

// config/workflow-canvas.php
'node_types' => [
    'custom' => [
        'label' => 'Custom Node',
        'icon' => '',
        'color' => 'purple',
        'processor' => CustomProcessor::class,
    ],
],

Workflow Execution

Execute workflows programmatically:

use HadyFayed\WorkflowCanvas\Services\WorkflowExecutionService;

$executionService = app(WorkflowExecutionService::class);
$result = $executionService->execute($workflow, $inputData);

if ($result->isSuccessful()) {
    $outputData = $result->getOutputData();
} else {
    $errors = $result->getErrors();
}

Events

The package dispatches several events during workflow execution:

use HadyFayed\WorkflowCanvas\Events\WorkflowStarted;
use HadyFayed\WorkflowCanvas\Events\WorkflowCompleted;
use HadyFayed\WorkflowCanvas\Events\WorkflowFailed;

// Listen for workflow events
Event::listen(WorkflowStarted::class, function ($event) {
    Log::info('Workflow started', ['workflow_id' => $event->workflow->id]);
});

API Reference

Workflow Model

$workflow = Workflow::create([
    'name' => 'My Workflow',
    'description' => 'A sample workflow',
    'canvas_data' => $canvasData,
    'is_active' => true,
]);

// Validate workflow structure
$errors = $workflow->validate();

// Duplicate workflow
$copy = $workflow->duplicate('New Name');

// Check for cycles
$hasCycles = $workflow->hasCycles();

Canvas Component Props

WorkflowCanvasComponent::make(
    workflow: $workflow,
    readonly: false,
    height: '800px',
    statePath: 'canvas_data'
)

Development

Package Development

When developing the packages locally:

# In the package directory
cd packages/workflow-canvas
npm install
npm run build  # Build distributable package

# Copy to main app for testing
cd ../../
cp -r packages/workflow-canvas/resources/js/* resources/js/workflow-canvas/

TypeScript Compilation

# Check types in package
cd packages/workflow-canvas
npm run typecheck

# Build with type declarations
npm run build

Main App Development

# Start development server
npm run dev

# Build for production
npm run build

Testing

# Package tests
cd packages/workflow-canvas
composer test
npm test

# Main app tests
cd ../../
php artisan test

Custom Node Development

Create custom nodes by extending the base components:

// resources/js/components/CustomNode.tsx
import React from 'react';
import { NodeProps } from 'reactflow';

export default function CustomNode({ data }: NodeProps) {
    return (
        <div className="custom-node">
            <h3>{data.label}</h3>
            {/* Your custom UI */}
        </div>
    );
}

Register the custom node:

// resources/js/bootstrap-react.tsx
import { componentRegistry } from './react-wrapper/core';
import CustomNode from './components/CustomNode';

componentRegistry.register({
    name: 'CustomNode',
    component: CustomNode,
    metadata: {
        category: 'custom',
        description: 'Custom workflow node'
    }
});

License

MIT License. See LICENSE for details.

About

No description, website, or topics provided.

Resources

License

MIT, MIT licenses found

Licenses found

MIT
LICENSE
MIT
LICENSE.md

Stars

Watchers

Forks

Packages

 
 
 

Contributors