koassi/filament-file-explorer
A Finder-style file explorer for Filament v4/v5, backed by Spatie Media Library over a folder tree. Includes icons, columns and detail views, keyboard navigation, drag and drop, trash, quotas, tags, versions and share links. Ships as a standalone panel page or form component, with a demo seeder to t...
A patch release. No API change — upgrade with composer update koassi/filament-file-explorer and, as always, php artisan filament:assets.
Both reports turned out to be the same defect twice: something evaluated later than the code meant to guard it.
Each page of a pair offers a header button to the other — the explorer page to the flat files table, and back. The URL was built inside the action's url() closure, and Filament evaluates that closure while rendering the header — long past the try/catch in getHeaderActions() that existed for exactly this case. So RouteNotFoundException came out of the middle of a Blade view:
Route [filament.admin.resources.projects.files-list] not defined.
That is not an exotic setup. filament-file-explorer:make-page --explorer and --list each generate one page of the pair, so it is one of the two documented ways to use the generator.
Three more sites had the same shape and are fixed with it:
| Page | Was |
|---|---|
FileExplorerPage |
a try/catch that could not fire — the reported bug |
FileExplorerFilesPage |
no guard at all, so --list alone crashed the same way |
StandaloneFileExplorerPage |
resolved in a closure; reachable with register_pages off |
StandaloneFileExplorerFilesPage |
resolved in a closure, no guard |
The URL is now resolved in getHeaderActions(), in one place shared by all four — InteractsWithFileExplorer::fileExplorerCompanionUrl(). The record-scoped pages ask getResource()::hasPage() first, which is the list the host actually registered rather than the router's; the catch behind it covers a page named in getPages() whose route was never built. No URL, no button.
filament-file-explorer:install reported a path that no longer existsERROR Can't locate path: <vendor/koassi/filament-file-explorer/src/../resources/dist>
->hasAssets() registers a publish group pointing at resources/dist, which this package stopped having when the JS and CSS began shipping from their sources. Laravel merges paths registered under one tag, so the images were published anyway and the only symptom was an error nobody could act on, in the middle of an install that had otherwise worked.
Four over the header actions, and one that walks every publish tag the package registers and asserts each path exists — the one that would have caught the stale reference the day it went stale.
One of those four was worthless when first written: toThrow(Throwable::class) does not assert what it reads as. Throwable is an interface, class_exists() is false for it, and Pest then treats the argument as a message to match, so the expectation passes whatever happens. It catches by hand now, and all four fail when their fix is reverted.
597 tests, 1573 assertions, and 56 in the JS harness.
The README is 100 lines instead of 817. The reference moved to a 29-page documentation site with a sidebar — koassiakakpo.github.io/filament-file-explorer — and seventeen screenshots run through it.
.gitattributes now export-ignores both the screenshots and the docs, so 8.4 MB of pictures stops reaching every vendor/ directory.
Full Changelog: https://github.com/KoassiAkakpo/filament-file-explorer/compare/v1.0.0...v1.0.1
The funnel in the toolbar narrows a listing to images, PDF, documents, spreadsheets, presentations, archives, audio or video. The entry toggles, and a bar above the listing names the active filter with a way out — a narrowed folder that simply looked empty, with nothing on screen saying why, would be a bug report.
Support\FileKinds owns both the list the menu offers and the predicate that matches it, so the menu cannot offer a kind the query ignores. It is applied before the window and before the counts, which is what makes "5 of 12" describe what the filter left and keeps a "load more" inside the filter rather than widening past it.
Matched on the stored mime type, never on the extension: extracting one is not portable across drivers and the filter has to run in SQL, and the mime type is the half worth trusting anyway. Only files are narrowed — a folder has no kind, and hiding folders would filter you into a room with no doors. The column view narrows every pane. The filter is not remembered across mounts, unlike the view mode and the sort.
This empties the pre-1.0 list: every decision the API freeze forced is settled and every feature planned alongside them has shipped. See ROADMAP.md.
Pre-1.0 still, so the public API may change between minor versions — but nothing structural is now expected to.
Full Changelog: https://github.com/KoassiAkakpo/filament-file-explorer/compare/v0.4.0...v0.5.0
Right-click a file and Share gives it a link that works with no account and no session. The dialog shows the link, when it expires, how many times it has been opened, and a button to stop sharing.
Gated on the share ability, which follows download for any authorizer
that does not answer it — the extensible ability set from v0.2.0 earning
its keep.
A public request has no authenticated user, so the two guards are split in time rather than both run at request time: the ability is checked when the link is made and the decision is recorded, and containment runs on every request against the root stored on the row. That is what makes a link die on its own — a file moved out of the scope it was shared from, trashed, or deleted stops being served with nothing to keep in step.
The route takes the token and nothing else, so a link cannot be edited into a link for another file or another rendition, and a bad token, an expired one, a revoked one and a missing file all answer 404 alike. Tokens are stored rather than signed, because revoking is the half of sharing that matters; revoking keeps the row, and FileShared / ShareRevoked fire like every other mutation.
Adds a shares table: run php artisan migrate.
Internally, two rules that must not drift now have one implementation each — ServesMediaFiles for the disk-and-conversion response, Support\MediaScope for the three-condition media containment check.
Pre-1.0 still: the public API may change between minor versions. See ROADMAP.md for what is left.
Full Changelog: https://github.com/KoassiAkakpo/filament-file-explorer/compare/v0.2.0...v0.3.0
Everything on the roadmap is done, including all six items originally parked after 1.0. Nothing structural is pending, which is what makes this the honest number rather than a date.
replace conflict policy keeps the last N instead of destroying what was there. Identity is a lineage minted once, which is why rename, move, copy and the trash needed no changes at all.post_max_size. Five ceilings stacked and the lowest won, so a promise of 50 MB delivered 2. They are now read in one place, and a slice transport covers the gap by ending where Livewire's own upload endpoint ends — same temporary file, same signed reference, so updatedFiles() is unchanged. Direct-to-storage was made to work at all: uploadMultiple throws outright on a remote temporary disk, so the upload button did nothing on an S3-configured host.Forms\Components\FileExplorerPicker, with ->kinds() to restrict what may be chosen, enforced from one SQL predicate in four places including the validation rule.file-explorer:demo command, and a finder that scrolls inside itself instead of growing the page.Everything a host app writes code against:
Contracts\FileExplorerAuthorizer, including the key set its abilities() returnsContracts\FileExplorerRootResolver and the optional ProvidesMultipleRoots / ResolvesExistingRootFilamentFileExplorerPlugin's fluent settersModels\Concerns\HasFileExplorer, and Models\Folder as the tree modelstubs/ generated from themStandaloneSettings precedence rulesdata-fe-items, data-fe-type, data-idAn ability added after this point is declared in Abilities::DERIVED and inherits from one that already existed, so the set can still grow without denying the action for every authorizer already written.
589 tests, 1561 assertions, and 56 in the JS harness.
Full Changelog: https://github.com/KoassiAkakpo/filament-file-explorer/compare/v0.5.0...v1.0.0
How can I help you explore Laravel packages today?