F
Filament7mo ago
Jakub

Looking for advice: Creating custom page with multiple tabs + resource tables

What am I trying to do?
Create a custom page that will display some tables for multiple resources. Similar to how you can have a relationship and on the ViewModel page have multiple tabs that just show the has many relationships with unique tables. I am looking to do the same thing, but with not having a relationship to anything specific.
Why am I trying to do this?
Creating a project management dashboard, and would like to have the first place I view act like a global inbox. Would like to have tabs for - submitted tasks for view - submitted time records for approval - client workspaces that are about to expire - tasks with unread messages or events
What do I need help with?
Honestly just need some direction on how to go about this, I don't need the full answer. Any advice is appreciated. I keep going through the docs and got most of the dashboard finished, but genuinely blanking on how to go about this. This is my first filament app, and I probably started it 4-5 times from scratch this year haha Trying to avoid creating a full custom livewire page, wondering if there is a way to use the really nice filament approach to make such a custom page.
No description
8 Replies
Jakub
JakubOP7mo ago
If this is something way to advanced for somone new to filament to do (5 months experiance) please let me know as well, so i can try other solutions. If I am over my heado n this I created a screenshot of what i want, just takign a screenshot of a relationsimp manager from workspace and adding it on the inbox page. That's really alli want to setup
<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;

class Inbox extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-inbox';

protected static string $view = 'filament.pages.inbox';
}
<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;

class Inbox extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-inbox';

protected static string $view = 'filament.pages.inbox';
}
If it helps lol fresh page created again
toeknee
toeknee7mo ago
In theory surely you can use a filament form, which loads in custom livewire components each one being a table? So you build the tabs and the tab fields would be a view which renders the livewire component?
Jakub
JakubOP7mo ago
🤔 im going to tinker with that now I just tried making a INboxResource thinking i could get around that lol and add relationships to it
Jakub
JakubOP7mo ago
No description
Jakub
JakubOP7mo ago
@toeknee this actually worked out pretty well, thanks bud
<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;
use Filament\Infolists\Infolist;
use Filament\Infolists\Components\Tabs;
use Filament\Infolists\Components\Livewire;
use App\Livewire\Agency\Inbox\ActiveTasksTable;

class Inbox extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-inbox';

protected static string $view = 'filament.pages.inbox';

public function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
Tabs::make('Tabs')
->tabs([
Tabs\Tab::make('active-tasks')->label('Active Tasks')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table')
]),
Tabs\Tab::make('Tab 2')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-2')->lazy()
]),
Tabs\Tab::make('Tab 3')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-3')->lazy()
]),
]),
]);
}
}
<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;
use Filament\Infolists\Infolist;
use Filament\Infolists\Components\Tabs;
use Filament\Infolists\Components\Livewire;
use App\Livewire\Agency\Inbox\ActiveTasksTable;

class Inbox extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-inbox';

protected static string $view = 'filament.pages.inbox';

public function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
Tabs::make('Tabs')
->tabs([
Tabs\Tab::make('active-tasks')->label('Active Tasks')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table')
]),
Tabs\Tab::make('Tab 2')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-2')->lazy()
]),
Tabs\Tab::make('Tab 3')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-3')->lazy()
]),
]),
]);
}
}
Trying it out with infolsits if it had any diffrences, trying to get the regular tabs style
Solution
Jakub
JakubOP7mo ago
No description
Jakub
JakubOP7mo ago
inbox page
<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;
use Filament\Infolists\Infolist;
use Filament\Infolists\Components\Tabs;
use Filament\Infolists\Components\Livewire;
use App\Livewire\Agency\Inbox\ActiveTasksTable;
use Filament\Resources\Components\Tab;

class Inbox extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-inbox';

protected static string $view = 'filament.pages.inbox';

public function getTabs(): array
{
return [
'All' => Tab::make('All')->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table')
]),
];
}

public function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
Tabs::make('Tabs')->contained(false)
->tabs([
Tabs\Tab::make('active-tasks')->label('Active Tasks')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table')
]),
Tabs\Tab::make('Tab 2')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-2')->lazy()
]),
Tabs\Tab::make('Tab 3')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-3')->lazy()
]),
]),
]);
}
}
<?php

namespace App\Filament\Pages;

use Filament\Pages\Page;
use Filament\Infolists\Infolist;
use Filament\Infolists\Components\Tabs;
use Filament\Infolists\Components\Livewire;
use App\Livewire\Agency\Inbox\ActiveTasksTable;
use Filament\Resources\Components\Tab;

class Inbox extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-inbox';

protected static string $view = 'filament.pages.inbox';

public function getTabs(): array
{
return [
'All' => Tab::make('All')->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table')
]),
];
}

public function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
Tabs::make('Tabs')->contained(false)
->tabs([
Tabs\Tab::make('active-tasks')->label('Active Tasks')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table')
]),
Tabs\Tab::make('Tab 2')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-2')->lazy()
]),
Tabs\Tab::make('Tab 3')
->schema([
Livewire::make(ActiveTasksTable::class)->key('active-tasks-table-3')->lazy()
]),
]),
]);
}
}
Inbox blade
<x-filament-panels::page>



{{ $this->infolist }}

</x-filament-panels::page>
<x-filament-panels::page>



{{ $this->infolist }}

</x-filament-panels::page>
active tasks table
<div>
{{ $this->table }}
</div>
<div>
{{ $this->table }}
</div>
<?php

namespace App\Livewire\Agency\Inbox;

use Filament\Forms;
use App\Models\Task;
use Filament\Tables;
use App\Enums\EStatus;
use Livewire\Component;
use Filament\Forms\Form;
use App\Models\Milestone;
use Filament\Tables\Table;
use App\Models\Shop\Product;
use Filament\Resources\Resource;
use Illuminate\Contracts\View\View;
use Filament\Forms\Contracts\HasForms;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Contracts\HasTable;
use Illuminate\Database\Eloquent\Builder;

use App\Filament\Resources\MilestoneResource;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Tables\Concerns\InteractsWithTable;
use App\Filament\Resources\MilestoneResource\Pages;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use App\Filament\Resources\MilestoneResource\RelationManagers;

class ActiveTasksTable extends Component implements HasForms, HasTable
{
use InteractsWithTable;
use InteractsWithForms;

public static function table(Table $table): Table
{
return $table
->query(Milestone::query())
->columns([
Tables\Columns\TextColumn::make('name')
->searchable(),
Tables\Columns\TextColumn::make('project.name')
->searchable(),
Tables\Columns\TextColumn::make('status')
->sortable(),
Tables\Columns\TextColumn::make('priority')
->sortable(),
])
->recordUrl(fn (Milestone $record): string => MilestoneResource::getUrl('view', ['record' => $record->id]))
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
// Tables\Actions\ViewAction::make(),
// Tables\Actions\EditAction::make(),
// Tables\Actions\ViewAction::make()->url(fn (Milestone $record) => MilestoneResource::getUrl('view', ['record' => $record->id]))

])
->headerActions([
Tables\Actions\CreateAction::make()
->mutateFormDataUsing(fn (array $data): array => Milestone::mutateFormDataBeforeCreate($data))
->visible(url()->current() != MilestoneResource::getUrl('index')),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}


public function render()
{
return view('livewire.agency.inbox.active-tasks-table');
}
}
<?php

namespace App\Livewire\Agency\Inbox;

use Filament\Forms;
use App\Models\Task;
use Filament\Tables;
use App\Enums\EStatus;
use Livewire\Component;
use Filament\Forms\Form;
use App\Models\Milestone;
use Filament\Tables\Table;
use App\Models\Shop\Product;
use Filament\Resources\Resource;
use Illuminate\Contracts\View\View;
use Filament\Forms\Contracts\HasForms;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Contracts\HasTable;
use Illuminate\Database\Eloquent\Builder;

use App\Filament\Resources\MilestoneResource;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Tables\Concerns\InteractsWithTable;
use App\Filament\Resources\MilestoneResource\Pages;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use App\Filament\Resources\MilestoneResource\RelationManagers;

class ActiveTasksTable extends Component implements HasForms, HasTable
{
use InteractsWithTable;
use InteractsWithForms;

public static function table(Table $table): Table
{
return $table
->query(Milestone::query())
->columns([
Tables\Columns\TextColumn::make('name')
->searchable(),
Tables\Columns\TextColumn::make('project.name')
->searchable(),
Tables\Columns\TextColumn::make('status')
->sortable(),
Tables\Columns\TextColumn::make('priority')
->sortable(),
])
->recordUrl(fn (Milestone $record): string => MilestoneResource::getUrl('view', ['record' => $record->id]))
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
// Tables\Actions\ViewAction::make(),
// Tables\Actions\EditAction::make(),
// Tables\Actions\ViewAction::make()->url(fn (Milestone $record) => MilestoneResource::getUrl('view', ['record' => $record->id]))

])
->headerActions([
Tables\Actions\CreateAction::make()
->mutateFormDataUsing(fn (array $data): array => Milestone::mutateFormDataBeforeCreate($data))
->visible(url()->current() != MilestoneResource::getUrl('index')),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}


public function render()
{
return view('livewire.agency.inbox.active-tasks-table');
}
}
@toeknee tytyty for the advice, i was so lost on this for to long lol Just somethign as simple as pointing that out helped so much haha
Want results from more Discord servers?
Add your server