bulk operations fixes

- Frontend: implémente bulkDelete, bulkArchive, bulkRestore
- Backend: adapts ticket DTOs pour bulk operations
- Infrastructure: MCP server pour gestion bulk tickets
- Tests: coverage frontend + backend
This commit is contained in:
2026-07-28 20:38:07 +02:00
parent 73c6081ab8
commit bd4f76ae74
19 changed files with 597 additions and 35 deletions

View File

@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize};
use uuid::Uuid;
use application::{
BulkIssueMutationOutput, BulkUpdateIssuePriorityInput, BulkUpdateIssueStatusInput,
CreateIssueInput, UpdateIssueInput,
BulkDeleteIssuesInput, BulkIssueMutationOutput, BulkUpdateIssuePriorityInput,
BulkUpdateIssueStatusInput, CreateIssueInput, UpdateIssueInput,
};
use domain::{
AgentId, AgentIssueRole, Issue, IssueActor, IssueCarnet, IssueIndexEntry, IssueLink,
@ -225,6 +225,15 @@ pub struct TicketBulkUpdatePriorityRequestDto {
pub priority: String,
}
/// Bulk delete request.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TicketBulkDeleteRequestDto {
#[serde(default)]
pub project_id: String,
pub refs: Vec<String>,
}
/// Bulk operation response.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@ -757,6 +766,16 @@ pub fn bulk_update_priority_input(
})
}
pub fn bulk_delete_input(
project: Project,
request: TicketBulkDeleteRequestDto,
) -> Result<BulkDeleteIssuesInput, ErrorDto> {
Ok(BulkDeleteIssuesInput {
project,
issue_refs: parse_bulk_refs(request.refs)?,
})
}
impl From<BulkIssueMutationOutput> for TicketBulkResultDto {
fn from(output: BulkIssueMutationOutput) -> Self {
Self {
@ -1272,6 +1291,27 @@ mod tests {
assert!(err.message.contains("duplicate ticket ref: #1"));
}
#[test]
fn bulk_delete_input_maps_refs_in_order() {
let input = bulk_delete_input(
project_for_tests(),
TicketBulkDeleteRequestDto {
project_id: String::new(),
refs: vec!["#2".into(), "#1".into()],
},
)
.unwrap();
assert_eq!(
input
.issue_refs
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>(),
vec!["#2", "#1"]
);
}
#[test]
fn actor_from_requester_maps_agent_uuid_else_user() {
let agent_id = AgentId::new_random();