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:
@ -14,26 +14,26 @@ use std::sync::{Arc, Mutex};
|
||||
use application::{
|
||||
AgentResumer, AgentWakeService, AppError, AssignIssueAgent, AssignSkillToAgent,
|
||||
AssignTicketToSprint, AttachLiveAgent, AuthenticateSession, BackgroundCommandArchive,
|
||||
BulkUpdateIssuePriority, BulkUpdateIssueStatus, CancelBackgroundTask, ChangeAgentProfile,
|
||||
CheckEmbedderSuggestion, CloneOpenCodeProfileFromSeed, CloneProfileFromSeed, CloseProject,
|
||||
CloseTab, CloseTerminal, CloseTicketAssistant, ConfigureProfiles, ContextGuardUseCases,
|
||||
CreateAgentFromScratch, CreateAgentFromTemplate, CreateIssue, CreateLayout, CreateMemory,
|
||||
CreateProject, CreateSkill, CreateSprint, CreateTemplate, DeleteAgent, DeleteEmbedderProfile,
|
||||
DeleteIssue, DeleteLayout, DeleteMemory, DeleteModelArtifact, DeleteModelServer, DeleteProfile,
|
||||
DeleteSkill, DeleteSprint, DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift,
|
||||
DetectProfiles, DismissEmbedderSuggestion, EnsureLocalModelServer, FirstRunState,
|
||||
GetAppExitWorkGuardState, GetLiveStateLean, GetMemory, GetProjectPermissions,
|
||||
GetProjectSystemPermissions, GetProjectWorkState, GitBranches, GitCheckout, GitCommit,
|
||||
GitGraph, GitInit, GitLog, GitStage, GitStatus, GitUnstage, HarvestMemoryFromTurn,
|
||||
HealthUseCase, InspectConversation, InstallPluginFromArchive, InstallPluginFromDirectory,
|
||||
JsonPluginManifestValidator, LaunchAgent, LaunchAgentInput, LinkIssues, ListAgents,
|
||||
ListAgentsInput, ListClaudeModels, ListCodexModels, ListDevices, ListEmbedderProfiles,
|
||||
ListIssues, ListLayouts, ListMemories, ListModelServers, ListOpenCodeProviders,
|
||||
ListPluginRuntimeContributions, ListPlugins, ListProfiles, ListProjects, ListResumableAgents,
|
||||
ListSkills, ListSprints, ListTemplates, LiveAgentRegistry, LiveSessions, LiveStateLeanProvider,
|
||||
LiveStateProvider, LiveStateReadProvider, LoadLayout, McpRuntime, McpToolPermissionCatalogue,
|
||||
MoveTabToNewWindow, MutateLayout, OnnxModelView, OpenProject, OpenTerminal,
|
||||
OpenTicketAssistant, OrchestratorService, PairAttemptLimiter, PairDevice,
|
||||
BulkDeleteIssues, BulkUpdateIssuePriority, BulkUpdateIssueStatus, CancelBackgroundTask,
|
||||
ChangeAgentProfile, CheckEmbedderSuggestion, CloneOpenCodeProfileFromSeed,
|
||||
CloneProfileFromSeed, CloseProject, CloseTab, CloseTerminal, CloseTicketAssistant,
|
||||
ConfigureProfiles, ContextGuardUseCases, CreateAgentFromScratch, CreateAgentFromTemplate,
|
||||
CreateIssue, CreateLayout, CreateMemory, CreateProject, CreateSkill, CreateSprint,
|
||||
CreateTemplate, DeleteAgent, DeleteEmbedderProfile, DeleteIssue, DeleteLayout, DeleteMemory,
|
||||
DeleteModelArtifact, DeleteModelServer, DeleteProfile, DeleteSkill, DeleteSprint,
|
||||
DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift, DetectProfiles,
|
||||
DismissEmbedderSuggestion, EnsureLocalModelServer, FirstRunState, GetAppExitWorkGuardState,
|
||||
GetLiveStateLean, GetMemory, GetProjectPermissions, GetProjectSystemPermissions,
|
||||
GetProjectWorkState, GitBranches, GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage,
|
||||
GitStatus, GitUnstage, HarvestMemoryFromTurn, HealthUseCase, InspectConversation,
|
||||
InstallPluginFromArchive, InstallPluginFromDirectory, JsonPluginManifestValidator, LaunchAgent,
|
||||
LaunchAgentInput, LinkIssues, ListAgents, ListAgentsInput, ListClaudeModels, ListCodexModels,
|
||||
ListDevices, ListEmbedderProfiles, ListIssues, ListLayouts, ListMemories, ListModelServers,
|
||||
ListOpenCodeProviders, ListPluginRuntimeContributions, ListPlugins, ListProfiles, ListProjects,
|
||||
ListResumableAgents, ListSkills, ListSprints, ListTemplates, LiveAgentRegistry, LiveSessions,
|
||||
LiveStateLeanProvider, LiveStateProvider, LiveStateReadProvider, LoadLayout, McpRuntime,
|
||||
McpToolPermissionCatalogue, MoveTabToNewWindow, MutateLayout, OnnxModelView, OpenProject,
|
||||
OpenTerminal, OpenTicketAssistant, OrchestratorService, PairAttemptLimiter, PairDevice,
|
||||
PermissionProjectorRegistry, ProposeContext, ReadAgentContext, ReadContext,
|
||||
ReadConversationPage, ReadIssue, ReadIssueCarnet, ReadMcpToolPermissions, ReadMemory,
|
||||
ReadMemoryIndex, ReadProjectContext, ReadSkill, ReadTemplate, RecallMemory, ReconcileLayouts,
|
||||
@ -991,6 +991,8 @@ pub struct BackendCore {
|
||||
pub bulk_update_issue_status: Arc<BulkUpdateIssueStatus>,
|
||||
/// Update public ticket priorities in batch.
|
||||
pub bulk_update_issue_priority: Arc<BulkUpdateIssuePriority>,
|
||||
/// Delete public tickets in batch.
|
||||
pub bulk_delete_issues: Arc<BulkDeleteIssues>,
|
||||
/// Read a ticket carnet.
|
||||
pub read_issue_carnet: Arc<ReadIssueCarnet>,
|
||||
/// Update a ticket carnet.
|
||||
@ -1684,6 +1686,10 @@ impl BackendCore {
|
||||
Arc::clone(&clock) as Arc<dyn Clock>,
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let bulk_delete_issues = Arc::new(BulkDeleteIssues::new(
|
||||
Arc::clone(&issue_store_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let read_issue_carnet = Arc::new(ReadIssueCarnet::new(Arc::clone(&issue_store_port)));
|
||||
let update_issue_carnet = Arc::new(UpdateIssueCarnet::new(
|
||||
Arc::clone(&issue_store_port),
|
||||
@ -2834,6 +2840,7 @@ impl BackendCore {
|
||||
update_issue,
|
||||
bulk_update_issue_status,
|
||||
bulk_update_issue_priority,
|
||||
bulk_delete_issues,
|
||||
read_issue_carnet,
|
||||
update_issue_carnet,
|
||||
link_issues,
|
||||
@ -4967,6 +4974,7 @@ mod mcp_serve_peer_tests {
|
||||
"idea_ticket_update_priority",
|
||||
"idea_ticket_bulk_update_status",
|
||||
"idea_ticket_bulk_update_priority",
|
||||
"idea_ticket_bulk_delete",
|
||||
"idea_ticket_read_carnet",
|
||||
"idea_ticket_update_carnet",
|
||||
"idea_ticket_link",
|
||||
@ -4987,8 +4995,8 @@ mod mcp_serve_peer_tests {
|
||||
assert!(!names.contains(&"idea_reply"));
|
||||
assert_eq!(
|
||||
tools.len(),
|
||||
33,
|
||||
"exactly the thirty-three exposed idea_* tools; got {names:?}"
|
||||
34,
|
||||
"exactly the thirty-four exposed idea_* tools; got {names:?}"
|
||||
);
|
||||
|
||||
drop(client); // EOF ⇒ serve loop ends
|
||||
|
||||
@ -357,7 +357,9 @@ fn is_ticket_policy_mutation_tool(name: &str) -> bool {
|
||||
fn is_ticket_policy_bulk_mutation_tool(name: &str) -> bool {
|
||||
matches!(
|
||||
name,
|
||||
"idea_ticket_bulk_update_status" | "idea_ticket_bulk_update_priority"
|
||||
"idea_ticket_bulk_update_status"
|
||||
| "idea_ticket_bulk_update_priority"
|
||||
| "idea_ticket_bulk_delete"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
Reference in New Issue
Block a user