diff --git a/frontend/src/features/tickets/TicketFacetsBar.tsx b/frontend/src/features/tickets/TicketFacetsBar.tsx index f09811e..9ef4608 100644 --- a/frontend/src/features/tickets/TicketFacetsBar.tsx +++ b/frontend/src/features/tickets/TicketFacetsBar.tsx @@ -14,7 +14,8 @@ */ import type { TicketPriority, TicketStatus } from "@/domain"; -import { Button, Input } from "@/shared"; +import type { TicketListSort, TicketListSortField } from "@/ports"; +import { Button, Input, cn } from "@/shared"; import { PriorityBadge, StatusBadge, @@ -24,6 +25,23 @@ import { statusLabel, } from "./ticketMeta"; +/** Styling for the sort-field select, matching the panel's other selects. */ +const selectClass = cn( + "h-8 rounded-md bg-raised px-2 text-xs text-content", + "border border-border outline-none transition-colors", + "focus:border-primary disabled:cursor-not-allowed disabled:opacity-50", +); + +/** Human labels for the sort fields (also the option text). */ +const SORT_FIELD_LABEL: Record = { + number: "Numéro", + priority: "Priorité", + status: "Statut", + title: "Titre", +}; + +const SORT_FIELDS = Object.keys(SORT_FIELD_LABEL) as TicketListSortField[]; + export interface TicketFacetsBarProps { /** Current free-text search value (controlled). */ text: string; @@ -42,6 +60,13 @@ export interface TicketFacetsBarProps { onClearFacets?: () => void; /** Placeholder for the search input. */ searchPlaceholder?: string; + /** + * Current sort (ticket #21). `undefined` ⇒ the backend's historical order. + * When {@link onSortChange} is provided, a « Trier par… » control appears. + */ + sort?: TicketListSort; + /** Emitted with the next sort, or `undefined` to restore the default order. */ + onSortChange?: (sort: TicketListSort | undefined) => void; } export function TicketFacetsBar({ @@ -53,6 +78,8 @@ export function TicketFacetsBar({ onTogglePriority, onClearFacets, searchPlaceholder = "Search title/description…", + sort, + onSortChange, }: TicketFacetsBarProps) { const hasFacets = statuses.length > 0 || priorities.length > 0; return ( @@ -109,6 +136,51 @@ export function TicketFacetsBar({ ))} + {/* Sort control (#21): field choice + asc/desc toggle. Absent field ⇒ + the backend keeps its historical order. Grouping-by-sprint stays + client-side; this sort applies intra-group. */} + {onSortChange && ( +
+ + {sort && ( + + )} +
+ )} {onClearFacets && hasFacets && (
diff --git a/frontend/src/features/tickets/TicketsPanel.tsx b/frontend/src/features/tickets/TicketsPanel.tsx index 65b0d19..abff0a8 100644 --- a/frontend/src/features/tickets/TicketsPanel.tsx +++ b/frontend/src/features/tickets/TicketsPanel.tsx @@ -163,6 +163,11 @@ export function TicketsPanel({ projectId, onOpen }: TicketsPanelProps) { onToggleStatus={vm.toggleStatus} onTogglePriority={vm.togglePriority} onClearFacets={vm.clearFacets} + sort={vm.query.sort} + onSortChange={(sort) => { + const { sort: _drop, ...rest } = vm.query; + vm.setQuery(sort ? { ...rest, sort } : rest); + }} />