How to search for ListX in global search?

Currently global search can search for a specific record, but I also want it to also search the List pages as I have too many resources types, May I know how to achieve that? So that things like ListUsers will appear in global search, I see it in pxlrbt/filament-spotlight but I would prefer not to use a package. Especially when spotlight v1 is no longer maintained Thanks!
30 Replies
Dennis Koch
Dennis Koch16mo ago
I don't think that's possible.
pocket.racer
pocket.racer16mo ago
I see it in ur package in which u claim it uses filament global search behind the scenes
this plugin relies on the same properties and methods used for Filament's global search
pocket.racer
pocket.racer16mo ago
We see a Discounts - List there
Dennis Koch
Dennis Koch16mo ago
It uses the global search data for searching the records. But the root elements List/Edit/Create/View are collected by the package
pocket.racer
pocket.racer16mo ago
Ah okay, would u all consider adding support for this to core filament in the future? As some of us have many Models
Dennis Koch
Dennis Koch16mo ago
Not sure. @Dan Harrin What's your opinion on this?
pocket.racer
pocket.racer16mo ago
i happen to have purchased Spotlight v2 some time ago too but not too sure how to integrate that with filament admin
Dennis Koch
Dennis Koch16mo ago
but I would prefer not to use a package. Especially when spotlight v1 is no longer maintained
I thought about building my own v2 as a Paid Plugin. Not sure if it's worth it though
pocket.racer
pocket.racer16mo ago
Maybe something can be worked out with @philonl
Dennis Koch
Dennis Koch16mo ago
I already talked to him. v2 wouldn't be that convenient. You need to buy Spotlight v2 separately, integrate that via Composer and then install a package that connects it to Filament
Unknown User
Unknown User16mo ago
Message Not Public
Sign In & Join Server To View
pocket.racer
pocket.racer16mo ago
i already bought (wire element pros) months ago but haven't use it in any projects yet. I'm not an expert filament user so find it quite intimidating on how do i get started with integrating spotlight v2 with filament admin
Dennis Koch
Dennis Koch16mo ago
If the process didn't change too much, you could use my package as a baseline.
pocket.racer
pocket.racer16mo ago
Alternatively would it be easier for me to extend filament core global search to support searching ListX Pages instead? It seems doable if I write my own GlobalSearchProvider https://github.com/filamentphp/filament/blob/2.x/packages/admin/src/GlobalSearch/DefaultGlobalSearchProvider.php But not sure how to get filament to use my GlobalSearchProvider instead of Filament own one
Dennis Koch
Dennis Koch16mo ago
I guess you need to swap it out via the Laravel Container. But I didn't look into this yet
pocket.racer
pocket.racer16mo ago
I traced to FilamentManager.php and saw this line https://github.com/filamentphp/filament/blob/2.x/packages/admin/src/FilamentManager.php protected string $globalSearchProvider = DefaultGlobalSearchProvider::class; Then I search for usage of FilamentManager.php and saw this in FilamentServiceProvider
$this->app->scoped('filament', function (): FilamentManager {
return new FilamentManager();
});
$this->app->scoped('filament', function (): FilamentManager {
return new FilamentManager();
});
I see that it is a Scoped Singleton but i'm not sure how do I swap it with My Filament Manager which reference my own GlobalSearchProvider https://laravel.com/docs/10.x/container#binding-scoped Do i just do this in my own AppServiceProvider register() method?
$this->app->scoped('filament', function (): FilamentManager {
return new MyFilamentManager();
});
$this->app->scoped('filament', function (): FilamentManager {
return new MyFilamentManager();
});
Would this be enough to override and have my app use my FilamentManager which reference my GlobalSearchServiceProvider instead of Filament own 1? ah okay there is this globalSearchProvider(string $provider) method maybe i try call that in the boot method Will let u all know again if it work for me, but if global search ListX Pages can be supported in filament admin core itself it would be great!
Dan Harrin
Dan Harrin16mo ago
I guess you can return custom global search results from the resource and link one to the list page of a resource
pocket.racer
pocket.racer16mo ago
Currently I did it this way (not working yet). Didn't see ur message before this attempt MyOwnFilamentServiceProvider
public function boot(FilamentManager $filamentManager): void
{
$filamentManager->globalSearchProvider(AdminGlobalSearchProvider::class);
}
public function boot(FilamentManager $filamentManager): void
{
$filamentManager->globalSearchProvider(AdminGlobalSearchProvider::class);
}
And my AdminGlobalSearchProvider
<?php

namespace App\Filament\GlobalSearch;

use Filament\Facades\Filament;
use Filament\GlobalSearch\DefaultGlobalSearchProvider;
use Filament\GlobalSearch\GlobalSearchResult;
use Filament\GlobalSearch\GlobalSearchResults;

class AdminGlobalSearchProvider extends DefaultGlobalSearchProvider
{
public function getResults(string $query): ?GlobalSearchResults
{
$builder = parent::getResults($query);

$pageSearchResults = [];
ray('did not show up in ray');

// code adapted from https://github.com/pxlrbt/filament-spotlight/blob/main/src/Actions/RegisterPages.php
foreach (Filament::getPages() as $page) {
ray('did not show up in ray either');

$name = \Livewire\invade(new $page())->getTitle();
$url = $page::getUrl();

if (blank($name) || blank($url)) {
continue;
}

$pageSearchResults[] = new GlobalSearchResult($name, $url);
}

$builder->category('Pages', $pageSearchResults);

return $builder;
}
}
<?php

namespace App\Filament\GlobalSearch;

use Filament\Facades\Filament;
use Filament\GlobalSearch\DefaultGlobalSearchProvider;
use Filament\GlobalSearch\GlobalSearchResult;
use Filament\GlobalSearch\GlobalSearchResults;

class AdminGlobalSearchProvider extends DefaultGlobalSearchProvider
{
public function getResults(string $query): ?GlobalSearchResults
{
$builder = parent::getResults($query);

$pageSearchResults = [];
ray('did not show up in ray');

// code adapted from https://github.com/pxlrbt/filament-spotlight/blob/main/src/Actions/RegisterPages.php
foreach (Filament::getPages() as $page) {
ray('did not show up in ray either');

$name = \Livewire\invade(new $page())->getTitle();
$url = $page::getUrl();

if (blank($name) || blank($url)) {
continue;
}

$pageSearchResults[] = new GlobalSearchResult($name, $url);
}

$builder->category('Pages', $pageSearchResults);

return $builder;
}
}
Dan Harrin
Dan Harrin16mo ago
cool
pocket.racer
pocket.racer16mo ago
But it doesn't work 😭
Dan Harrin
Dan Harrin16mo ago
i dont think the boot() bit is right
pocket.racer
pocket.racer16mo ago
Hmm so i should do app(FilamentManager::class) ? since FilamentManager is a scoped singleton Having FilamentManager at boot() didn't throw any error, other than the search still did not show the pages
Dan Harrin
Dan Harrin16mo ago
i think you can just call Filament::globalSearchProvider(AdminGlobalSearchProvider::class); as a facade
pocket.racer
pocket.racer16mo ago
hmm ok let me try
Dan Harrin
Dan Harrin16mo ago
also is the service provider registered
pocket.racer
pocket.racer16mo ago
yup service provider is registered. Ok using Filament::globalSearchProvider(AdminGlobalSearchProvider::class); works But the pages returned in the search results are the dashboard pages, not the Resource pages like ListUsers
Dan Harrin
Dan Harrin16mo ago
right but you still need to loop through resources as we do in the default provider resource pages arent registered in the same way you just call ResourceName::getUrl() to generate the URL
pocket.racer
pocket.racer16mo ago
Thanks it sort of worked! here is my code, feel free to improve & add to core if u want
class AdminGlobalSearchProvider extends DefaultGlobalSearchProvider
{
public function getResults(string $query): ?GlobalSearchResults
{
$builder = parent::getResults($query);

// Dashboard Pages
$dashboardPageSearchResults = [];

// code adapted from https://github.com/pxlrbt/filament-spotlight/blob/main/src/Actions/RegisterPages.php
foreach (Filament::getPages() as $page) {
$name = \Livewire\invade(new $page())->getTitle();
$url = $page::getUrl();

if (blank($name) || blank($url)) {
continue;
}

// prob need some permissions check here too

// A primitive search filter
// strtolower() because str_contains is case-sensitive
if (str_contains($name, $query)) {
$dashboardPageSearchResults[] = new GlobalSearchResult($name, $url);
}
}

$builder->category('Dashboard Pages', $dashboardPageSearchResults);

// Resource Pages
$resourceListPageResults = [];
foreach (Filament::getResources() as $resource) {

// prob need to tighten the permissions check more here
if (! $resource::canGloballySearch()) {
continue;
}

$modelPluralLabel = $resource::getPluralModelLabel();

// A primitive search filter
// strtolower() because str_contains is case-sensitive
if (str_contains($modelPluralLabel, strtolower($query))) {
$resourceListPageResults[] = new GlobalSearchResult(
'List ' . $modelPluralLabel,
$resource::getUrl()
);
}
}

$builder->category('Resource Pages', $resourceListPageResults);

return $builder;
}
}
class AdminGlobalSearchProvider extends DefaultGlobalSearchProvider
{
public function getResults(string $query): ?GlobalSearchResults
{
$builder = parent::getResults($query);

// Dashboard Pages
$dashboardPageSearchResults = [];

// code adapted from https://github.com/pxlrbt/filament-spotlight/blob/main/src/Actions/RegisterPages.php
foreach (Filament::getPages() as $page) {
$name = \Livewire\invade(new $page())->getTitle();
$url = $page::getUrl();

if (blank($name) || blank($url)) {
continue;
}

// prob need some permissions check here too

// A primitive search filter
// strtolower() because str_contains is case-sensitive
if (str_contains($name, $query)) {
$dashboardPageSearchResults[] = new GlobalSearchResult($name, $url);
}
}

$builder->category('Dashboard Pages', $dashboardPageSearchResults);

// Resource Pages
$resourceListPageResults = [];
foreach (Filament::getResources() as $resource) {

// prob need to tighten the permissions check more here
if (! $resource::canGloballySearch()) {
continue;
}

$modelPluralLabel = $resource::getPluralModelLabel();

// A primitive search filter
// strtolower() because str_contains is case-sensitive
if (str_contains($modelPluralLabel, strtolower($query))) {
$resourceListPageResults[] = new GlobalSearchResult(
'List ' . $modelPluralLabel,
$resource::getUrl()
);
}
}

$builder->category('Resource Pages', $resourceListPageResults);

return $builder;
}
}
Dan Harrin
Dan Harrin16mo ago
could be a plugin? :) but a PR would be good to enable these results optionally
pocket.racer
pocket.racer16mo ago
I still prefer to keep my github username private for now so... if anyone wants to make a PR to enable it feel free to take credit for it 🙂 Thanks a lot!