Tabulka
Neaktivní záznamy
Stornovaný, zrušený nebo archivovaný záznam, který v seznamu zůstává a přestává být zapisovatelný — ztlumený, na přání přeškrtnutý a obarvený, a tak jako tak odmítnutý serverem.
Na této stránce
- Co jedno volání rozhoduje
- Zámek je na straně serveru
- Vzhled
- Co zůstává živé a jak to vzít pryč
- selectable(false) — držet ho mimo hromadné akce
- actions(false) — udělat z řádku netečný
- editing(true) — stav jako štítek
- Telefony dostanou stejný stav
- Výchozí nastavení pro celý projekt
- Rozšířený příklad
- Přehled API
- Na tabulce
- Na InactiveRow
- Řešení potíží
- Související
Záznam může přestat být živý, aniž by z tabulky zmizel. Stornovaná objednávka, zrušený řádek faktury, archivovaný zákazník: pořád se čte, pořád se v něm hledá, pořád se počítá do součtů — a už do něj nikdo nemá psát.
Skrýt ho by byla lež o datech. Nechat otevřené jeho editory je pozvánka k zápisu, který doména už jednou odmítla. Tabulce se proto jednou řekne, které záznamy jsou neaktivní:
->rowInactive(fn (Order $order) => $order->status === 'cancelled')
Takový řádek se ztlumí, jeho inline editory se neotevřou a server zápis odmítne, i kdyby byl podvržený. Všechno ostatní na řádku — akce, zaškrtávátko, kliknutí, které záznam otevře — funguje dál.
Co jedno volání rozhoduje
rowInactive() bere predikát a volitelný druhý argument, který určuje, co stav
dělá:
use NyonCode\WireTable\Support\InactiveRow; ->rowInactive( fn (Order $order) => $order->status === 'cancelled', fn (InactiveRow $row) => $row ->strikethrough() // přeškrtnout texty řádku ->color('danger'), // a obarvit ho)
Closure dostane InactiveRow této tabulky a konfiguruje ho na místě, stejně jako
gestures() konfiguruje TableGestures. Návratová hodnota se ignoruje, takže
funguje jak plynulý řetěz, tak víceřádkové tělo.
Předejte prosté true pro tabulku, jejíž každý řádek je neaktivní (obrazovka
archivu jen ke čtení), nebo false, chcete-li výchozí stav vyslovit nahlas:
->rowInactive() // každý záznam této tabulky->rowInactive(false) // žádný — totéž jako metodu nezavolat
Zámek je na straně serveru
Tohle je ta půlka, na které záleží, a není to nová mašinerie: tabulka vloží své
pravidlo do vlastního per-record stavu disabled každého editovatelného sloupce, a
to je brána, kterou Column::canEdit() už dnes uplatňuje v zápisové pipeline.
Má to tři důsledky, které stojí za to znát:
- Podvržený požadavek je odmítnut. Atribut
disabled, který vidí prohlížeč, je jen kosmetika; odmítnutí padne znovu při commitu editace buňky, pod zámkem řádku, vCellEditPipeline::commit(). - Fill handle je pokrytý zdarma. Tažení, které zapíše jednu hodnotu do sta řádků, projde pro každý z nich stejnou per-record bránou — stornované řádky uprostřed tahu se přeskočí a nahlásí, nezapíšou.
- Vlastní
disabled()sloupce platí dál. Jsou to dvě oddělené přihrádky a buňku zamkne kterákoli z nich, ať byla deklarována první nebo druhá — pravidlo sloupce pro jeho vlastní buňky:
TextInputColumn::make('quantity')->disabled(fn (Order $order) => $order->locked)
a pravidlo tabulky, naráz pro všechny editovatelné sloupce té tabulky:
->rowInactive(fn (Order $order) => $order->status === 'cancelled')
Na pořadí deklarace nezáleží. ->columns([...])->rowInactive(...) i
->rowInactive(...)->columns([...]) zamknou přesně stejné buňky.
Vzhled
Dva oddělené přepínače, protože každý říká něco jiného.
dim() je ve výchozím stavu zapnutý. Ztlumí texty řádku: tenhle řádek
přestal být živý. Je to tiché konstatování a platí o každém neaktivním záznamu.
strikethrough() čeká, až si o něj řeknete. Přeškrtnutí je tvrzení o
obsahu — „tahle hodnota není součástí součtu“ — což je správně u stornovaného
řádku objednávky a špatně u archivovaného zákazníka.
->rowInactive($when, fn (InactiveRow $row) => $row->strikethrough())->rowInactive($when, fn (InactiveRow $row) => $row->dim(false)) // jen přeškrtnutí
Přeškrtnutí dosáhne i na formulářové prvky řádku, nejen na texty. Je to záměr a
je to smysl celé věci: prohlížeč nedědí text-decoration do <input> a
nedotčený input je přesně to, co by čtenář jinak považoval za editovatelné.
color() obarví celý řádek stejným resolverem, jaký používá rowColor() —
kanonickým vlastníkem tónování řádků — takže se neaktivní a obarvený řádek
nemohou rozejít. Funguje libovolná sémantická role i syrový odstín a tónovaný
řádek dostane vlastní hover ve stejném odstínu a ztratí neutrální pruhování:
->rowInactive($when, fn (InactiveRow $row) => $row->color('danger'))
Explicitní rowColor() na tabulce nad ním vždy vyhraje, což je právě to, co
tabulce dovolí tónovat podle stavu a zároveň označit stornované řádky:
->rowColor(fn (Order $o) => $o->isOverdue() ? 'warning' : null) // vyhraje tam, kde vrátí barvu->rowInactive( fn (Order $o) => $o->status === 'cancelled', fn (InactiveRow $row) => $row->color('gray'), // použije se tam, kde rowColor() vrátil null)
Řádek navíc nese aria-disabled="true" a data-inactive="true", takže
asistivní technologie se to dozví a aplikace si může stylovat podle
[data-inactive], aniž by publikovala view.
Co zůstává živé a jak to vzít pryč
Akce řádku, zaškrtávátko výběru i kliknutí na záznam na neaktivním řádku fungují dál. Je to výchozí stav záměrně: akce, která stav vrací zpět („obnovit“, „zrušit storno“), bydlí právě ve sloupci akcí toho řádku, a zamknout celý řádek by znamenalo vzít pryč jediný ovládací prvek, kterým se záznam vrací.
Zbylé dvě věci jdou vypnout, když je neaktivní záznam opravdu netečný.
selectable(false) — držet ho mimo hromadné akce
->rowInactive($when, fn (InactiveRow $row) => $row->selectable(false))
Zaškrtávátko řádku se stane inert (nejen neklikatelné — vypadne i z pořadí
tabulátoru), „vybrat stránku“ i zaškrtávátko v hlavičce řádek přeskočí a
podvržené přepnutí je odmítnuto. Odškrtnout jde vždycky, takže řádek zamčený až
poté, co byl vybrán, jde ze výběru pořád odebrat.
Jedno omezení, a to upřímné: výběr „vybrat vše odpovídající“ je dotaz, ne seznam — teprve to umožňuje vybrat 128 000 řádků — a predikát napsaný v PHP do toho dotazu vložit nejde. Hromadná akce, která se neaktivních záznamů nesmí dotknout, si záznam ověří sama, přesně jako u jakéhokoli jiného pravidla, které databáze neumí vyjádřit.
actions(false) — udělat z řádku netečný
->rowInactive($when, fn (InactiveRow $row) => $row->actions(false))
Buňka s akcemi se stane inert, kontextové menu se pro ten záznam vůbec
nepostaví a executeTableAction() / openActionModal() ho odmítnou na serveru —
což pokrývá i navázanou record akci (Record akce:
onClick(), onDoubleClick(), onKey()), protože ty se spouštějí přes tytéž
dvě metody. Kliknutí do prohlížeče dorazí a pak neudělá nic.
recordUrl() je jediné klikání na celý řádek, kterého se to nedotkne: je to
prostý odkaz a otevřít stornovaný záznam je čtení, ne zápis. Když se záznam nemá
otevřít vůbec, ať recordUrl(fn ($record) => …) pro něj vrátí null.
editing(true) — stav jako štítek
Pro tabulku, kde „neaktivní“ je barva a nic víc:
->rowInactive($when, fn (InactiveRow $row) => $row->editing())
Telefony dostanou stejný stav
Skládaná karta (Responzivní rozvržení) nese stejné ztlumení, stejné přeškrtnutí i stejné tónování a platí pro ni stejné dva zámky na zaškrtávátku a řádku akcí. Není co navíc konfigurovat — karta je druhé vykreslení téhož záznamu, ne druhá definice.
Výchozí nastavení pro celý projekt
Back office, kde má každý stornovaný řádek vypadat stejně, to řekne jednou v
config/wire-table.php:
'defaults' => [ 'inactive_rows' => [ 'strikethrough' => true, 'color' => 'danger', ],],
Každá tabulka, která zavolá rowInactive(), z toho vychází; konfigurátor na
úrovni tabulky to přebije klíč po klíči. Neznámý klíč vyhodí výjimku, místo aby
tiše nic nedělal.
Rozšířený příklad
use Livewire\Component;use NyonCode\WireCore\Actions\Action;use NyonCode\WireTable\Columns\TextColumn;use NyonCode\WireTable\Columns\TextInputColumn;use NyonCode\WireTable\Concerns\WithTable;use NyonCode\WireTable\Support\InactiveRow;use NyonCode\WireTable\Table; class ListOrders extends Component{ use WithTable; public function table(Table $table): Table { return $table ->model(Order::class) ->selectable() ->columns([ TextColumn::make('number')->searchable(), TextInputColumn::make('quantity'), // na stornovaném řádku zamčeno // TextColumn::make('total')->money('CZK'), ]) ->actions([ Action::make('restore') // pořád ovladatelná — právě ona stav vrací // ->visible(fn (Order $order) => $order->status === 'cancelled') ->action(fn (Order $order) => $order->update(['status' => 'open'])), ]) ->rowInactive( fn (Order $order) => $order->status === 'cancelled', fn (InactiveRow $row) => $row ->strikethrough() ->color('danger') ->selectable(false), // a držet ho mimo hromadné akce // ); } public function render() { return $this->getTableProperty(); }}
Přehled API
Na tabulce
->rowInactive(bool|Closure $when = true, Closure|InactiveRow|null $configure = null)// $when: fn ($record): bool — které záznamy jsou neaktivní (true = všechny)// $configure: fn (InactiveRow $row) => … — konfiguruje se na místě, návratová hodnota se ignoruje ->hasInactiveRecords(): bool // zda tabulka stav vůbec deklaruje->isRecordInactive(?Model $record): bool // vyhodnocený predikát->getInactiveRow(): InactiveRow // konfigurace této tabulky, nasazená z configu
Na InactiveRow
->strikethrough(bool $condition = true) // přeškrtnout texty řádku i jeho inputy — výchozí false->dim(bool $condition = true) // ztlumit texty řádku — výchozí true->color(?string $color) // 'danger'|'warning'|… nebo libovolný odstín; null = bez tónu — výchozí null->editing(bool $allowed = true) // smí se neaktivní řádek dál editovat — výchozí false->selectable(bool $allowed = true) // smí se zaškrtnout — výchozí true->actions(bool $allowed = true) // jsou jeho akce ovladatelné — výchozí true ->isStrikethrough(): bool->isDimmed(): bool->getColor(): ?string->allowsEditing(): bool->allowsSelection(): bool->allowsActions(): bool
Řešení potíží
Řádek vypadá neaktivně, ale buňka se pořád uloží. Predikát se vyhodnocuje pro záznam na obou cestách, takže to znamená, že si odporuje sám — ověřte, že čte uložený atribut, ne takový, který vzniká až během vykreslení.
Nic není přeškrtnuté. strikethrough() je ve výchozím stavu vypnutý;
dim() je vzhled, který se dodává. Zapněte ho na tabulce, nebo pro celý projekt
v configu.
Přeškrtnutí je vidět na textu, ale ne na odznaku nebo odkazu. Potomek, který si nastavuje vlastní barvu nebo dekoraci, si ji ponechá — je to totéž pravidlo, díky kterému zůstane odznak čitelný uvnitř tónovaného řádku.
Související
- Inline editace — editory, které tenhle stav zamyká
- Výběr — co zamčené zaškrtávátko znamená pro hromadné akce
- Record akce — kliknutí, kterého se stav nedotkne
- Vrstva gest — fill handle, který pokrývá stejná brána