Action Notifikasi
Action notifikasi adalah tombol pada notifikasi yang tersimpan, seperti "Download", "Download failed rows", atau "View order". Action ini berupa label dan URL, bukan nama action yang perlu di-resolve. Gunakan ketika notifikasi mengarahkan pengguna untuk membuka sesuatu.
Contoh minimal yang berfungsi
<?php
use PandaPanel\Notifications\Notification;
use PandaPanel\Notifications\NotificationAction;
Notification::make('export-ready')
->title('Your export is ready')
->success()
->persistent()
->actions([
NotificationAction::make('download')
->label('Download')
->url('/admin/exports/users.csv'),
])
->send($user);2
3
4
5
6
7
8
9
10
11
12
13
14
15
Bell sekarang menampilkan notifikasi dengan tombol Download. Ketika ditekan, notifikasi ditandai sudah dibaca lalu browser melakukan navigasi.
Mengapa ini bukan Action
PandaPanel\Actions\Action di-resolve terhadap schema yang mendeklarasikannya — table, form, atau infolist. Notifikasi tidak memiliki schema. Notifikasi adalah sebuah row pada table yang mungkin masih ada minggu depan, jauh setelah page yang mengirimkannya sudah tidak ada lagi, dan schema yang dahulu dapat me-resolve nama action tersebut mungkin juga sudah tidak tersedia.
Karena itu, yang dikirim adalah link yang dibuat oleh server, sama seperti URL pada link action. Apa pun tujuan link tersebut harus melakukan authorization untuk dirinya sendiri ketika dibuka. Itulah pemeriksaan yang masih dapat dipercaya bahkan seminggu kemudian.
Konsekuensi praktisnya:
| Tidak didukung | Mengapa | Gunakan ini sebagai gantinya |
|---|---|---|
| Closure untuk dijalankan | tidak ada executable code yang boleh dikirim | arahkan URL ke route yang melakukan pekerjaan tersebut |
| Modal konfirmasi | tidak ada schema tempat modal dapat dibuka | lakukan konfirmasi pada page tujuan URL |
| Form | alasan yang sama | page tujuan yang merender form |
| Callback visibility atau authorization | kapan callback harus dievaluasi? row dapat hidup lebih lama daripada request | putuskan sebelum mengirim; lakukan authorization pada URL tujuan |
Semua method pada NotificationAction
PandaPanel\Notifications\NotificationAction bersifat final, dan setiap setter mengembalikan self.
| Method | Signature | Default |
|---|---|---|
make | static make(string $name): self | — |
label | label(string $label): self | Str::headline($name) |
url | url(string $url, bool $newTab = false): self | null |
variant | variant(ActionVariant $variant): self | ActionVariant::Outline |
markAsRead | markAsRead(bool $mark = true): self | true |
getName | getName(): string | — |
toArray | toArray(): array | — |
fromArray | static fromArray(array $data): ?array | — |
use PandaPanel\Actions\Enums\ActionVariant;
use PandaPanel\Notifications\NotificationAction;
// The label falls back to the headline of the name.
NotificationAction::make('failed-rows')->toArray()['label']; // 'Failed Rows'
// A second tab, for a file the user should keep the panel open behind.
NotificationAction::make('report')
->label('Open report')
->url('/admin/imports/failed-rows.csv', newTab: true);
// A destructive-looking button, for a notification that leads somewhere final.
NotificationAction::make('review')
->label('Review')
->url('/admin/orders/42')
->variant(ActionVariant::Destructive);
// Leave it unread — for an action the user may take several times.
NotificationAction::make('retry')
->label('Retry')
->url('/admin/exports/retry/42')
->markAsRead(false);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
url(string $url, bool $newTab = false)
URL dan perilaku tab diatur dalam satu pemanggilan karena keduanya merupakan satu keputusan. URL diperlukan agar tombol memiliki tujuan. URL relatif serta scheme http, https, mailto, dan tel dipertahankan; scheme yang tidak aman disimpan sebagai null, dan frontend menerapkan guard yang sama sebelum membuka action.
Bangun URL menggunakan route() daripada menulisnya secara manual, dan gunakan absolute: false agar row tetap valid ketika hostname berubah:
use PandaPanel\Core\PanelManager;
$panel = app(PanelManager::class)->currentPanel();
NotificationAction::make('download')
->label('Download')
->url(route($panel->routeName('export-file'), [
'file' => $result['file'],
'exporter' => $exporter,
], absolute: false));2
3
4
5
6
7
8
9
10
variant(ActionVariant $variant)
PandaPanel\Actions\Enums\ActionVariant menggunakan closed set yang sama seperti bagian Panel lainnya, karena setiap case dipetakan ke variant tombol shadcn di frontend:
| Case | Value |
|---|---|
ActionVariant::Default | default |
ActionVariant::Secondary | secondary |
ActionVariant::Outline | outline (default di sini) |
ActionVariant::Ghost | ghost |
ActionVariant::Destructive | destructive |
markAsRead(bool $mark = true)
Aktif secara default: notifikasi yang sudah ditindaklanjuti berarti sudah dilihat. Membiarkannya tetap unread membuat counter bertahan lebih lama daripada hal yang dihitungnya. Frontend menghormati nilai ini sebelum melakukan navigasi:
if (action.markAsRead) {
await markRead(item.id);
}2
3
Bentuk data yang disimpan
toArray() menghasilkan data yang masuk ke kolom data dan yang dikembalikan oleh notification center:
[
'name' => 'download',
'label' => 'Download',
'url' => '/admin/exports/users.csv',
'variant' => 'outline',
'markAsRead' => true,
'newTab' => false,
]2
3
4
5
6
7
8
Membaca kembali action yang tersimpan
public static function fromArray(array $data): ?arrayPanelNotificationController memanggil method ini untuk setiap item pada array actions yang tersimpan. Notifikasi persisten adalah JSON di database, sehingga data yang dibaca kembali harus dianggap tidak tepercaya seperti request body:
| Data tersimpan | Hasil |
|---|---|
name atau label hilang, atau bukan string | null — action dibuang dan tidak dirender |
url hilang, kosong, atau bukan string | url: null |
variant bukan salah satu dari lima nilai yang valid | outline |
markAsRead bukan literal true | false |
newTab bukan literal true | false |
use PandaPanel\Notifications\NotificationAction;
NotificationAction::fromArray(['name' => 'a', 'label' => 'A', 'variant' => 'chartreuse']);
// ['name' => 'a', 'label' => 'A', 'url' => null, 'variant' => 'outline',
// 'markAsRead' => true, 'newTab' => false]
NotificationAction::fromArray(['label' => 'A']); // null2
3
4
5
6
7
Perhatikan asimetri yang sengaja dibuat agar strict pada bagian penting namun tetap toleran pada bagian yang tidak berbahaya: markAsRead default ke true ketika tidak tersedia, tetapi nilai yang bukan literal true dibaca sebagai false.
Cara Panel menggunakannya
Kedua queued job bawaan package memasang tepat satu action, dan keduanya layak dijadikan pola.
RunPanelExport — file adalah tujuan utama notifikasinya:
Notification::make('export-ready')
->title($exporter::completedMessage($result['records']))
->success()
->icon('download')
->persistent()
->actions([
NotificationAction::make('download')
->label('Download')
->url(route($panel->routeName('export-file'), [
'file' => $result['file'],
'exporter' => $exporter,
], absolute: false)),
])
->send($user);2
3
4
5
6
7
8
9
10
11
12
13
14
RunPanelImport — failure report dibawa bersama notifikasi sehingga pengguna tidak perlu mencarinya:
if ($result['report'] !== null) {
$notification->actions([
NotificationAction::make('failed-rows')
->label('Download failed rows')
->url(route($panel->routeName('import-file'), [
'file' => $result['report'],
'importer' => $importer,
], absolute: false)),
]);
}2
3
4
5
6
7
8
9
10
Kedua URL mengarah ke controller yang membangun directory berdasarkan pengguna yang sedang meminta file, sehingga hanya file milik pengguna tersebut yang dapat diakses. Polanya sederhana: link tetaplah link, dan authorization dilakukan oleh destination.
Hal yang perlu diperhatikan
- Action tidak pernah muncul pada toast. Client toast membaca
urldanurlLabel, sedangkanNotification::toArray()tidak menghasilkan keduanya. Notifikasi yang memiliki actions tetapi tidak memakaipersistent()akan menampilkan toast tanpa tombol dan tidak meninggalkan apa pun. Untuk toast yang dapat diklik, dispatchPandaPanel\Broadcasting\PanelNotificationdengan$urldan$urlLabel. actions()mengganti daftar sebelumnya, bukan menambahkan.Notification::actions()memanggilarray_values()pada array yang diberikan; memanggilnya dua kali hanya mempertahankan daftar kedua.- URL relatif lebih aman. Row mungkin dibaca dari host berbeda dibanding saat dibuat — misalnya queued job pada worker atau aplikasi yang tersedia melalui dua domain.
absolute: falsemembuat URL tetap valid. - Nama tidak divalidasi. Berbeda dengan
Action::make(),NotificationAction::make()menerima string apa pun karena nama tersebut tidak pernah dikirim kembali ke route, sehingga tidak ada hal yang perlu dibatasi. - Dead link tetap menjadi dead link. File export yang sudah dibersihkan tetap memiliki notifikasinya. Tentukan berapa lama file disimpan, lalu bersihkan notifikasi lama dengan kebijakan yang selaras.
Lihat juga
- Database notifications — tempat action disimpan
- Notification center — bagaimana tombol dijalankan
- Toast notifications — dan mengapa tombol tidak berada di sana
- Actions overview — jenis action yang di-resolve melalui schema
- Import and export actions
- Queued notifications