setMode({ type: "create" })}>
+ + Ticket
+
+ }
+ >
+ {vm.error && (
+
+ {vm.error}
+
+
+ )}
+
+ {sprintFocus && (
+
+
+ Filtré sur le sprint « {vm.sprints.find((s) => s.id === sprintFocus)?.name ?? sprintFocus} »
+
+
+
+ )}
+
+ {/* ── Search + compact filters ── */}
+
+
vm.setQuery({ ...vm.query, text: e.target.value || undefined })}
+ />
+
+
+
+
+
+
+
+
+ {/* ── List, grouped by sprint ── */}
+ {vm.busy && vm.list === null ? (
+
+ Chargement des tickets…
+
+ ) : items.length === 0 && !hasFilters ? (
+
+
Aucun ticket dans ce projet.
+
+
+ ) : items.length === 0 ? (
+
+
Aucun ticket ne correspond aux filtres.
+
+
+ ) : (
+
+ {grouped.map((g) => (
+ setMode({ type: "detail", ref })}
+ />
+ ))}
+ {noSprint.length > 0 && (
+ setMode({ type: "detail", ref })}
+ />
+ )}
+
+ )}
+
+ {vm.list?.nextCursor && (
+
+
+
+ )}
+
+ );
+}
+
+function TicketGroup({
+ heading,
+ tickets,
+ sprints,
+ nameOf,
+ onOpen,
+}: {
+ heading: string;
+ tickets: TicketSummary[];
+ sprints: Sprint[];
+ nameOf: (id: string) => string;
+ onOpen: (ref: string) => void;
+}) {
+ const sprintNameOf = (id: string | null | undefined) =>
+ id ? sprints.find((s) => s.id === id)?.name : undefined;
+ return (
+