feat(tickets): suppression d'un ticket (backend + frontend)
Ajoute la suppression complète d'un ticket (#6). Backend Rust : - port IssueStore::delete (NotFound si absent) + event IssueDeleted{freed_sprint} - FsIssueStore::delete : supprime .ideai/tickets/<N>/ et l'index sous lock - use case DeleteIssue + adaptations des tests sprint/ticket_assistant au port - commande Tauri ticket_delete + câblage events/state/lib Frontend : - gateway delete (ports, adapter ticket + mock, domain) - useTicketDetail : retrait de la liste et fermeture du détail via event issueDeleted - intégration TicketDetail + tests Tests verts : application/issue_usecases (6), infrastructure/issue_store (7), app-tauri --lib (56), frontend vitest (503), npm run build (exit 0). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -161,6 +161,59 @@ impl ReadIssue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Input for [`DeleteIssue::execute`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct DeleteIssueInput {
|
||||
/// Project owning the issue.
|
||||
pub project: Project,
|
||||
/// Issue reference.
|
||||
pub issue_ref: IssueRef,
|
||||
}
|
||||
|
||||
/// Output of [`DeleteIssue::execute`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct DeleteIssueOutput {
|
||||
/// Deleted issue reference.
|
||||
pub issue_ref: IssueRef,
|
||||
}
|
||||
|
||||
/// Deletes an issue.
|
||||
pub struct DeleteIssue {
|
||||
issues: Arc<dyn IssueStore>,
|
||||
events: Arc<dyn EventBus>,
|
||||
}
|
||||
|
||||
impl DeleteIssue {
|
||||
/// Builds the use case.
|
||||
#[must_use]
|
||||
pub fn new(issues: Arc<dyn IssueStore>, events: Arc<dyn EventBus>) -> Self {
|
||||
Self { issues, events }
|
||||
}
|
||||
|
||||
/// Executes deletion.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`AppError`] on missing issue or store failure.
|
||||
pub async fn execute(&self, input: DeleteIssueInput) -> Result<DeleteIssueOutput, AppError> {
|
||||
let issue = self
|
||||
.issues
|
||||
.get_by_ref(&input.project.root, input.issue_ref)
|
||||
.await?;
|
||||
let freed_sprint = issue.sprint;
|
||||
self.issues
|
||||
.delete(&input.project.root, input.issue_ref)
|
||||
.await?;
|
||||
self.events.publish(DomainEvent::IssueDeleted {
|
||||
project_id: input.project.id,
|
||||
issue_ref: input.issue_ref,
|
||||
freed_sprint,
|
||||
});
|
||||
Ok(DeleteIssueOutput {
|
||||
issue_ref: input.issue_ref,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Input for [`ReadIssueCarnet::execute`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ReadIssueCarnetInput {
|
||||
|
||||
@ -79,11 +79,11 @@ pub use git::{
|
||||
pub use health::{HealthInput, HealthReport, HealthUseCase};
|
||||
pub use issues::{
|
||||
AssignIssueAgent, AssignIssueAgentInput, AssignIssueAgentOutput, CreateIssue, CreateIssueInput,
|
||||
CreateIssueOutput, LinkIssues, LinkIssuesInput, LinkIssuesOutput, ListIssues, ListIssuesInput,
|
||||
ListIssuesOutput, ReadIssue, ReadIssueCarnet, ReadIssueCarnetInput, ReadIssueCarnetOutput,
|
||||
ReadIssueInput, ReadIssueOutput, UnlinkIssues, UnlinkIssuesInput, UpdateIssue,
|
||||
UpdateIssueCarnet, UpdateIssueCarnetInput, UpdateIssueCarnetOutput, UpdateIssueInput,
|
||||
UpdateIssueOutput,
|
||||
CreateIssueOutput, DeleteIssue, DeleteIssueInput, DeleteIssueOutput, LinkIssues,
|
||||
LinkIssuesInput, LinkIssuesOutput, ListIssues, ListIssuesInput, ListIssuesOutput, ReadIssue,
|
||||
ReadIssueCarnet, ReadIssueCarnetInput, ReadIssueCarnetOutput, ReadIssueInput, ReadIssueOutput,
|
||||
UnlinkIssues, UnlinkIssuesInput, UpdateIssue, UpdateIssueCarnet, UpdateIssueCarnetInput,
|
||||
UpdateIssueCarnetOutput, UpdateIssueInput, UpdateIssueOutput,
|
||||
};
|
||||
pub use layout::{
|
||||
CreateLayout, CreateLayoutInput, CreateLayoutOutput, DeleteLayout, DeleteLayoutInput,
|
||||
|
||||
Reference in New Issue
Block a user