* fix broken Cropper.js documentation link
it seems the link changed with the Cropper.js update to v2 and they introduced a new website
Signed-off-by: Niklas Wildenburg <niklascanisius@me.com>
* Update FileUpload.php
---------
Signed-off-by: Niklas Wildenburg <niklascanisius@me.com>
Co-authored-by: Dan Harrin <git@danharrin.com>
* fix(actions): add batch-cancel early-return and failed() handler to ExportCsv and ImportCsv
Two pure additions on both row-processor jobs. No existing property
is touched; `$maxExceptions = 5`, `retryUntil()`, `backoff()`,
`middleware()`, and `tags()` delegation all preserved.
- `if ($this->batch()?->cancelled()) { return; }` at the top of
`handle()` so a batch cancelled via `Bus::findBatch($id)->cancel()`
stops in-flight chunks on the next worker cycle instead of running
every popped chunk to completion.
- `failed()` handler with scalar-only log context (`export_id` /
`import_id`, `page`, `batch_id`, exception class, exception
message). No secret leakage.
Tests:
- `{Export,Import}CsvBatchCancellationTest`: use
`withFakeBatch(cancelledAt: ...)` + Mockery
`shouldNotReceive('getAttribute')->with('user')` to prove the
early-return fires.
- `{Export,Import}CsvFailedHandlerTest`: call
`failed(new RuntimeException(...))` against `Log::shouldReceive('error')`
to pin the structured log context shape.
* fix(actions): add failed() + explicit $tries/$maxExceptions to three standalone jobs
These three jobs have never had retry properties set. The implicit
design is "inherit the worker default," which varies by platform:
`queue:work` uses 1, `vapor:work` signature says 0 but runtime
overrides to `SQS_TRIES ?? 3`, Horizon supervisor configs vary.
Make the intent explicit per each job's idempotency and runtime
profile.
PrepareCsvExport (Batchable orchestrator, non-idempotent):
`$tries = 1` (retry would re-dispatch children via `batch()->add()`),
`$maxExceptions = 0`, batch-cancel early-return, `failed()` handler.
No `$timeout`: work scales with source-query size, keep worker-
inherited timeout rather than cap at 60s.
ExportCompletion (not Batchable, non-idempotent notifier):
`$tries = 1` (retry would double-notify), `$maxExceptions = 0`,
`failed()` handler. No `$timeout`: single `Notification::send()` or
`Notification::sendToDatabase()` call, sub-second runtime.
CreateXlsxFile (not Batchable, idempotent file converter):
`$tries = 3` (re-reads CSV chunks and overwrites same XLSX, so
transient failures recover), `$backoff = [30, 60, 300]` (avoids
0-second retry loop since `$tries > 1`), `$maxExceptions = 0`,
`failed()` handler. No `$timeout`: XLSX conversion runtime is
O(row count), large exports need worker-inherited timeout (Vapor
Lambda ceiling, Horizon supervisor) rather than 60s cap.
None of these three delegate `retryUntil()`, so `$tries` is the
active attempts bound. Public API unchanged.
* Remove tests (too brittle)
* Remove failed() hooks (too opinionated)
* cs
---------
Co-authored-by: Dan Harrin <git@danharrin.com>
* fix: prevent invalid notification id handling in notification actions
* refactor: use Str::isUuid for notification id validation
* test: cover database notification id handling
* fix: validate notification id as UUID before performing database actions
* feat: add ->size() support to Filament\Schemas\Components\Icon
* cleanup
* docs
* improve ss
---------
Co-authored-by: Dan Harrin <git@danharrin.com>
* feat: expose TipTap/ProseMirror globals for custom extensions
Custom extensions loaded via RichContentPlugin::getTipTapJsExtensions()
are fetched at runtime via dynamic import(). Each extension bundle must
currently include its own copy of TipTap/ProseMirror, leading to:
- Duplicate ProseMirror instances on the page
- instanceof checks failing across bundles (e.g. DecorationSet)
- ~150-200 KB of redundant JS per extension
This adds window.Filament.TipTap with the core ProseMirror modules
(@tiptap/core, @tiptap/pm/state, @tiptap/pm/view, @tiptap/pm/model)
already bundled in rich-editor.js. Custom extension builds can mark
@tiptap/* as external and resolve from this global at runtime,
sharing the same ProseMirror instance as the host editor.
Non-breaking: existing extensions that bundle their own TipTap
continue to work unchanged.
* Discard changes to packages/forms/dist/components/rich-editor.js
* chore: fix code style
* clean up & docs
---------
Co-authored-by: leek <leek@users.noreply.github.com>
Co-authored-by: Dan Harrin <git@danharrin.com>
* Add openableUrl support for file uploads
Include server-provided openable URLs in uploaded file metadata and use them for the file open action. JS: add uploadedFile.metadata to the file options and prefer metadata.openableUrl (falling back to file.source) when generating the open link. PHP: introduce a getOpenableUrlUsing closure property and setter, and populate metadata.openableUrl for each stored file by evaluating the callback. This enables customizable/signed URLs or alternate domains for opening uploaded files.
* chore: fix code style
* Add downloadable URL support for file uploads
Support custom downloadable URLs for uploaded files. Backend: add a getDownloadableUrlUsing callback and property on BaseFileUpload, populate metadata.downloadableUrl when isDownloadable() and the callback is set, and ensure openable URL generation checks isOpenable(). Frontend: prefer metadata.downloadableUrl for the download anchor href (fallback to file.source behavior removed). This enables serving custom download links separate from the file source.
* Format conditionals in BaseFileUpload
Remove an extra blank line and standardize conditional formatting in BaseFileUpload: add consistent spacing and braces for the openable/downloadable URL checks and tidy up the getDownloadableUrlUsing method. Purely stylistic changes with no functional impact.
* run composer cs
* clean up
---------
Co-authored-by: Abdulmajeed-Jamaan <Abdulmajeed-Jamaan@users.noreply.github.com>
Co-authored-by: Dan Harrin <git@danharrin.com>
* feat: add deferred badge loading for relation manager tabs
Extends the deferred tab badge loading introduced in PR #19336 to
relation manager tabs, fixing two upstream issues:
1. `RelationManager::getTabComponent()` was evaluating `getBadge()`
eagerly before the deferred mechanism could intercept it.
2. `HasRelationManagers::getRelationManagersContentComponent()` built
`Tabs::make()` with no key, causing `callSchemaComponentMethod()` to
receive null when the async badge fetch fired.
Changes:
- Add `protected static bool $deferBadge = false` to `RelationManager`
with an overrideable `isBadgeDeferred()` method for per-record control
- Add fluent `->deferBadge()` and `isBadgeDeferred()` to `RelationGroup`
- Add `->key('relationManagerTabs')` to the `Tabs` built in
`HasRelationManagers`
- Add docs and tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* cleanup
---------
Co-authored-by: buzkall <buzkall@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Dan Harrin <git@danharrin.com>
Added missing Persian translations for the export column selection actions
in the Filament actions export language file.
The following keys were missing in the `fa` locale:
- actions.select_all
- actions.deselect_all
These translations ensure the column selection controls in the export
modal are properly localized for Persian users.
Signed-off-by: Amirhossein <amirhosseinzangali@gmail.com>
* improve: add Set/Get reactive snippet, table filters, edit test, and relationship mistake
Added examples for reactive field mutation and computed column values. Updated guidelines for using SelectFilter and actions with modal forms.
Signed-off-by: Rupesh Shrestha <46959961+rupeshstha@users.noreply.github.com>
* Revise core guidelines for forms and layouts
Updated guidelines for reactive field mutation and layout components.
Signed-off-by: Rupesh Shrestha <46959961+rupeshstha@users.noreply.github.com>
* condense
---------
Signed-off-by: Rupesh Shrestha <46959961+rupeshstha@users.noreply.github.com>
Co-authored-by: Dan Harrin <git@danharrin.com>