diff --git a/frontend/src/features/tickets/TicketsPanel.tsx b/frontend/src/features/tickets/TicketsPanel.tsx index 049beb1..fdb4a15 100644 --- a/frontend/src/features/tickets/TicketsPanel.tsx +++ b/frontend/src/features/tickets/TicketsPanel.tsx @@ -74,6 +74,8 @@ export function TicketsPanel({ projectId, onOpen }: TicketsPanelProps) { const [showSprintPicker, setShowSprintPicker] = useState(false); const [selectedRefs, setSelectedRefs] = useState>(() => new Set()); const [bulkStatus, setBulkStatus] = useState(""); + const [showBulkSprintPicker, setShowBulkSprintPicker] = useState(false); + const [bulkNotice, setBulkNotice] = useState(null); const [confirmBulkDelete, setConfirmBulkDelete] = useState(false); const items = vm.list?.items ?? []; @@ -126,6 +128,7 @@ export function TicketsPanel({ projectId, onOpen }: TicketsPanelProps) { } function toggleTicketSelection(ref: string, selected: boolean) { + setBulkNotice(null); setSelectedRefs((prev) => { const next = new Set(prev); if (selected) next.add(ref); @@ -135,6 +138,7 @@ export function TicketsPanel({ projectId, onOpen }: TicketsPanelProps) { } async function applyBulkStatus(nextStatus: TicketStatus | "") { + setBulkNotice(null); setBulkStatus(nextStatus); if (!nextStatus || selectedVisibleRefs.length === 0) return; const result = await vm.bulkUpdateStatus(selectedVisibleRefs, nextStatus); @@ -144,7 +148,26 @@ export function TicketsPanel({ projectId, onOpen }: TicketsPanelProps) { setBulkStatus(""); } + async function applyBulkSprint(sprint: Sprint | null) { + setBulkNotice(null); + const refs = selectedVisibleRefs; + if (refs.length === 0) return; + const result = await vm.bulkAssignSprint(refs, sprint?.id ?? null); + if (!result) return; + const failed = new Set(result.items.filter((i) => !i.ok).map((i) => i.ref)); + const successCount = result.items.length - failed.size; + setSelectedRefs(new Set(refs.filter((ref) => failed.has(ref)))); + setBulkNotice( + failed.size === 0 + ? `Sprint mis à jour pour ${successCount} ticket${ + successCount > 1 ? "s" : "" + }.` + : `Sprint mis à jour pour ${successCount}/${result.items.length} tickets. Les échecs restent sélectionnés.`, + ); + } + async function applyBulkDelete() { + setBulkNotice(null); const result = await vm.bulkDelete(selectedVisibleRefs); if (!result) return; const failed = new Set(result.items.filter((i) => !i.ok).map((i) => i.ref)); @@ -214,6 +237,14 @@ export function TicketsPanel({ projectId, onOpen }: TicketsPanelProps) { ]} onChange={(next) => void applyBulkStatus(next as TicketStatus | "")} /> +