Filament UI
Alpha notice:
dbflowlabs/filamentis in active alpha. Page slugs, config keys, and permission names may change between tags. Pin exact tags in production (for example0.1.0-alpha.1@alpha).
DBFlow Filament is the Standard operational UI layer for workflow administration. It runs on top of dbflowlabs/core and gives operators a Filament-native way to work with tasks, instances, and definitions.
DBFlow Filament operates workflows. DBFlow Pro (dbflowlabs/filament-pro) designs workflows visually. Pro is Early Access / Preview — see Pro Visual Builder and Preview Limitations. Standard UI details are below.
Filament UI is only half of an integration. You still need Core runtime setup: migrations, user resolution, workflow definitions (code or UI), assignee resolvers, sync, and host business triggers (
DBFlow::start()). Complete the Host Integration Checklist first.
Security: The package ships with
AllowAllPermissionCheckerby default. Replacepermission_checker_classinconfig/dbflow-filament.phpbefore any shared or production environment — otherwise every authenticated panel user can access workflow pages and approve/reject tasks.
What you get
After DBFlowFilamentPanel::register($panel), the package exposes:
| Surface | Class | Default URL (panel path admin) |
|---|---|---|
| My Workflow Tasks | MyWorkflowTasks |
/admin/dbflow/my-workflow-tasks |
| Workflow Instances | WorkflowInstances |
/admin/dbflow/workflow-instances |
| Instance detail | ViewWorkflowInstance |
/admin/dbflow/workflow-instances/{record} |
| Workflow definitions | WorkflowResource |
/admin/workflows |
Routing notes:
- Package pages use
{panel_path}/{route_prefix}/…. Defaultroute_prefixisdbflow(config('dbflow-filament.route_prefix')). WorkflowResourceis a normal Filament resource registered at the panel root — its slug isworkflows, not under thedbflowprefix.- Named routes use
route_name_prefix(defaultdbflow.filament.). - If your panel path is empty (
->path('')), My Tasks becomes/dbflow/my-workflow-tasks.
The package does not auto-register pages during boot(). You must call DBFlowFilamentPanel::register($panel) from your PanelProvider (or register pageClasses() / resourceClasses() manually).
Install
composer require "dbflowlabs/filament:0.1.0-alpha.1@alpha" "dbflowlabs/core:^0.1.0-alpha.1@alpha"
If your project already allows alpha stability, you may omit @alpha.
php artisan vendor:publish --tag=dbflow-filament-config
php artisan migrate
dbflowlabs/core is required and installs automatically as a dependency.
Two configuration files
| Config file | Primary switch | What it controls |
|---|---|---|
config/dbflow.php |
enabled |
Core runtime feature flag (provider still boots during alpha) |
config/dbflow-filament.php |
enabled |
Whether registered Filament pages/resources are exposed |
DBFlowFilamentPanel checks dbflow-filament.enabled and panel_registration_mode. It does not read dbflow.enabled.
Hosts that want a single product feature flag should gate both configs (and panel registration) in application code:
if ($this->shouldRegisterDbflow()) {
return DBFlowFilamentPanel::register($panel);
}
Typical pattern: wrap registration on config('dbflow.enabled') and a host pilot flag, not only dbflow-filament.enabled.
Register the panel
Call DBFlowFilamentPanel::register() inside your PanelProvider. This is the supported integration — do not use a separate Filament plugin class.
<?php
namespace App\Providers\Filament;
use DbflowLabs\Filament\Support\DBFlowFilamentPanel;
use Filament\Panel;
use Filament\PanelProvider;
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
$panel = $panel
->id('admin')
->path('admin')
// ... your existing panel configuration
;
if ($this->shouldRegisterDbflow()) {
return DBFlowFilamentPanel::register($panel);
}
return $panel;
}
private function shouldRegisterDbflow(): bool
{
return (bool) config('dbflow-filament.enabled', true)
&& (bool) config('dbflow.enabled', true);
// Hosts often add a product pilot flag here as well.
}
}
DBFlowFilamentPanel reads config/dbflow-filament.php to decide which pages and resources to attach. Set panel_registration_mode to disabled if you prefer manual registration via DBFlowFilamentPanel::pageClasses() and resourceClasses().
Feature toggles
| Config key | Env (optional) | Default | Purpose |
|---|---|---|---|
enabled |
DBFLOW_FILAMENT_ENABLED |
true |
Master Filament package toggle |
panel_registration_mode |
DBFLOW_FILAMENT_PANEL_REGISTRATION |
explicit |
explicit or disabled |
enable_my_tasks_page |
DBFLOW_FILAMENT_MY_TASKS |
true |
My Workflow Tasks page |
enable_my_task_actions |
DBFLOW_FILAMENT_MY_TASK_ACTIONS |
true |
Approve/reject on tasks page |
enable_workflow_instances_page |
DBFLOW_FILAMENT_INSTANCES |
true |
Instance list + detail |
enable_workflow_definition_resource |
DBFLOW_FILAMENT_DEFINITIONS |
true |
Workflow Definition resource |
enable_logs_timeline |
DBFLOW_FILAMENT_LOGS_TIMELINE |
true |
Audit timeline on instance detail |
require_reject_note |
DBFLOW_FILAMENT_REQUIRE_REJECT_NOTE |
true |
Require note when rejecting from tasks UI |
reject_strategy |
DBFLOW_FILAMENT_REJECT_STRATEGY |
end |
Core RejectTask strategy from My Tasks |
Example .env:
DBFLOW_FILAMENT_ENABLED=true
DBFLOW_FILAMENT_MY_TASKS=true
DBFLOW_FILAMENT_INSTANCES=true
DBFLOW_FILAMENT_DEFINITIONS=true
DBFLOW_FILAMENT_LOGS_TIMELINE=true
DBFLOW_FILAMENT_REJECT_STRATEGY=end
You can substitute custom page classes — for example view_workflow_instance_page_class — when you need host-specific layouts. The dbflow-demo project uses DemoViewWorkflowInstance for a friendlier instance detail page.
Extension contracts
Hosts customize presentation and authorization by binding class strings in config/dbflow-filament.php (*_class keys). Prefer class bindings over legacy callables (permission_checker, workflowable_label_resolver, status_badge_mapper).
| Contract | Config key | Purpose |
|---|---|---|
PermissionChecker |
permission_checker_class |
Gate package pages, resources, and table actions |
WorkflowableLabelResolver |
workflowable_label_resolver_class |
Human-readable labels for workflowable records |
UserDisplayResolver |
user_display_resolver_class |
Actor names in tables and timelines |
UserAssigneeOptionsResolver |
user_assignee_options_resolver_class |
User picker options in definition editors |
PermissionAssigneeOptionsResolver |
permission_assignee_options_resolver_class |
Labels for permission/callback assignee keys in editors |
StatusBadgeMapper |
status_badge_mapper_class |
Badge color/label for workflow statuses |
WorkflowDefinitionEditorResolver |
workflow_definition_editor_resolver |
Replace the standard linear editor (Pro uses this hook) |
Default permission_checker_class is DbflowLabs\Filament\Support\AllowAllPermissionChecker — replace it in every non-local environment.
Permission abilities
Ability strings are configured under permissions in config/dbflow-filament.php. WorkflowFilamentPermissions resolves them before calling PermissionChecker::can().
Default ability names:
dbflow.tasks.view
dbflow.tasks.approve
dbflow.tasks.reject
dbflow.workflow_instances.view
dbflow.workflow_instances.view_any
dbflow.definitions.view
dbflow.definitions.create
dbflow.definitions.update
dbflow.definitions.delete
dbflow.definitions.validate
dbflow.definitions.publish
dbflow.definitions.disable
dbflow.definitions.enable
dbflow.definitions.archive
dbflow.definitions.copy
dbflow.tasks.view is required for the My Workflow Tasks navigation item. If navigation is missing but direct URLs work, check your PermissionChecker mapping first.
Permission assignees vs Core resolvers
| Layer | API | Purpose |
|---|---|---|
| Filament definition editor | PermissionAssigneeOptionsResolver |
Human-readable labels for assignee keys authors can pick |
| Core runtime | DBFlow::registerAssigneeResolver($key, …) |
Resolves user IDs when a workflow runs |
For assignees.type: permission (or callback), the JSON value / callback must match the same registry key you register in Core — it is not a Spatie permission string or Laravel Gate ability. See Code-defined Workflows.
Runtime approval identity still flows through Core's UserResolver (config/dbflow.php). Filament contracts are display and admin UX only.
Host model links
Implement DbflowLabs\Core\Contracts\WorkflowRouteResolvable on workflowable models so instance and task tables can link back to your Filament resource:
public function getWorkflowShowUrl(): ?string
{
return PurchaseOrderResource::getUrl('edit', ['record' => $this]);
}
My Tasks actions
The My Tasks table uses MyWorkflowTaskTableActions, which delegates to MyWorkflowTaskActionRunner. That runner calls Core's ApproveTask and RejectTask actions — the same runtime entrypoints as DBFlow::approve() and DBFlow::reject().
Reject strategy on the My Tasks page defaults to config('dbflow-filament.reject_strategy') (commonly end → RejectStrategy::End).
Workflow definitions resource
WorkflowResource manages draft definitions stored in dbflow_workflows / dbflow_workflow_versions. The Standard linear editor ships with the package. Pro may replace the editor through workflow_definition_editor_resolver when installed.
Code-synced workflows and the definition editor
WorkflowResource::definitionEditorSection() is visible only when Workflow::hasDraft() is true.
| How the workflow was created | Draft state after sync |
|---|---|
| Created via WorkflowResource → Create | Draft exists (CreateWorkflowDraft) — editor shows |
Synced from WorkflowDefinitionProvider |
Published version exists, no draft — edit page metadata only, no node editor |
SyncWorkflowDefinitions writes published versions; it does not populate draft_definition. This is a common “sync succeeded but the edit form is empty” surprise.
Host options:
- Seed a draft after sync (recommended for code-first pilots that still want the Standard editor):
use DbflowLabs\Core\Actions\SaveWorkflowDraft;
use DbflowLabs\Core\Models\Workflow;
$workflow = Workflow::query()->where('key', 'your_workflow_key')->first();
if ($workflow && ! $workflow->hasDraft() && $workflow->hasPublishedVersion()) {
$definition = $workflow->currentDefinition();
$definition['key'] = $workflow->key;
$definition['name'] = $workflow->name;
app(SaveWorkflowDraft::class)->handle($workflow, $definition);
}
Run this after SyncWorkflowDefinitions::handle() in boot, deploy, or your own Artisan command. Skip workflows with source = ui or workflows that already have a draft.
-
Disable the definition resource (
enable_workflow_definition_resource = false) when definitions are owned entirely by code or Pro. -
Treat UI edits as ops-only — publishing from Filament creates a new version; code sync behaviour for
source = codevssource = uidiffers. Document ownership for your team before operators publish from the UI.
Customize navigation
// config/dbflow-filament.php
'navigation_group' => 'Workflow',
'navigation_sort' => [
'my_tasks' => 10,
'workflow_instances' => 20,
'workflow_definitions' => 25,
],
Optional should_register_navigation callable gates all package navigation items for the current user.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| No Workflow navigation group | Panel not registered or Filament disabled | DBFlowFilamentPanel::register(), dbflow-filament.enabled, panel_registration_mode !== disabled |
| Navigation missing but routes work | Permission mapping | PermissionChecker must allow dbflow.tasks.view |
| Empty task list after submit | Assignee resolution | Resolver registered? Returns user IDs? Current user in assignee set? |
Unknown assignee resolver on start |
Missing Core registration | DBFlow::registerAssigneeResolver() for each permission / callback key |
| 404 on package page URLs | Panel path mismatch | Compare {panel_path}/{route_prefix}/… with Panel::path() |
| Definition edit page has no node form | No draft after code sync | Seed draft with SaveWorkflowDraft or create via WorkflowResource |
| Everyone can approve | Default permission checker | Replace AllowAllPermissionChecker |
| UI works but actions fail | Core auth / runtime | DBFLOW_AUTH_MODEL, assignee IDs; Filament does not gate on dbflow.enabled |
End-to-end Filament checklist
- Install Core + Filament alpha packages; run migrations.
- Publish
dbflow-filament-config; setpermission_checker_class(not allow-all). - Register
DBFlowFilamentPanel::register($panel)behind host feature flags. - Register providers, resolvers, hooks; run
SyncWorkflowDefinitions. - If using the definition editor for code workflows, seed drafts after sync (see above).
- Call
DBFlow::start()from host business actions; guard downstream operations. - Log in as assignee → My Workflow Tasks → approve or reject.
What's next
- Permissions → — authorization extension points and ability mapping
- Pro Visual Builder → — LogicFlow canvas preview (Early Access)
- Workflow Timeline → — audit trail presentation on instance detail
- Filament Resource Actions → — start workflows from your own resources
- Host Integration → — Core wiring, sync, assignees, guards
- Host Reference Patterns → — optional ERP-style integration patterns
- Refund Approval → — full end-to-end demo walkthrough