yacoubalhaidari/organization-chart
Installation
composer require yacoubalhaidari/organization-chart
Publish the config (if needed):
php artisan vendor:publish --provider="YacoubAlhardari\OrganizationChart\OrganizationChartServiceProvider"
Basic Widget Registration Add the widget to a Filament panel or resource:
use YacoubAlhardari\OrganizationChart\Widgets\OrganizationChart;
OrganizationChart::make()
->heading('Company Hierarchy')
->data($this->getChartData()) // Your data source
->mount();
First Use Case
Fetch hierarchical data from your database (e.g., users with manager_id relationship):
public function getChartData()
{
return User::with('manager', 'subordinates')
->whereNull('manager_id')
->get()
->map(function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
'title' => $user->title,
'image' => $user->profile_photo_url,
'children' => $user->subordinates->map(fn($sub) => [
'id' => $sub->id,
'name' => $sub->name,
// ... nested structure
]),
];
});
}
id, name, and optional children keys.
[
'id' => '1',
'name' => 'CEO',
'children' => [
['id' => '2', 'name' => 'CTO', ...],
['id' => '3', 'name' => 'CFO', ...],
],
]
$data = User::whereNull('manager_id')->with('subordinates')->get()->toHierarchy();
Styling: Chain methods for visual tweaks:
OrganizationChart::make()
->heading('Team Structure')
->height('600px')
->orientation('vertical') // or 'horizontal'
->nodeWidth(150)
->nodeHeight(100)
->colors(['#4CAF50', '#2196F3', '#FFC107'])
->showImages(true)
->showTitles(true);
Interactivity:
->onNodeClick(fn($node) => redirect()->route('users.show', $node['id']))
->onNodeHover(fn($node) => toast()->success("Hovering on {$node['name']}"));
Panel Widget:
// app/Filament/Resources/UserResource.php
public static function getWidgets(): array
{
return [
OrganizationChart::make()
->query(fn() => User::whereNull('manager_id')->with('subordinates'))
->heading('Organization'),
];
}
Live Updates: Use Filament’s livewire or polling to refresh data:
OrganizationChart::make()
->pollingInterval('60') // Refresh every 60 seconds
->data(fn() => $this->getLiveData());
dd($this->getChartData()) to verify.id or name keys).php artisan filament:cache:clear
->data(fn() => $this->getPaginatedData(100)) // Load 100 nodes at a time
with() sparingly to avoid N+1 queries. Pre-load relationships:
User::with(['subordinates' => fn($q) => $q->with('subordinates')])->get();
->view('filament.organization-chart::custom-node', ['node' => $node])
->data(fn() => Http::get('https://api.example.com/hierarchy')->json())
// lang/en/filament-organization-chart.php
return [
'no_data' => 'No employees found in this department.',
];
'image' => Storage::disk('public')->url($user->profile_photo_path),
.filament-widgets-organization-chart { min-width: 1000px; }
^3.0). Check the package’s composer.json for constraints.How can I help you explore Laravel packages today?