WorkQueue
Työjono
Asiat ryhmiteltyinä vasemmalla, valitun sisältö oikealla; poikkeuskortti kertoo mikä on vialla ja kuka korjaa.
Käyttöpaikat
Suoraan: palvelu tuo osan itse. Välillisesti: osa tulee mukaan toisen paketin osan kautta, ja sen muutos näkyy palvelussa silti. Laskettu julkaisun yhteydessä 23.10.2026.
Käyttö
Paketin README:n luku sellaisenaan.
IssueCard — poikkeuskortti
Mikä on vialla, kenen korjattava ja mikä korjaa sen. Tuotannon hälytyslista näytti Pythonin poikkeuksen ja kaksi nappia, *Kuittaa* ja *Hiljennä* — kumpikaan ei korjaa mitään.
<IssueCard
avatar={<Avatar name="Akkuvoima Oy" tone="identity" />}
title="Akkuvoima Oy"
meta="Ehdokkaat · Manuaalinen"
owner="Meidän korjattava"
ownerTone="self"
status="Jäsennysasetus puuttuu"
statusTone="error"
description="Tiedostolle «uutuudet syksy.xlsx» ei ole jäsennysasetusta. Toimittaja on todennäköisesti vaihtanut nimen."
footnote="Havaittu 7 pv sitten · viimeisin onnistunut 9 pv sitten"
technical="ValueError: XLSX ingest config not found for input '…'"
actions={<Button size="sm">Käytä aiempaa asetusta</Button>}
/>owner+ownerTone:selfpiirtääwarning-merkin ja vaatii toimenpiteen tältä käyttäjältä;otheron ääriviiva ja tiedoksi. Painike seuraa samaa sääntöä:self-kortille täytetty,other-kortillevariant="outline".technicalon<details>-elementissä: taitettuna, ilman tilaa, saatavilla ilman JavaScriptiä. Pitkä polku ei levitä korttia (break-all).childrenon paikka riville avautuvalle lomakkeelle, esimerkiksi puuttuvan osoitteen syötölle.
Palvelinrenderöitävä. Listaa varten kääri <ul className="divide-y">:n sisään <li>:nä, kortti ei piirrä omaa reunaansa.
WorkQueue — työjono
Asiat ryhmiteltyinä vasemmalla, valitun sisältö oikealla. Lista kertoo mitä on jäljellä, valittu kohta yhden asian kerrallaan, ja päätös siirtää seuraavaan. Ryhmän nimi on kuka päättää (Ostaja, Hinnoittelu, Katselmoija), ja hint kertoo miksi ryhmä ei koske tätä käyttäjää.
"use client";
const [valittu, setValittu] = useState("hinta");
<div className="grid items-start gap-6 lg:grid-cols-[19rem_minmax(0,1fr)]">
<WorkQueue
label="Muutosjono"
className="lg:sticky lg:top-20"
value={valittu}
onValueChange={setValittu}
groups={[
{ label: "Ostaja", items: [{ id: "hinta", title: "Ostohinta ei vastaa sovittua", description: "syöte 26,13 € · sovittu 25,80 €", tone: "pending" }] },
{ label: "Toimittaja", hint: "ei toimenpiteitä meiltä", items: [{ id: "yksikko", title: "Koko ilman yksikköä", tone: "info" }] },
{ label: "Säännöt ratkaisivat", items: [{ id: "sovittu", title: "Ostohinta vastaa sovittua", tone: "none" }] },
]}
/>
<Card>{/* valitun sisältö */}</Card>
</div>- Sävy on tila, ei prioriteetti:
pendingodottaa tämän käyttäjän päätöstä,doneon päätetty,infoodottaa jotakuta muuta,noneei vaadi mitään. Kiireellisyys näytetään järjestyksellä. ↑/↓jaj/ksiirtävät valintaa ja kohdistuksen;aria-current="true"kertoo valitun ruudunlukijalle.- Vain lista. Sisältöalue, asettelu ja «seuraavaan avoimeen» -siirto kuuluvat kuluttajalle, koska ne riippuvat siitä mitä asiat ovat. Demo
/v3/muutoksetnäyttää koko reseptin.
Tuonti ja lähde
import { WorkQueue, IssueCard } from "@karkkainen/ui";src/components/work-queue.tsxsrc/components/issue-card.tsx