F
Filament2mo 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
Jakub2mo 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
toeknee2mo 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
Jakub2mo 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
Jakub2mo ago
No description
Jakub
Jakub2mo 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
Jakub2mo ago
No description
Jakub
Jakub2mo 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
More Posts