wip(tickets): backend createdBy (#5) + bulk status/priority/delete (#6)

Ajoute created_by sur IssueIndexEntry/TicketSummaryDto + filtre createdBy
(#5), et les use cases BulkUpdateIssueStatus/Priority + BulkDeleteIssues
avec les DTO/outils MCP idea_ticket_bulk_* associés (#6).

NON VERT : BulkDeleteIssues::execute référence BatchIssueResult::deleted(),
constructeur pas encore ajouté à BatchIssueResult (seuls ok/err existent) ->
`cargo check` échoue (E0599 dans application::issues::mod). Reste à
DevBackend avant toute QA/merge.

Branché sur feature/sdk-integration (dépend du commit #2 dans
orchestrator/mcp/server.rs et tools.rs) ; à rebaser sur develop une fois
feature/sdk-integration mergé.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 18:28:39 +02:00
parent 1ef1fd9e40
commit 6da52c6a02
20 changed files with 1061 additions and 34 deletions

View File

@ -29,6 +29,8 @@ pub struct AppTicketToolProvider {
pub read: Arc<application::ReadIssue>,
pub list: Arc<application::ListIssues>,
pub update: Arc<application::UpdateIssue>,
pub bulk_update_status: Arc<application::BulkUpdateIssueStatus>,
pub bulk_update_priority: Arc<application::BulkUpdateIssuePriority>,
pub read_carnet: Arc<application::ReadIssueCarnet>,
pub update_carnet: Arc<application::UpdateIssueCarnet>,
pub link: Arc<application::LinkIssues>,
@ -180,6 +182,28 @@ impl TicketToolProvider for AppTicketToolProvider {
.issue;
json!(TicketDto::from_issue(issue, None))
}
"idea_ticket_bulk_update_status" => {
let req = mcp_bulk_update_status_request(project, arguments)?;
let out = self
.bulk_update_status
.execute(
bulk_update_status_input(project.clone(), req, actor)
.map_err(dto_tool_error)?,
)
.await;
json!(TicketBulkResultDto::from(out))
}
"idea_ticket_bulk_update_priority" => {
let req = mcp_bulk_update_priority_request(project, arguments)?;
let out = self
.bulk_update_priority
.execute(
bulk_update_priority_input(project.clone(), req, actor)
.map_err(dto_tool_error)?,
)
.await;
json!(TicketBulkResultDto::from(out))
}
"idea_ticket_read_carnet" => {
let carnet = self
.read_carnet
@ -332,6 +356,40 @@ pub async fn ticket_delete(
.map_err(ErrorDto::from)
}
#[tauri::command]
pub async fn ticket_bulk_update_status(
request: TicketBulkUpdateStatusRequestDto,
state: State<'_, AppState>,
) -> Result<TicketBulkResultDto, ErrorDto> {
let project = resolve_project(&state, &request.project_id).await?;
let out = state
.bulk_update_issue_status
.execute(bulk_update_status_input(
project,
request,
IssueActor::User,
)?)
.await;
Ok(TicketBulkResultDto::from(out))
}
#[tauri::command]
pub async fn ticket_bulk_update_priority(
request: TicketBulkUpdatePriorityRequestDto,
state: State<'_, AppState>,
) -> Result<TicketBulkResultDto, ErrorDto> {
let project = resolve_project(&state, &request.project_id).await?;
let out = state
.bulk_update_issue_priority
.execute(bulk_update_priority_input(
project,
request,
IssueActor::User,
)?)
.await;
Ok(TicketBulkResultDto::from(out))
}
#[tauri::command]
pub async fn open_ticket_chat(
request: OpenTicketChatRequestDto,
@ -766,6 +824,26 @@ fn mcp_list_request(
TicketListPageInput::from_request(req).map_err(|e| TicketToolError::new("invalid", e.message))
}
fn mcp_bulk_update_status_request(
project: &Project,
arguments: Value,
) -> Result<TicketBulkUpdateStatusRequestDto, TicketToolError> {
let mut req: TicketBulkUpdateStatusRequestDto = serde_json::from_value(arguments)
.map_err(|e| TicketToolError::new("invalid", e.to_string()))?;
req.project_id = project.id.to_string();
Ok(req)
}
fn mcp_bulk_update_priority_request(
project: &Project,
arguments: Value,
) -> Result<TicketBulkUpdatePriorityRequestDto, TicketToolError> {
let mut req: TicketBulkUpdatePriorityRequestDto = serde_json::from_value(arguments)
.map_err(|e| TicketToolError::new("invalid", e.to_string()))?;
req.project_id = project.id.to_string();
Ok(req)
}
fn parse_json_ref(arguments: &Value, key: &str) -> Result<IssueRef, TicketToolError> {
required_str(arguments, key).and_then(|raw| parse_ref_dto(raw).map_err(dto_tool_error))
}