TR
Başlangıç

DataTable: tüm seçenekler

Bu sayfa DataTable'ın bütün metotlarını ve ayarlarını konu konu listeler. Adım adım anlatım için DataTable, çalışan örnekler için DataTable örnekleri sayfasına bakın.

Tablo sınıfı

Tablo, Acun\Ui\DataTable\DataTable sınıfını genişleten bir Livewire bileşenidir. Zorunlu metotlar yalnızca query() ve columns(); diğerleri isteğe bağlıdır.

Bu sayfadaki örnekler şu sipariş tablosunu kullanır:

namespace App\Livewire;

use Acun\Ui\DataTable\Actions\{BulkAction, ExportAction, RowAction, TableAction, UtilityAction};
use Acun\Ui\DataTable\Column;
use Acun\Ui\DataTable\DataTable;
use Acun\Ui\DataTable\Filter;
use App\Models\Order;
use Illuminate\Database\Eloquent\Builder;

final class OrdersTable extends DataTable
{
    public string $title = 'Siparişler';

    protected function query(): Builder
    {
        return Order::query();
    }

    protected function columns(): array
    {
        return [/* … */];
    }
}

Tablo sınıfına yazabileceğiniz metotlar:

Metot Ne yapar Bölüm
query() Listelenecek kayıtların sorgusu (zorunlu) Yetki ve güvenlik
columns() Sütunlar (zorunlu) Sütunlar
filters() Filtreler Filtreler
defaultSort() Açılıştaki sıra Sıralama
actions(), bulkActions() Satır ve toplu işlemler İşlemler
headerActions(), utilityActions() Araç çubuğu düğmeleri Araç çubuğu
exportActions() "Dışa aktar" menüsü Dışa aktarma
authorizeTable() Tabloyu kimin açabileceği Yetki ve güvenlik

Hızlı çalışması için

  • Sorgu her istekte veritabanında çalışır; tarayıcıya yalnızca açık sayfanın satırları gider. Model::all() ile bütün kayıtları alıp PHP'de süzmeyin.
  • Gerekirse query() içinde yalnızca gereken sütunları seçin (select()) ve ilişkileri önceden yükleyin (with()).
  • Sıralanan ve filtrelenen sütunlara veritabanında indeks ekleyin; paket migration dosyalarınızı değiştirmez. Arama sütunları $table->searchColumn() ile indeksiyle birlikte gelir.
  • Dışa aktarma tablonun kendi sorgusunu kullanır; arama, filtre ve sıralamayı ikinci kez yazmanız gerekmez.

Sütunlar

Sütunlar tablonun hangi alanları nasıl göstereceğini belirler. Her sütun Column::make('Başlık', 'alan') ile başlar:

Column::make('Sipariş no', 'number')->searchable()->sortable()->nowrap()->toggleable(false),
Column::make('Müşteri', 'customer_name')->searchable('contains')->view('admin.tables.cells.order-customer'),
Column::make('Şehir', 'city')->hidden()->priority(4),
Column::make('Tutar', 'amount')->renderUsing(fn (Order $order) => $order->formattedAmount())->align('right')->width('140px'),
Column::make('Sipariş tarihi', 'ordered_at')->dateTime()->sortable()->priority(3),

Sütun metotları

Metot Ne yapar Örnek
searchable() Arama kutusu bu sütunda arar (Arama) ->searchable('contains')
sortable() Başlığa tıklanınca sıralar ->sortable()
hidden() Başta gizlidir; sütun menüsünden açılır ->hidden()
toggleable(false) Hep görünür; sütun menüsünden kapatılamaz ->toggleable(false)
priority() Dar ekranda gizlenir (aşağıda) ->priority(3)
width() Sütun genişliği ->width('140px')
align() Hizalama: left, center ya da right ->align('right')
nowrap() Hücre tek satırda kalır ->nowrap()
wrap() Uzun metin alt satıra geçer, scrollX() tablosunda da ->wrap()->width('20rem')
money($para, $dil) Para biçimi; dil verilmezse sayfanın dili ->money('TRY')
number($ondalık) Sayı biçimi ->number(2)
date($biçim) Tarih; biçim verilmezse dilin kısa tarihi ->date('d.m.Y')
dateTime($biçim) Tarih ve saat ->dateTime()
boolean($evet, $hayır) Doğru/yanlış değeri yazıyla gösterir; varsayılan "Aktif" / "Pasif" ->boolean('Açık', 'Kapalı')
renderUsing() Hücre metnini sizin fonksiyonunuz üretir ->renderUsing(fn (Order $order) => …)
view() Hücreyi kendi Blade dosyanızla çizer ->view('admin.tables.cells.order-status')
exportable(false) Dışa aktarmada yer almaz (Dışa aktarma) ->exportable(false)
exportUsing() Dosyaya yazılan değeri değiştirir ->exportUsing(fn (Order $order) => $order->amount / 100)
  • renderUsing() fonksiyonu satırı, alanın değerini ve sütunu alır: fn ($row, $value, $column). Döndürdüğü metin HTML olarak yorumlanmaz, düz metin gösterilir. HTML gereken hücreler için view() kullanın.
  • date() ve dateTime() modelde tarih olarak tanımlanmamış değerleri de biçimlendirir (metin ya da Unix zaman damgası). Okunamayan değer olduğu gibi gösterilir.

Hücreyi kendi görünümünüzle çizmek

view() dosyası satırın modelini $row, sütunu $column değişkeniyle alır:

{{-- resources/views/admin/tables/cells/order-status.blade.php --}}
<acun:badge :variant="$row->status->variant()">{{ $row->status->label() }}</acun:badge>

Hücre içeriğine kendi arka plan rengini vermeyin; saydam bırakın. Sabit sütunlarda rengi paket verir (Sınırlar ve ipuçları).

Dar ekranda sütun gizlemek

Sütunlar varsayılan olarak priority(1) ile her ekranda görünür. Daha büyük bir değer, sütunu dar ekranda gizler:

Değer Ne zaman gizlenir
priority(1), priority(2) Hiçbir zaman
priority(3) 38rem (608 px) altında
priority(4) ve üstü 52rem (832 px) altında

Gizlenen sütunların değerini kullanıcı satır ayrıntılarıyla görür.

Satır ayrıntıları (+)

Satır ayrıntıları satırın başına bir (+) düğmesi koyar. Düğme satırın bütün sütunlarını "başlık: değer" olarak bir pencerede (modal) gösterir. Başta gizli sütunlar, sütun menüsünden kapatılanlar ve dar ekranda gizlenenler de listelenir.

protected function rowDetails(): ?string
{
    return 'responsive';   // 'always': her ekranda; null: kapalı (varsayılan)
}

// İsteğe bağlı: penceredeki sütunlar ve başlık
protected function rowDetailsColumns(): array
{
    return $this->resolvedColumns();   // varsayılan: bütün sütunlar
}

protected function rowDetailsTitle(Model $row): string
{
    return $row->number.' · '.$row->customer_name;   // varsayılan: ilk sütunun değeri
}
  • 'responsive' değerinde (+) yalnızca dar ekran yüzünden bir sütun gizliyken görünür.
  • Hücre biçimleri (view(), renderUsing(), money()…) pencerede de aynen kullanılır.
  • Pencere yalnızca tablonun query() sorgusundaki bir kaydı açar; başka bir hesabın kaydı açılamaz.

Sütun menüsü

Sütun menüsü kullanıcının sütunları açıp kapatmasını sağlar. Araç çubuğundaki düğmenin adı "Kolonlar"dır.

  • Menüde "Tümünü göster" ve "Varsayılana dön" vardır.
  • toggleable(false) sütunlar hep görünür; tarayıcıdan gizleme isteği gelse de sunucu reddeder.
  • Kullanıcının seçimi, varsayılandan farklıysa adres çubuğuna yazılır. Oturum boyunca hatırlanması için acun-ui.datatable.columns.persist değerini session yapın.
  • Menünün ne zaman görüneceği: Araç çubuğu.

Arama

Arama kutusu searchable() işaretli sütunlarda ve searchFields() alanlarında arar. Arama sunucuda yapılır ve Arama kılavuzundaki altyapıyı kullanır.

Arama sütunu

Her alan, veritabanının o alandan ürettiği ayrı bir arama sütununda aranır. Sütunun adı {alan}_search biçimindedir. Sütunu bir migration ile ekleyin:

Schema::table('orders', function (Blueprint $table) {
    $table->searchColumn('number');          // number_search + indeks
    $table->searchColumn('customer_name');   // customer_name_search + indeks
});

Arama sütununda Türkçe harfler ve büyük/küçük harf eşitlenmiştir. Bu yüzden her arama türünde "ayse" → "Ayşe", "ali" → "ALİ" ve "ALI", "ismail isik" → "İsmail Işık", "ÇAĞRI" → "çağrı" bulunur.

Arama türleri

Tür yalnızca terimin değerin neresinde olabileceğini belirler:

Tür Eşleşme İndeks
SearchMode::Prefix (varsayılan) Değer terimle başlar Kullanır
SearchMode::Exact Değer terime eşittir Kullanır
SearchMode::Contains Terim değerin herhangi bir yerindedir Kullanmaz; küçük tablolarda bilerek seçin
SearchMode::FullText Her sözcük, değerdeki bir sözcüğün başıdır MySQL'de kullanır

FullText MySQL'de FULLTEXT indeksini kullanır; arama sütununu $table->searchColumn('ad', fullText: true) ile ekleyin. Diğer veritabanlarında her sözcük Contains gibi aranır.

Türü sütunda verin. Metin olarak da yazılabilir: 'prefix', 'exact', 'contains', 'fulltext'.

use Acun\Ui\Search\SearchMode;

Column::make('Sipariş no', 'number')->searchable(),                         // number_search, baştan
Column::make('Müşteri', 'customer_name')->searchable(SearchMode::Contains),
Column::make('Müşteri', 'customer_name')->searchable('contains', column: 'customer_search'),

Son satır, birden çok alandan üretilmiş bir arama sütununu okur. Böyle bir sütunu migration'da $table->searchColumn(['customer_name', 'customer_email'], 'customer_search') ile ekleyin.

Sütun olmayan alanda aramak

Sütun olarak gösterilmeyen bir alanda da aramak için searchFields() metodunu yazın. Gizli bir sütun eklemeniz gerekmez:

use Acun\Ui\Search\SearchField;

protected function searchFields(): array
{
    return [...parent::searchFields(), SearchField::make('customer_email')];
}

Arama nasıl çalışır

  • Kutu, kullanıcı yazmayı bıraktıktan 400 ms sonra arar (acun-ui.datatable.search_debounce).
  • Aranan bütün alanlar sorguya tek bir gruplanmış "ya bu alan ya şu alan" koşulu olarak eklenir. Böylece query() içindeki koşullarınız bozulmaz.
  • Terimdeki % ve _ joker karakter değildir, düz metin olarak aranır: "50%" yalnızca "50%" içeren kayıtları bulur. Paket her LIKE koşuluna ESCAPE '!' ekler.
  • SQLite'ta baştan arama GLOB ile yapılır; orada da *, ? ve [ düz metindir. Davranış SQLite, MySQL, PostgreSQL ve SQL Server'da aynıdır.
  • Terimin en çok 200 karakteri ve 10 sözcüğü kullanılır (acun-ui.search.max_length, max_words).
  • Başka bir arama sürücüsü (ör. Meilisearch için kendi sürücünüz) için tabloda searchDriver() metodunu yazın ya da acun-ui.search.driver değerini değiştirin. Sütun tanımları değişmez. Bkz. Arama: sürücüler.
  • Arama kutusunu gizlemek ve içindeki yazıyı değiştirmek: Araç çubuğu.

Filtreler

Filtreler listeyi bir alana göre daraltır. filters() metodunda listelenir:

protected function filters(): array
{
    return [
        Filter::select('Kanal', 'channel')->options(OrderChannel::options())->inToolbar(),
        Filter::multiSelect('Durum', 'status')->options(OrderStatus::options())->inToolbar(),
        Filter::dateRange('Sipariş tarihi', 'ordered_at'),
        Filter::select('Şehir', 'city')->options(array_combine(Order::CITIES, Order::CITIES)),
    ];
}

Filtre türleri

Metot Ne yapar Örnek
Filter::text() Metin kutusu; değeri içeren kayıtları bulur Filter::text('Ürün', 'product')
Filter::select() Açılır liste; seçilen değere eşit kayıtlar Filter::select('Kanal', 'channel')->options([…])
Filter::multiSelect() Onay kutulu liste; seçilenlerden birine eşit kayıtlar Filter::multiSelect('Durum', 'status')->options([…])
Filter::boolean() Evet / Hayır seçimi Filter::boolean('Aktif', 'is_active')
Filter::date() Tek gün Filter::date('Gün', 'ordered_at')
Filter::dateRange() Başlangıç ve bitiş günü Filter::dateRange('Tarih', 'ordered_at')
Filter::number() Sayıya eşit kayıtlar Filter::number('Adet', 'quantity')
Filter::numberRange() En az ve en çok değer Filter::numberRange('Tutar', 'amount')
  • date ve dateRange gün olarak karşılaştırır. Tarih-saat sütunlarında seçilen günün tamamı, aralıkta bitiş gününün tamamı da dahildir.
  • boolean filtrede options() vermezseniz seçenekler "Evet" (1) ve "Hayır" (0) olur.
  • '0' gibi bir değer (ör. "Hayır") etkin filtre sayılır. Boş bir aralık sayılmaz.

Araç çubuğundaki filtreler

Filtreler varsayılan olarak "Filtreler" düğmesinin açtığı çekmecededir (drawer). Sık kullanılan birkaçını inToolbar() ile arama kutusunun altındaki satıra alın; orada hep görünürler.

  • Seçim filtreleri filtre adını her seçenekte gösterir: "Kanal: Web".
  • Çoklu seçim, onay kutulu bir açılır kutudur: "Durum: 2 seçili". Kutu işaretlerken kapanmaz.
  • Aralık filtreleri iki alan olarak çizilir.
  • Çekmece yalnızca araç çubuğunda olmayan filtreleri listeler. Hiç kalmazsa "Filtreler" düğmesi gösterilmez.
  • Düğmedeki sayı rozeti ve çekmecedeki "Temizle" yalnızca çekmecedeki filtreleri kapsar.
  • inDrawer() filtreyi açıkça çekmecede tutar (varsayılan davranış).

Kendi koşulunuz

Hazır karşılaştırma yetmezse koşulu applyUsing() ile kendiniz yazın. Fonksiyon sorguyu ve filtrenin değerini alır:

// Tutar lira olarak girilir, veritabanında kuruş olarak saklanır.
Filter::numberRange('Tutar (₺)', 'amount')->applyUsing(function (Builder $query, mixed $value): void {
    if (is_numeric($value['from'] ?? null)) {
        $query->where('amount', '>=', (int) round((float) $value['from'] * 100));
    }

    if (is_numeric($value['to'] ?? null)) {
        $query->where('amount', '<=', (int) round((float) $value['to'] * 100));
    }
}),

Etkin filtreleri saymak ve temizlemek

Metot Ne yapar Örnek
activeFilterCount() Etkin filtre sayısı $this->activeFilterCount()
activeFilterCount(toolbar: …) true: yalnızca araç çubuğundakiler; false: yalnızca çekmecedekiler $this->activeFilterCount(toolbar: false)
clearFilters() Filtreleri temizler; aynı toolbar: parametresini alır $this->clearFilters(toolbar: true)

Filtre rozeti ve boş durum mesajı activeFilterCount() sonucunu kullanır.

Sıralama

Sıralama, satırların hangi sütuna göre dizileceğini belirler. Yalnızca sortable() işaretli sütunlar sıralanabilir.

  • Başlığa ilk tıklama artan, ikinci tıklama azalan sıralar. Başka bir sütuna tıklamak artan sırayla başlar.
  • Tarayıcıdan gelen sütun adı yalnızca sortable() sütunlardan biriyse kullanılır (Yetki ve güvenlik).

Varsayılan sıra

Kullanıcı bir sütun seçene kadar geçerli sırayı defaultSort() verir:

protected function defaultSort(): ?array
{
    return ['field' => 'ordered_at', 'direction' => 'desc'];
}
  • Alanın sıralanabilir bir sütun olması gerekmez.
  • "Sıralamayı sıfırla" bu sıraya döner.
  • Varsayılan sıra adres çubuğuna yazılmaz; ?direction= yalnızca varsayılandan farklıysa görünür.

Eşit değerler

Sıralanan sütundan sonra aynı yönde modelin anahtarı (genellikle id) eklenir. Böylece eşit değerli satırlar sayfalar, imleçli sayfalama ve parça parça okunan dışa aktarmalar boyunca hep aynı sırada kalır. Gruplanmış (groupBy) bir sorguda bunu kapatın:

protected function sortTieBreaker(Builder $query): ?string
{
    return null;
}

İşlemler

İşlemler tabloya düğme ekler: araç çubuğuna, her satırın sonuna ve seçim çubuğuna. Her grup tablo sınıfında bir metottur. Hepsi isteğe bağlıdır ve varsayılan olarak boş liste döndürür.

Metot Sınıf Nerede
headerActions() Actions\TableAction Araç çubuğunun sağ ucu ("Yeni sipariş")
utilityActions() Actions\UtilityAction Yenile, sütun menüsü ve "⋮" menüsü
exportActions() Actions\ExportAction "Dışa aktar" menüsü
actions() Actions\RowAction Her satırın sonu
bulkActions() Actions\BulkAction Seçim çubuğu

Tarayıcı tarafı (tam ekran, kısayollar, kopyalama, yazdırma penceresi, onay pencereleri) PRO JavaScript dosyasındaki acunDataTable bileşenindedir. Uygulamanızın JS girişinde import '@acunsoft/acun-ui-pro'; satırı olmalıdır (JavaScript katmanları). PRO paketi güncellendiyse npm run build çalıştırın.

Tam örnek

final class OrdersTable extends DataTable
{
    protected function headerActions(): array
    {
        return [
            TableAction::make('create')->label('Yeni sipariş')->icon('plus')
                ->url(fn () => route('orders.create'))
                ->can('create', Order::class)
                ->shortcut('mod+shift+n'),

            TableAction::make('sync')->label('Senkronize et')->icon('arrow-path')->color('gray')
                ->action('syncOrders')                       // tablonun bir metodu
                ->confirm('Siparişler senkronize edilsin mi?', 'Senkronizasyon')
                ->loadingLabel('Senkronize ediliyor…')
                ->successMessage('Siparişler güncellendi.'),
        ];
    }

    protected function exportActions(): array
    {
        return [
            ExportAction::csv()->shortcut('mod+e'),
            ExportAction::pdf(),
            ExportAction::json()->can('export-json'),
            ExportAction::print(),
            ExportAction::copy(),
        ];
    }

    protected function utilityActions(): array
    {
        return [
            UtilityAction::refresh(),
            UtilityAction::columns(),
            UtilityAction::fullscreen(),
            UtilityAction::resetFilters(),
            UtilityAction::resetSorting(),
        ];
    }

    protected function bulkActions(): array
    {
        return [
            BulkAction::make('ship')->label('Kargoya ver')->icon('truck')
                ->action(fn (Builder $query) => $query->where('status', 'paid')->update(['status' => 'shipped']))
                ->successMessage(':count sipariş kargoya verildi.'),
            BulkAction::exportSelected('csv'),
            BulkAction::printSelected(),
            BulkAction::delete()->can('delete-any', Order::class)
                ->authorizeRow(fn (Order $order) => auth()->user()->can('delete', $order)),
        ];
    }

    protected function actions(): array
    {
        return [
            RowAction::view(fn (Order $order) => route('orders.show', $order)),
            RowAction::edit(fn (Order $order) => route('orders.edit', $order))->can('update'),
            RowAction::make('ship')->label('Kargoya ver')->icon('truck')
                ->visible(fn (Order $order) => $order->status === OrderStatus::Paid)
                ->action(fn (Order $order) => $order->update(['status' => OrderStatus::Shipped])),
            RowAction::delete()->can('delete'),
        ];
    }

    protected function syncOrders(): void
    {
        // …
    }
}

Ortak metotlar

Bütün işlem sınıfları TableAction üzerine kuruludur ve şu metotları paylaşır. make('ad') ile verilen ad bir grup içinde benzersiz olmalıdır. Ad harf, rakam, -, _, . ve : içerebilir.

Metot Ne yapar Örnek
label() Düğme yazısı; verilmezse addan üretilir ->label('Yeni sipariş')
icon() Yazının önündeki ikon (heroicons adı) ->icon('plus')
tooltip() Fareyle üzerine gelince görünen ipucu ->tooltip('Mağazayla eşitle')
iconOnly() Yalnızca ikon; yazı ipucu ve ekran okuyucu adı olur ->iconOnly()
color() Anlamsal renk (Düğmenin görünümü) ->color('gray')
variant() Doğrudan bir acun:button türü; color() değerinin önüne geçer ->variant('outline')
url() Bağlantı; yeni sekme için newTab: true ->url(fn () => route('orders.create'))
navigate() Bağlantıyı sayfayı yenilemeden açar (wire:navigate) ->navigate()
action() Çalışacak fonksiyon ya da tablonun bir metodunun adı ->action('syncOrders')
confirm($mesaj, $başlık, $düğme) Çalışmadan önce onay penceresi açar ->confirm('Emin misiniz?')
withoutConfirmation() Onayı kapatır ->withoutConfirmation()
visible(), hidden() Koşula göre gösterir ya da gizler ->visible(fn (Order $order) => …)
can($yetki, $argüman) Laravel yetki kontrolü (Gate::allows) ->can('update')
authorize() Başka bir yetki kontrolü; false dönerse işlem yoktur ->authorize(fn () => …)
disabled() Soluk çizilir ve çalışmaz ->disabled(fn (Order $order) => …)
shortcut() Klavye kısayolu (aşağıda) ->shortcut('mod+e')
loadingLabel() Çalışırken düğmede görünen yazı ->loadingLabel('Hazırlanıyor…')
successMessage() Bitince başarı bildirimi ->successMessage('Güncellendi.')
attributes() Ek HTML nitelikleri (test ya da analiz için) ->attributes(['data-test' => 'yeni'])
order() Sıra; küçük sayı önce çizilir ->order(10)
  • url() bir bağlantı çizer, action() sunucuda çalışır. İkisini birlikte vermeyin.
  • confirm() başlık ve düğme yazısı verilmezse işlemin etiketini kullanır. Satır işleminde mesaj bir fonksiyon olabilir: ->confirm(fn (Order $order) => "{$order->number} iptal edilsin mi?").
  • Görünmeyen ya da yetkisiz işlem çizilmez; tarayıcıdan çağrılırsa sunucu 403 döner. disabled() işlem soluk çizilir, çağrılırsa yine 403 döner.
  • Satır işleminde can() argümansız yazılırsa satırın kendisiyle sorulur: ->can('update') → Gate::allows('update', $order).
  • successMessage() içindeki :count toplu işlemde kayıt sayısıyla değişir.

İşlemin aldığı değerler

İşlem fonksiyonları ihtiyaç duydukları değeri adıyla ya da türüyle ister:

Parametre Ne verir Nerede
$table Tablo bileşeni Bütün işlemler
$row, $record ya da model türü (Order $order) Satırın modeli Satır işlemleri
$query ya da $builder Seçimle daraltılmış sorgu Toplu işlemler
$ids ya da $keys Seçili kayıtların anahtarları Toplu işlemler
$records Seçili modeller, parça parça okunur Toplu işlemler
$count Seçili kayıt sayısı Toplu işlemler

Türü yazılmamış parametreler sırayla doldurulur: satır işleminde satır ve tablo, toplu işlemde sorgu ve tablo. Başka bir sınıf türü istenirse Laravel'in servis kapsayıcısından gelir. Toplu işlemde yalnızca istenen değer hesaplanır.

Düğmenin görünümü

Her işlem bir acun:button olarak çizilir. Rengi color() ile anlamına göre verin; paket düğmenin yerine uygun türü seçer:

color() Başlık ve araç çubuğu Satır ve toplu işlem
verilmezse primary (başlık), white (araç çubuğu) soft
'primary' primary soft
'secondary' secondary soft-secondary
'gray' white (beyaz, çerçeveli) soft-secondary
'danger' danger soft-danger
'success' success soft-success
'warning' warning soft-warning
'info' info soft-info
'dark' dark soft

Belirli bir tür istiyorsanız variant() her şeyin önüne geçer:

TableAction::make('create')->label('Yeni sipariş')->icon('plus');                        // ana renk, dolu
TableAction::make('import')->label('İçe aktar')->icon('arrow-up-tray')->color('gray');  // beyaz, çerçeveli
TableAction::make('archive')->label('Arşivle')->variant('outline');
TableAction::make('sync')->label('Senkronize et')->icon('arrow-path')->iconOnly()->tooltip('Mağazayla eşitle');

İkon adları acun:icon bileşeninin heroicons adlarıdır: plus, arrow-path, arrow-down-tray, printer, truck, eye, pencil-square, trash… İşlem sınıfları yalnızca adı taşır.

Başlık işlemleri

Başlık işlemleri araç çubuğunun sağ ucundadır. Telefonda ilk başlık işlemi görünür kalır, diğerleri "İşlemler" paneline girer; en önemli düğmeyi ilk sıraya koyun.

protected function headerActions(): array
{
    return [
        // Bir sayfaya git
        TableAction::make('create')->label('Yeni sipariş')->icon('plus')
            ->url(route('orders.create'))
            ->shortcut('mod+shift+n'),

        // Yeni sekmede aç
        TableAction::make('report')->label('Aylık rapor')->icon('document-text')->color('gray')
            ->url(fn () => route('reports.monthly'), newTab: true),

        // Sayfadaki bir pencereyi aç (acun:modal ya da form penceresi)
        TableAction::make('quick-add')->label('Hızlı ekle')->icon('bolt')->color('gray')
            ->action(fn (self $table) => $table->dispatch('acun:modal:open', name: 'siparis-formu')),

        // Tablonun bir metodunu çalıştır, önce onay al
        TableAction::make('recalculate')->label('Yeniden hesapla')->icon('arrow-path')->color('gray')
            ->action('recalculateTotals')
            ->confirm('Sipariş toplamları yeniden hesaplansın mı?', 'Toplamları yeniden hesapla', 'Hesapla')
            ->loadingLabel('Hesaplanıyor…')
            ->successMessage('Toplamlar güncellendi.')
            ->can('recalculate', Order::class),
    ];
}

protected function recalculateTotals(): void
{
    // …
}

action('recalculateTotals') tablonun bir metodunu çalıştırır. Metot public ya da protected olabilir. Tarayıcı yalnızca işlemin adını gönderir; hangi metodun çalışacağını tablo belirler.

Satır işlemleri

Satır işlemleri her satırın sonundaki düğmelerdir:

protected function actions(): array
{
    return [
        RowAction::view(fn (Order $order) => route('orders.show', $order)),
        RowAction::edit(fn (Order $order) => route('orders.edit', $order))->can('update'),

        // Duruma göre görünen işlem
        RowAction::make('ship')->label('Kargoya ver')->icon('truck')->color('success')
            ->visible(fn (Order $order) => $order->status === OrderStatus::Paid)
            ->action(fn (Order $order) => $order->update(['status' => OrderStatus::Shipped]))
            ->successMessage('Sipariş kargoya verildi.'),

        // Sayfadaki bir paneli açan işlem
        RowAction::make('notes')->label('Notlar')->icon('chat-bubble-left-ellipsis')
            ->action(fn (Order $order, self $table) => $table->dispatch('show-order-notes', id: $order->id)),

        RowAction::delete()->can('delete'),
    ];
}
  • RowAction::view($adres) ve RowAction::edit($adres) bağlantıdır.
  • RowAction::delete() onay sorar, kaydı siler (model olayları çalışır) ve bildirim gösterir. Metnini değiştirmek için: ->confirm('Sipariş kalıcı olarak silinsin mi?')->successMessage('Sipariş silindi.').
  • İkonu olan satır işlemi ikon düğmesidir; etiketi ekran okuyucu adı ve ipucudur. İkonu yoksa etiketiyle küçük bir düğmedir.
  • Bir satırda üçten fazla işlem görünürse ilk ikisi düğme, gerisi "⋮" menüsündedir. Menü tablonun kaydırma kutusunda kesilmez.
  • visible(), can() ve disabled() her satır için ayrı değerlendirilir.

Seçim

Seçim, toplu işlemlerin hangi kayıtlarda çalışacağını belirler.

  • Başlıktaki onay kutusu aramaya ve filtrelere uyan bütün kayıtları, bütün sayfalarda seçer. Bir kısmı seçiliyken kutuda çizgi görünür; tekrar tıklamak seçimi temizler.
  • Yalnızca görünen sayfayı seçmesi için acun-ui.datatable.select_all değerini page yapın.
  • Sayfalar arasında gezinmek ve sayfa boyutunu değiştirmek seçimi silmez. Arama ya da filtre değişince seçim temizlenir.
  • Bütün kayıtlar seçiliyken görünen satırlar işaretli görünür. Bir satırın işareti kaldırılırsa o satır seçimden çıkar; toplu işlem "eşleşenler eksi işareti kaldırılanlar" üzerinde çalışır. Başlıktaki kutunun işareti kaldırılırsa seçim tamamen temizlenir.
  • Bütün kayıtlar seçiliyken binlerce anahtar tarayıcıya yazılmaz; işlem aynı sunucu sorgusunda çalışır.
  • Tek tek en çok 5.000 kayıt işaretlenebilir (acun-ui.datatable.selection.max_keys). "Bütün kayıtlar" seçiminde sınır yoktur.
  • Seçim varken tablonun üstünde seçim çubuğu (acun:selection-bar) görünür.

Toplu işlemler

Toplu işlemler seçim çubuğundaki düğmelerdir:

protected function bulkActions(): array
{
    return [
        BulkAction::make('approve')->label('Onayla')->icon('check')->color('success')
            ->action(fn (Builder $query) => $query->update(['status' => 'approved']))
            ->confirm('Seçili :count sipariş onaylansın mı?')
            ->successMessage(':count sipariş onaylandı.'),

        BulkAction::exportSelected('csv'),
        BulkAction::printSelected(),
        BulkAction::delete()->can('delete-any', Order::class),
    ];
}
  • :count onay ve başarı metinlerinde seçili kayıt sayısıyla değişir.
  • Toplu işlemler varsayılan olarak onay ister. Onay penceresi acun:confirmation-dialog bileşenidir; tarayıcının kendi onay kutusu kullanılmaz. withoutConfirmation() onayı kapatır.
  • İşlem bitince seçim temizlenir; keepSelection() seçimi korur.
  • Satır yetkisi için authorizeRow(): Yetki ve güvenlik.

Hazır toplu işlemler:

Metot Ne yapar Örnek
BulkAction::delete() Kayıtları tek tek siler; model olayları ve geçici silme (soft delete) çalışır BulkAction::delete()
BulkAction::exportSelected() Seçimi dosya olarak indirir: csv, json ya da kendi biçiminiz; pdf yazdırma sayfasını açar. Seçimi korur BulkAction::exportSelected('csv')
BulkAction::printSelected() Seçimi yazdırma sayfasında açar; seçimi korur BulkAction::printSelected()

Uygun olmayan kayıtları atlamak

Seçimdeki kayıtların yalnızca bir kısmı işleme uygun olabilir (ör. yalnızca ödenmiş siparişler kargoya verilir). O zaman sorguyu kendiniz daraltın ve sonucu bildirin:

BulkAction::make('ship')->label('Kargoya ver')->icon('truck')
    ->withoutConfirmation()
    ->action(function (Builder $query, int $count, self $table) {
        $shipped = (clone $query)->where('status', 'paid')->update(['status' => 'shipped']);
        $table->dispatch('toast', type: 'success', message: "{$shipped} sipariş kargoya verildi, ".($count - $shipped).' sipariş atlandı.');
    }),

authorizeRow() ise bir yetki kuralıdır: seçimdeki kayıtlardan biri bile geçemezse hiçbir kayda dokunulmaz (403). İş kuralları için yukarıdaki kalıbı, yetki için authorizeRow() kullanın.

Klavye kısayolları

shortcut('mod+e') işleme bir klavye kısayolu verir. mod Windows ve Linux'ta Ctrl, macOS'ta ⌘ tuşudur.

  • Kısayol menüde ve ipucunda gösterilir. Bir alana yazı yazılırken çalışmaz.
  • Değiştirici tuşlar: mod, ctrl, meta, alt, shift. Son tuş bir harf, rakam ya da işaret, f1–f12, enter, delete, backspace, insert, home ya da end olabilir.

Eski Action ve BulkAction sınıfları

Acun\Ui\DataTable\Action ve Acun\Ui\DataTable\BulkAction işlem sisteminden önceki sınıflardır ve aynen çalışır:

use Acun\Ui\DataTable\Action;
use Acun\Ui\DataTable\BulkAction;

Action::make('Detay', 'detail')->icon('eye')->action(fn (Order $order) => $this->dispatch('show-order', id: $order->id));
BulkAction::make('Kargoya ver', 'ship')->icon('truck')->action(fn (Builder $query) => $query->update(['status' => 'shipped']));
  • make($etiket, $ad): ikinci parametre sabit bir addır. Verilmezse ad etiketten üretilir ve etiket çevrilince değişir.
  • icon(), style('danger'), visible(), authorize() ve action() kullanılabilir. Eski BulkAction authorizeRow() da alır.
  • Yetkisiz eski işlem gizlenmez, soluk çizilir. Eski toplu işlemler her zaman onay ister.
  • Yeni tablolarda Actions\RowAction ve Actions\BulkAction kullanın.

Dışa aktarma

Dışa aktarma, kayıtları dosya olarak indirmeyi, yazdırmayı ya da panoya kopyalamayı sağlar. Biçimleri exportActions() metodunda listeleyin:

protected function exportActions(): array
{
    return [
        ExportAction::csv()->label('CSV (.csv)')->shortcut('mod+e'),
        ExportAction::pdf(),
        ExportAction::print()->label('Yazdır'),
        ExportAction::copy()->can('orders.export'),
    ];
}

Menüde yalnızca listelediğiniz biçimler, listelediğiniz sırayla görünür. Liste boşsa "Dışa aktar" düğmesi çıkmaz.

Biçimler

Metot Ne yapar Örnek
ExportAction::csv() CSV dosyası ExportAction::csv()
ExportAction::json() JSON dosyası ExportAction::json()
ExportAction::pdf() Yazdırma sayfasını açar; kullanıcı tarayıcıda "PDF olarak kaydet"i seçer ExportAction::pdf()
ExportAction::print() Yeni pencerede sade bir yazdırma sayfası ExportAction::print()
ExportAction::copy() Satırları panoya kopyalar; Excel'e hücre olarak yapışır ExportAction::copy()

Kapsam

"Dışa aktar" menüsü önce hangi satırların alınacağını sorar:

Kapsam Satırlar Değer
Mevcut sayfa Ekranda görünen sayfa current_page
Filtrelenmiş kayıtlar Arama ve filtrelere uyan bütün kayıtlar filtered
Seçili kayıtlar (n) Seçim; bütün kayıtlar seçiliyse işareti kaldırılanlar hariç selected
Tüm kayıtlar query() sorgusunun tamamı, arama ve filtre olmadan; önce onay ister all

Varsayılan kapsam: seçim varsa seçili kayıtlar, arama ya da filtre varsa filtrelenmiş kayıtlar, yoksa mevcut sayfa. Tabloda değiştirmek için:

use Acun\Ui\DataTable\Export\ExportScope;

protected function defaultExportScope(): ExportScope
{
    return ExportScope::Filtered;
}
  • O an uygulanamayan kapsam soluk görünür (ör. seçim yokken "Seçili kayıtlar").
  • copy() yalnızca mevcut sayfa ve seçimle çalışır; en çok 1.000 satır kopyalar (exports.copy_max_rows).
  • Her kapsam query() koşullarını ve geçerli sıralamayı korur.

Biçim seçenekleri

Metot Ne yapar Örnek
scopes() Biçimin kabul ettiği kapsamlar ->scopes(['filtered', 'selected'])
defaultScope() Bu biçimin varsayılan kapsamı ->defaultScope('filtered')
filename() Uzantısız dosya adı ->filename('siparisler')
maxRows() En çok satır sayısı ->maxRows(10000)
queue(false) Dosyayı kuyruğa göndermeden hemen hazırlar ->queue(false)
driver() Kendi yazıcı sınıfınız ->driver(XmlExportDriver::class)

Dosya adı verilmezse tablo başlığı ve tarih kullanılır, ör. siparisler-2026-10-05-143000.csv.

Dışa aktarılan sütunlar ve değerler

Dosyaya görünen sütunlar yazılır. Değerler hücrelerle aynı biçimden (tarih, sayı, para, boolean, renderUsing) düz metin olarak gelir. view() hücreleri alanın ham değerini yazar; farklı bir değer için exportUsing() verin:

// Ekranda "₺1.249,90", dosyada 1249.9 (sayı)
Column::make('Tutar', 'amount')
    ->renderUsing(fn (Order $order) => $order->formattedAmount())
    ->exportUsing(fn (Order $order) => $order->amount / 100),

Column::make('Durum', 'status')->view('admin.tables.cells.order-status')
    ->exportUsing(fn (Order $order) => $order->status->label()),

Column::make('İç not', 'internal_note')->exportable(false),   // dosyada yer almaz

Dışa aktarmada ilişki kullanıyorsanız ilişkileri önceden yüklemek için exportQuery() metodunu yazın:

protected function exportQuery(ExportScope $scope): Builder
{
    return parent::exportQuery($scope)->with('customer');
}

Dosya biçimlerinin ayrıntıları

  • CSV UTF-8 BOM ile ve varsayılan ; ayırıcıyla yazılır; böylece Türkçe Excel dosyayı doğru açar. =, +, -, @ ile başlayan metinlerin başına ' eklenir, dosya açılınca formül çalışmaz.
  • PDF ayrı bir dosya üretmez: yazdırma sayfasını açar ve tarayıcının "PDF olarak kaydet" seçeneğini önerir. Ek bir paket gerekmez. Satır sınırı ve görünüm yazdırma sayfasınınkidir (print.max_rows, print.layout).
  • Yazdırma sayfası en çok 2.000 satır gösterir (print.max_rows). Görünümünü print.layout ile değiştirebilirsiniz.

Kendi biçiminiz

Acun\Ui\DataTable\Export\Contracts\ExportDriver arayüzünü uygulayan bir sınıf yazın. Arayüzün üç metodu vardır: extension(), mimeType() ve write($rows, $columns, $stream, $options). Satırlar tek tek gelir; onları biriktirmeyin, geldikçe akışa yazın.

ExportAction::make('xml')->label('XML')->driver(XmlExportDriver::class),

Biçimi bütün tablolarda kullanmak ya da hazır yazıcılardan birini değiştirmek için sınıfı acun-ui.datatable.exports.drivers ayarına ekleyin.

Kuyrukta dışa aktarma

Satır sayısı 5.000'in (exports.queue_threshold) altındaysa dosya hemen iner. Üstündeyse dosya bir kuyruk işinde hazırlanır:

  1. "Dışa aktarma kuyruğa alındı" bildirimi çıkar.
  2. Tablo, bekleyen iş varken birkaç saniyede bir (exports.poll_seconds) durumu sorar.
  3. İş bitince indirme bağlantılı bir bildirim gelir.
  • CSV, JSON ve kendi biçimleriniz kuyruğa gidebilir. PDF, yazdırma ve kopyalama her zaman hemen hazırlanır; "Mevcut sayfa" kapsamı da kuyruğa gitmez.
  • İş, isteği yapan kullanıcıyı aynı oturum sürücüsüyle (guard) oturum açmış sayar. Tabloyu o anki arama, filtre, sıralama ve seçimle yeniden kurar; authorizeTable() ve işlemin yetkisi yeniden denetlenir.
  • Satırlar sırası korunarak 1.000'erli parçalarla (exports.chunk_size) okunur. Dosya exports.disk diskinde, exports.directory klasörüne yazılır.
  • İndirme bağlantısı imzalıdır, 60 dakika sonra (exports.expire_minutes) geçersiz olur ve dosyayı yalnızca işi başlatan kullanıcıya verir.
  • Eski dosyalar her kuyruk işinden sonra ve acun-ui:prune-exports komutuyla silinir (Yapılandırma).

Gerekenler:

  • Bir kuyruk işçisi: php artisan queue:work. Özel bir kuyruk adı verdiyseniz (exports.queue) --queue=exports ekleyin.
  • Web sunucusu ile işçinin paylaştığı bir önbellek deposu: database, redis, file… (array olmaz). İşin durumu burada tutulur (exports.cache_store).
  • Tablonun query() için ihtiyaç duyduğu değerler public özelliklerde olmalıdır; işçi mount() çalıştırmaz. Public olmayan değerleri restoringFromSnapshot() metodunda yeniden kurun.

Araç çubuğu

Araç çubuğu tablonun üstündeki kutudur: sayfa boyutu, arama, filtreler, araçlar ve başlık işlemleri burada durur. Masaüstünde soldan sağa:

[ 25 ] [ arama ]  …  [ ⏷ ] [ ↻ ] [ özel araçlar ] [ ⊞ ] [ ⤓ ] [ ⋮ ]  [ + Yeni sipariş ]
[ araç çubuğu filtreleri (Durum: Tümü ▾) (Kanal: Tümü ▾) … ]

Filtreler (⏷), Yenile (↻), sütun menüsü (⊞) ve Dışa aktar (⤓) yalnızca ikondur. Adları fareyle üzerine gelince ipucu olarak görünür. Etkin filtre sayısı Filtreler ikonunun köşesinde rozet olarak durur.

Parçaları göstermek ve gizlemek

Her parçayı tablo sınıfından açıp kapatırsınız; görünüm yayınlamanız gerekmez.

Parça Ne zaman görünür Nasıl değiştirilir
Başlık ve kayıt sayısı $title doluysa public string $title = 'Siparişler';
Başlık işlemleri headerActions() doluysa Başlık işlemleri
Arama kutusu Aranacak alan varsa showsSearch(), searchPlaceholder()
Filtreler düğmesi Çekmecede filtre varsa inToolbar() filtreler alt satırda durur
Yenile UtilityAction::refresh() varsa utilityActions()
Sütun menüsü utilityActions() boşsa ya da UtilityAction::columns() içeriyorsa showsColumnPicker()
Dışa aktar exportActions() doluysa exportActions()
Sayfa boyutu Her zaman showsPerPageSelector()
"⋮" menüsü Tam ekran, sıfırlama ya da özel bir araç varsa utilityActions()

Örnek: sütun menüsü ve Dışa aktar istemiyorum.

// Dışa aktar: exportActions() yazmayın ya da [] döndürün.

// Sütun menüsü: kapatın.
protected function showsColumnPicker(): ?bool
{
    return false;
}

showsColumnPicker() null döndürdüğünde (varsayılan) tablodaki kural çalışır. false her durumda gizler, true her durumda gösterir.

Örnek: sade bir tablo, yalnızca arama.

protected function showsPerPageSelector(): bool
{
    return false;   // sayfa boyutu kutusu yok; boyutu defaultPerPage() belirler
}

protected function searchPlaceholder(): string
{
    return 'Sipariş no ya da müşteri ara';
}

Arama kutusunu tamamen kaldırmak için showsSearch() false döndürsün. Hiçbir sütun searchable() değilse ve searchFields() boşsa kutu zaten görünmez.

Tablo araçları

Hangi araçların görüneceğini utilityActions() belirler; listede olmayan araç çizilmez:

protected function utilityActions(): array
{
    return [
        UtilityAction::refresh(),
        UtilityAction::columns(),
        UtilityAction::fullscreen(),
        UtilityAction::resetFilters(),
        UtilityAction::resetSorting(),

        // Kendi aracınız: "⋮" menüsünde
        UtilityAction::make('clear-cache')->label('Önbelleği temizle')->icon('trash')
            ->action(fn () => Cache::tags('orders')->flush())
            ->successMessage('Önbellek temizlendi.'),

        // Araç çubuğunda ikon düğmesi olarak
        UtilityAction::make('help')->label('Yardım')->icon('question-mark-circle')->iconOnly()
            ->url(route('help.orders'), newTab: true)
            ->inline(),
    ];
}
Araç Ne yapar Yeri
refresh() Satırları yeniden yükler; sayfa artık yoksa son sayfaya geçer Araç çubuğu
columns() Sütun menüsü Araç çubuğu
fullscreen() Tabloyu tam ekran açar; Esc ya da "Tam ekrandan çık" kapatır "⋮" menüsü
resetFilters() Aramayı ve bütün filtreleri temizler "⋮" menüsü
resetSorting() defaultSort() sırasına döner "⋮" menüsü
make('ad') Kendi aracınız; inline() ile araç çubuğunda "⋮" menüsü
  • Tam ekran, tabloyu sayfa arka planıyla bütün ekrana yayar ve sayfa kaydırmasını kilitler.
  • Yalnızca [UtilityAction::columns()] verirseniz "⋮" menüsü çıkmaz.
  • order() araçların sırasını değiştirir.

Telefonda araç çubuğu

Telefonda (640 px altı) arama kutusunun altında tek satır kalır: sayfa boyutu, ilk başlık işlemi ve "İşlemler" düğmesi. Diğer bütün araçlar bu düğmenin açtığı panele, yazılarıyla alt alta girer. 375 px genişlikte yatay taşma olmaz. Bu düzen, tabloda en az bir başlık, dışa aktarma ya da araç işlemi varsa kullanılır.

Yükleme sırasında tıklanan düğme pasifleşir ve dönen bir gösterge çıkar. loadingLabel() verdiyseniz o yazı da görünür.

Sayfalama

Sayfalama çubuğu tablonun altındadır: solda "1 - 25 / 5000 sonuç", sağda önceki, sayfa numaraları ve sonraki düğmeleri.

  • Sonuç yokken de yerinde durur ("Sonuç yok").
  • Telefonda yalnızca önceki, geçerli ve sonraki sayfa görünür.
  • Sayfa değişince liste başına kaydırılır.
Metot Ne yapar Örnek
perPageOptions() Sayfa boyutu seçenekleri (public) return [20, 50, 100];
defaultPerPage() Açılıştaki boyut; seçeneklerden biri olmalı return 50;
showsPerPageSelector() Sayfa boyutu kutusunu gösterir ya da gizler return false;
paginationOnEachSide() Geçerli sayfanın iki yanında kaç numara görünür (varsayılan 1) return 2;
paginationMode() Sayfalama türü return PaginationMode::Cursor;
paginationView() Kendi sayfalama görünümünüz (public) return 'tables.pagination-compact';
use Acun\Ui\DataTable\PaginationMode;

public function perPageOptions(): array
{
    return [20, 50, 100];
}

protected function defaultPerPage(): int
{
    return 50;
}

protected function paginationMode(): PaginationMode
{
    return PaginationMode::Simple;
}

Bütün tablolar için yapılandırma: acun-ui.datatable.per_page (seçenekler, varsayılan [10, 25, 50, 100]), default_per_page (25) ve pagination. Adres çubuğundaki ?perPage= yalnızca seçeneklerden biri olabilir; başka bir değer varsayılana döner.

Sayfalama türü

Tür Ne yapar Yapılandırma değeri
PaginationMode::LengthAware (varsayılan) Toplam sayfa sayısını bilir; sayfa numaraları görünür paginate
PaginationMode::Simple Yalnızca önceki ve sonraki simple
PaginationMode::Cursor En hızlısı; numara ve toplam yok, yalnızca önceki ve sonraki cursor

Çok büyük tablolarda toplam sayım yavaştır; o zaman Simple ya da Cursor seçin.

Metinler

"Gösteriliyor", "sonuç", "Sonuç yok", "Önceki" ve "Sonraki" metinleri çeviri anahtarlarıdır. Uygulamanızın lang/tr.json dosyasında aynı anahtarı yazarak değiştirin (Dil ve çeviri):

{
    "Showing": "Listelenen",
    "results": "kayıt",
    "No results": "Kayıt bulunamadı"
}

Sayfalama görünümü

Sayfa numaraları ve önceki/sonraki düğmeleri acun:button (white) ile, geçerli sayfa ana renkle çizilir. Çubuğun HTML'ini değiştirmenin iki yolu vardır:

  1. Bütün uygulamada: php artisan vendor:publish --tag=acun-ui-views komutuyla görünümleri yayınlayın ve resources/views/vendor/acun-ui/components/ui/pagination.blade.php dosyasını düzenleyin. DataTable ve WithListing listeleri bu görünümü kullanır.

  2. Yalnızca bir tabloda: paginationView() ile kendi görünümünüzü verin. Görünüm, Laravel'in sayfalama görünümleri gibi $paginator ve $elements alır:

    public function paginationView(): string
    {
        return 'tables.pagination-compact';
    }
    
    {{-- resources/views/tables/pagination-compact.blade.php --}}
    <nav class="flex items-center justify-end gap-2" aria-label="Sayfalama">
        <acun:button variant="ghost" size="sm" wire:click="previousPage" :disabled="$paginator->onFirstPage()">Önceki</acun:button>
        <span class="text-sm text-gray-600 dark:text-zinc-400">{{ $paginator->currentPage() }} / {{ $paginator->lastPage() }}</span>
        <acun:button variant="ghost" size="sm" wire:click="nextPage" :disabled="! $paginator->hasMorePages()">Sonraki</acun:button>
    </nav>
    

WithListing ile elle yazılan listelerde de perPageOptions() ve paginationView() aynı işi yapar (Liste sayfası).

Görünüm ve renkler

Tablo temanın kendi bileşenleriyle çizilir: acun:table, acun:input, acun:filter-button, acun:drawer, acun:selection-bar, acun:pagination. Bu yüzden temanın ana rengine ve koyu temasına kendiliğinden uyar; tabloya ayrıca renk yazmanız gerekmez.

  • Ana renk brand, açık temada gray, koyu temada zinc tonları kullanılır. Ayrıntı: Özelleştirme.
  • PRO paketinin acun-ui-pro.css dosyası yalnızca dar ekranda sütun gizleme, kaydırma, sabit başlık ve sabit sütun kurallarını ekler.

Başlık

$title tablonun üstünde başlığı ve kayıt sayısını gösterir; boşsa ikisi de gösterilmez:

public string $title = 'Siparişler';

Başlık yazdırma sayfasında ve dosya adında da kullanılır. Tarayıcıdan değiştirilemez. Çevrilmiş bir başlık için değeri mount() içinde verin:

public function mount(): void
{
    $this->title = __('Siparişler');

    parent::mount();
}

Boş durum

Sonuç yokken gösterilen başlığı ve açıklamayı emptyState() verir:

protected function emptyState(): array
{
    return $this->search !== ''
        ? ['title' => 'Aramanıza uyan sipariş yok.', 'description' => 'Başka bir sipariş no ya da müşteri deneyin.']
        : ['title' => 'Henüz sipariş yok.', 'description' => 'İlk sipariş geldiğinde burada görünür.'];
}

Arama ya da filtre varken "Filtreleri temizle" düğmesi kendiliğinden eklenir.

Satır yoğunluğu

Satır yoğunluğu hücre boşluklarını tema aralıklarıyla ayarlar. Kullanıcının değiştirdiği bir araç değil, tablonun ayarıdır:

protected function density(): string
{
    return 'compact';   // compact (sıkı), normal ya da comfortable (geniş)
}

Vermezseniz acun-ui.datatable.density.default değeri (normal) kullanılır. Geçersiz bir değer normal sayılır.

Görünümleri değiştirmek

HTML'i tamamen değiştirmek isterseniz PRO görünümlerini yayınlayın. Önce bu sayfadaki PHP seçeneklerini deneyin; görünüm yayınlamayı son çare olarak kullanın.

php artisan vendor:publish --tag=acun-ui-pro-views

Dosyalar resources/views/vendor/acun-ui-pro/components/data-table/ altına kopyalanır. Yalnızca değiştirmek istediklerinizi tutun, diğerlerini silin; silinenler paketten gelmeye devam eder. Paket güncellendiğinde yayınladığınız dosyalar güncellenmez.

Dosya İçerik
toolbar.blade.php, search.blade.php Başlık, arama, düğmeler, sayfa boyutu
actions/button.blade.php Başlık ve araç çubuğu düğmesi
actions/export-menu.blade.php, actions/export-panel.blade.php "Dışa aktar" menüsü
actions/utility-menu.blade.php "⋮" menüsü
actions/row-actions.blade.php, actions/row-button.blade.php, actions/row-menu.blade.php Satır işlemleri
bulk-actions.blade.php Seçim çubuğu ve toplu işlemler
column-picker.blade.php Sütun menüsü
header.blade.php, row.blade.php Tablo başlığı ve satırlar
row-details.blade.php Satır ayrıntıları penceresi
filters.blade.php, filter-control.blade.php, toolbar-filters.blade.php Filtre çekmecesi ve araç çubuğu filtreleri
empty-state.blade.php, pagination.blade.php Boş durum ve sayfalama
print.blade.php Yazdırma sayfası

Sabit başlık ve sütunlar

Dört isteğe bağlı metot, tablonun kaydırılırken nasıl davranacağını belirler. Hepsi varsayılan olarak kapalıdır; hiçbirini kullanmayan tablonun HTML'i değişmez. Her birinin çalışan örneği: DataTable örnekleri.

Metot Ne yapar Örnek
scrollX(): bool Hücreler tek satırda kalır; geniş tablo kendi kutusunda yana kayar return true;
scrollY(): ?string Kutuya yükseklik verir; tablo kutuda aşağı kayar, başlık üstte kalır return '400px';
fixedHeader(): bool Sayfa kaydırılırken başlık satırı üst çubuğun altında kalır return true;
fixedColumns(): array Baştaki sütunlar ve işlemler sütunu yana kaydırırken yerinde kalır return ['start' => 1, 'end' => true];

scrollX() ve scrollY() yalnızca CSS ile çalışır. fixedHeader() ve fixedColumns() PRO JavaScript dosyasındaki acunDataTableFixed bileşenini kullanır (import '@acunsoft/acun-ui-pro' ya da @acunUiScripts). JS yüklenmemişse tablo yine çalışır, yalnızca başlık ve sütunlar sabit kalmaz; tarayıcı konsolu eksik JS'i bildirir (PRO JavaScript yüklenmezse).

Kaydırma

protected function scrollX(): bool
{
    return true;
}

protected function scrollY(): ?string
{
    return '400px';   // herhangi bir CSS uzunluğu: '28rem', 'min(70vh, 42rem)'…
}
  • scrollX() bütün hücreleri tek satırda tutar. Uzun bir metin sütununun alt satıra geçmesi için o sütunda wrap() kullanın ve bir genişlik verin: Column::make('Not', 'note')->wrap()->width('20rem').
  • scrollY() kutuyu o yükseklikte tutar; kutu dikey kayar ve başlık satırı kutunun üstüne yapışır. İkisi birlikte iki yöne kayan bir kutu verir.
  • Eski ayarlar çalışmaya devam eder: tabloda public bool $stickyHeader = true; ve bütün tablolar için acun-ui.datatable.sticky_header, scrollY('min(70vh, 42rem)') ile aynıdır. scrollY() bir değer döndürürse o kullanılır.

Sabit başlık

protected function fixedHeader(): bool
{
    return true;
}
  • Başlık satırı üst çubuğun altına geldiğinde orada başlığın bir kopyası görünür. Tablonun sonuna gelince kopya tabloyla birlikte yukarı çıkar ve kaybolur; sayfada hiçbir şey kaymaz.
  • Kopyadaki sıralama okları ve "tümünü seç" kutusu çalışır; tıklama gerçek başlıktaki düğmeye iletilir. Klavye ve ekran okuyucu kullanıcıları gerçek başlığı kullanır; kopya ekran okuyuculardan gizlidir ve sekme sırasına girmez.
  • Kopya her Livewire güncellemesinden sonra yeniden kurulur. Sütun genişlikleri ve yatay kaydırma gerçek tabloyla aynıdır.
  • Panelin üst çubuğu (.panel-topbar, sabit menü düzeninde) otomatik bulunur. Kendi düzeninizde sabit bir çubuk varsa ona data-ac-sticky-top niteliği verin. Başlıkla çubuk arasında boşluk için: .ac-data-table { --ac-data-table-fixed-header-gap: 8px; }.
  • Tam ekranda başlık ekranın üst kenarında kalır. Telefonda da çalışır.
  • scrollY() ile birlikte kullanılırsa scrollY() kazanır: başlık zaten kutunun içinde sabittir, sayfadaki kopya çizilmez.

Sabit sütunlar

protected function fixedColumns(): array
{
    return ['start' => 1, 'end' => true];
}
  • start: soldaki veri sütunu sayısıdır (en fazla 10). Seçim kutusu ve satır ayrıntıları (+) sütunu önde olduğu için onlar da sabit kalır. start görünen sütun sayısından büyükse bütün sütunlar sabitlenir. İlk sütun sütun menüsünden gizlenirse sıradaki sütun sabitlenir.
  • end: işlemler sütununu sağda tutar. Tabloda satır işlemi (actions()) yoksa bir şey yapmaz.
  • Sabit sütunların genişliği tarayıcıda ölçülür. Ekran boyutu, yoğunluk (density()), sütun menüsü ya da dar ekranda gizlenen priority() sütunları değişince yeniden hesaplanır.
  • Altından içerik geçerken sabit sütunların kenarında hafif bir gölge görünür.
  • Telefonda (640 px altı) yalnızca soldaki sütunlar sabit kalır; işlemler sütunu dar ekranda yer kaplamasın diye tabloyla birlikte kayar. Telefonda start değerini küçük tutun (genelde 1).
  • scrollX() ile birlikte kullanmanız önerilir.

Birlikte kullanım

Birleşim Sonuç
scrollX() + scrollY() İki yöne kayan kutu, başlık üstte
scrollX() + scrollY() + fixedColumns() Aynı kutu; sabit sütunlar solda ve sağda, köşe hücreleri en üstte
fixedHeader() + fixedColumns() Sayfada sabit başlık; kopyada da sabit sütunlar aynı yerde
fixedHeader() + scrollY() scrollY() kazanır; başlık kutunun içinde sabittir
Satır ayrıntıları, seçim çubuğu, yoğunluk, tam ekran Hepsiyle çalışır

Sınırlar ve ipuçları

  • Düz arka plan: Sabit hücreler, altından geçen içeriği örtmek için düz bir arka plan alır. Normal satırda kutunun rengi, fareyle üzerine gelinen satırda satırın rengi, başlıkta başlığın rengi kullanılır. Kendi CSS'inizle bir satırı renklendiriyorsanız (ör. seçili satır), aynı rengi --ac-data-table-row-bg değişkenine de verin:

    .ac-data-table tbody tr:has(input:checked) {
        background-color: var(--color-brand-50);
        --ac-data-table-row-bg: var(--color-brand-50);
    }
    
  • Özel hücre görünümleri: view() ile çizdiğiniz hücre içeriğine kendi arka plan rengini vermeyin, saydam bırakın. İçerikteki bir renk, satırın fareyle üzerine gelinen rengini ve koyu temayı bozar.

  • Taşan kutular: Tabloyu overflow: hidden ya da overflow: auto olan bir kutunun içine koymayın; sabit başlık o kutuya göre yapışır. Köşe yuvarlatma için overflow: clip kullanın.

  • Bir sayfada birden çok tablo: Yalnızca gövdesi ekranda olan tablonun başlığı sabit görünür. Adres çubuğundaki değerleri (?q=, ?page=) paylaşmamaları için ikinci tabloda queryString() metodunu yazın ya da acun-ui.datatable.url_state ayarını kapatın.

  • Hız: Özellik kapalıyken hiçbir JS çalışmaz. Açıkken kaydırma her ekran karesinde en çok bir kez işlenir; ölçüm yalnızca boyut değişince ve Livewire güncellemesinden sonra yapılır. Çok uzun sayfalarda (100+ satır) bile maliyet yalnızca başlık hücresi sayısı kadardır.

  • Yazdırma: Sabit başlık kopyası yazdırmada gizlenir.

Yapılandırma

Bütün tabloların varsayılanları config/acun-ui.php dosyasının datatable bölümündedir. Dosyayı uygulamanıza kopyalamak için:

php artisan vendor:publish --tag=acun-ui-config
'datatable' => [
    'per_page' => [10, 25, 50, 100],      // sayfa boyutu seçenekleri
    'default_per_page' => 25,
    'search_debounce' => 400,             // arama kutusunun bekleme süresi (ms)
    'url_state' => true,                  // arama, sıralama, filtre… adres çubuğuna yazılır
    'sticky_header' => false,             // eski ad: her tabloda scrollY('min(70vh, 42rem)')
    'pagination' => 'paginate',           // paginate | simple | cursor
    'select_all' => 'all',                // başlıktaki kutu: all (bütün eşleşenler) | page (görünen sayfa)
    'selection' => ['max_keys' => 5000],  // tek tek seçilebilecek en çok kayıt
    'actions' => ['enabled' => true],     // false: başlık, dışa aktarma ve araç işlemleri kapanır
    'exports' => [
        'enabled' => true,                // false: dışa aktarma, kopyalama ve yazdırma kapanır
        'queue_threshold' => 5000,        // bu satır sayısının üstü kuyrukta hazırlanır
        'chunk_size' => 1000,             // satırlar bu büyüklükte parçalarla okunur
        'disk' => 'local',
        'directory' => 'exports',
        'queue' => null,                  // kuyruk adı (null: varsayılan)
        'connection' => null,             // kuyruk bağlantısı (null: varsayılan)
        'expire_minutes' => 60,           // indirme bağlantısının ömrü
        'poll_seconds' => 3,              // tablo kuyruktaki işi bu aralıkla sorar
        'cache_store' => null,            // iş durumunun tutulduğu önbellek; işçiyle ortak olmalı
        'csv_delimiter' => ';',
        'copy_max_rows' => 1000,
        'per_minute' => 30,               // kullanıcı başına dakikada yazdırma, indirme, kopyalama
        'drivers' => [
            'csv' => CsvExportDriver::class,
            'json' => JsonExportDriver::class,
        ],
    ],
    'print' => ['layout' => 'acun-ui-pro::components.data-table.print', 'max_rows' => 2000, 'token_minutes' => 10],
    'density' => ['default' => 'normal'],  // compact | normal | comfortable
    'columns' => ['persist' => 'none'],    // none | session
    'routes' => ['middleware' => ['web', 'auth'], 'prefix' => 'acun-ui/data-table'],
],
  • Eski bir config/acun-ui.php yayınladıysanız eksik anahtarlar için paket varsayılanları kullanılır.
  • İndirme ve yazdırma rotaları imzalıdır ve dosyayı yalnızca sahibine verir. Farklı bir oturum sürücüsü (guard) kullanıyorsanız routes.middleware içinde belirtin, ör. ['web', 'auth:admin'].
  • Yazdırma bağlantısı 10 dakika geçerlidir (print.token_minutes).
  • Arama ayarları acun-ui.search bölümündedir: Arama kılavuzu.
  • Bütün anahtarların kısa açıklaması: Yapılandırma sayfası.

Adres çubuğu

Arama (q), sıralama (sort, direction), filtreler (filters), sayfa boyutu (perPage), sütun seçimi (columns) ve sayfa numarası adres çubuğuna yazılır. Sayfa yenilenince ya da bağlantı paylaşılınca aynı liste açılır.

  • Her değer yalnızca varsayılandan farklıysa görünür.
  • Kapatmak için url_state değerini false yapın ya da tabloda kendi queryString() metodunuzu yazın.

Eski dosyaları silmek

Süresi dolan dışa aktarma dosyalarını düzenli silmek için komutu zamanlayın:

// routes/console.php
Schedule::command('acun-ui:prune-exports')->hourly();

Yetki ve güvenlik

DataTable tarayıcıdan gelen her isteği sunucuda yeniden denetler. Paket kendi yetki sistemini dayatmaz; kuralları siz authorizeTable(), query() ve işlem yetkileriyle verirsiniz.

Tabloya erişim

authorizeTable() tabloyu kimin açabileceğini belirler:

protected function authorizeTable(): void
{
    $this->authorize('viewAny', Order::class);
}

Metot ilk yüklemede ve sonraki her Livewire isteğinde, değer güncellemelerinden ve işlem çağrılarından önce çalışır. Oturum sırasında yetkisi kaldırılan kullanıcı artık hiçbir işlemi çalıştıramaz.

Kayıtların görünürlüğü

Kullanıcının hangi kayıtları göreceğini query() belirler. Her kullanıcının ya da her müşteri hesabının yalnızca kendi kayıtlarını gördüğü uygulamalarda koşulu buraya yazın:

protected function query(): Builder
{
    return Order::query()->where('user_id', auth()->id());
}
  • Satır işlemleri yalnızca query() içindeki bir kayıtta çalışır; başka bir kaydın anahtarı gönderilirse 404 döner.
  • Toplu işlemler ve dışa aktarma her zaman query() kapsamında ve etkin filtrelerle çalışır. Tarayıcıdan gelen anahtarlar bu sorgunun üstüne eklenir; kapsam dışındaki kayıtlara dokunulmaz.
  • Satır ayrıntıları penceresi de yalnızca query() içindeki kayıtları açar.

İşlemlerin denetimi

Düğmeyi gizlemek tek başına güvenlik sayılmaz. Bu yüzden paket her çağrıyı sunucuda yeniden denetler:

  • Her Livewire çağrısı (runTableAction, runRowAction, runBulkAction, exportTable, copyRows, preparePrint) işlemi sunucuda yeniden bulur. Tanımsız işlem 404, gizli, yetkisiz ya da pasif işlem 403 döner.
  • authorizeTable() her istekte bunlardan önce çalışır.
  • İşlemin döndürdüğü değer tarayıcıya gönderilmez; yalnızca yönlendirme ve dosya indirme gider.

Toplu işlemde satır yetkisi

authorize() işlemin tamamı için, authorizeRow() hedeflenen her kayıt için sunucuda çalışır:

BulkAction::delete()
    ->authorize(fn () => auth()->user()->can('delete-any', Order::class))
    ->authorizeRow(fn (Order $order) => auth()->user()->can('delete', $order)),
  • Seçili kayıtlardan biri bile authorizeRow() kontrolünden geçmezse işlem hiç çalışmaz ve 403 döner. Kayıtlar sessizce atlanmaz.
  • Bütün kayıtlar seçiliyken kontrol bütün eşleşen kayıtlar üzerinde, parça parça yapılır.
  • Satır işleminde kayda bağlı bir yetki kuralı varsa (ör. can('delete')), aynı kuralı toplu işleme authorizeRow() ile verin. Yoksa toplu işlem, satır kuralını aşmak için kullanılabilir.

Tarayıcıdan gelen değerler

  • Sıralama yalnızca sortable() sütunlarda yapılır; tarayıcıdan gelen sütun adı doğrudan sorguya aktarılmaz. Yön yalnızca asc ya da desc olabilir.
  • Sayfa boyutu yalnızca perPageOptions() seçeneklerinden biri olabilir. Adres çubuğundan gelen başka bir değer (ör. -1) varsayılana döner.
  • Filtre değerleri türüne göre denetlenir: seçim filtresi yalnızca tanımlı seçenekleri, aralık filtresi yalnızca from ve to değerlerini alır. Tanımsız filtreler yok sayılır.
  • Arama teriminin en çok 200 karakteri ve 10 sözcüğü kullanılır.
  • Tablonun $title ve $stickyHeader özellikleri tarayıcıdan değiştirilemez.
  • Tek tek seçilebilecek kayıt sayısı selection.max_keys ile sınırlıdır.

Dışa aktarma sınırları

  • Bir kullanıcı dakikada en çok 30 yazdırma, indirme ya da kopyalama başlatır (exports.per_minute). Sınır aşılınca uyarı bildirimi çıkar.
  • İndirme ve yazdırma bağlantıları imzalıdır, süreleri dolar ve dosyayı yalnızca sahibine verir.
  • exports.enabled = false dışa aktarma menüsünü, toplu yazdırmayı ve seçimi dışa aktarmayı birlikte kapatır.

Not

Eski ad AcunDataTable hâlâ çalışır ama kullanımdan kalkacak; yeni tablolarda DataTable kullanın. Paketteki eski tarzda tam örnek: examples/Livewire/OrdersTable.php.

Acun UIİnsanlar için tasarlandı.