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:
@ -29,6 +29,7 @@ import type {
|
||||
Sprint,
|
||||
TerminalSession,
|
||||
Ticket,
|
||||
TicketBulkResult,
|
||||
TicketCarnet,
|
||||
TicketChat,
|
||||
TicketLinkKind,
|
||||
@ -297,6 +298,21 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
async delete(projectId: string, ref: string): Promise<void> {
|
||||
await this.http.invoke<void>("ticket_delete", { request: { projectId, ref } });
|
||||
}
|
||||
bulkUpdateStatus(projectId: string, refs: string[], status: Ticket["status"]): Promise<TicketBulkResult> {
|
||||
return this.http.invoke<TicketBulkResult>("ticket_bulk_update_status", {
|
||||
request: { projectId, refs, status },
|
||||
});
|
||||
}
|
||||
bulkUpdatePriority(projectId: string, refs: string[], priority: Ticket["priority"]): Promise<TicketBulkResult> {
|
||||
return this.http.invoke<TicketBulkResult>("ticket_bulk_update_priority", {
|
||||
request: { projectId, refs, priority },
|
||||
});
|
||||
}
|
||||
bulkDelete(projectId: string, refs: string[]): Promise<TicketBulkResult> {
|
||||
return this.http.invoke<TicketBulkResult>("ticket_bulk_delete", {
|
||||
request: { projectId, refs },
|
||||
});
|
||||
}
|
||||
readCarnet(projectId: string, ref: string): Promise<TicketCarnet> {
|
||||
return this.http.invoke<TicketCarnet>("ticket_read_carnet", { request: { projectId, ref } });
|
||||
}
|
||||
|
||||
@ -66,6 +66,7 @@ import type {
|
||||
SystemPermissionSet,
|
||||
TerminalSession,
|
||||
Ticket,
|
||||
TicketBulkResult,
|
||||
TicketCarnet,
|
||||
TicketChat,
|
||||
TicketLink,
|
||||
@ -2910,6 +2911,75 @@ export class MockTicketGateway implements TicketGateway {
|
||||
});
|
||||
}
|
||||
|
||||
async bulkUpdateStatus(
|
||||
projectId: string,
|
||||
refs: string[],
|
||||
status: Ticket["status"],
|
||||
): Promise<TicketBulkResult> {
|
||||
const items = refs.map((ref) => {
|
||||
try {
|
||||
const ticket = this.require(projectId, ref);
|
||||
ticket.status = status;
|
||||
this.bump(ticket);
|
||||
this.system?.emit({
|
||||
type: "issueUpdated",
|
||||
issueRef: ref,
|
||||
version: ticket.version,
|
||||
});
|
||||
return { ref, ok: true, ticket: structuredClone(ticket) };
|
||||
} catch (error) {
|
||||
return { ref, ok: false, error: error as GatewayError };
|
||||
}
|
||||
});
|
||||
return { items };
|
||||
}
|
||||
|
||||
async bulkUpdatePriority(
|
||||
projectId: string,
|
||||
refs: string[],
|
||||
priority: Ticket["priority"],
|
||||
): Promise<TicketBulkResult> {
|
||||
const items = refs.map((ref) => {
|
||||
try {
|
||||
const ticket = this.require(projectId, ref);
|
||||
ticket.priority = priority;
|
||||
this.bump(ticket);
|
||||
this.system?.emit({
|
||||
type: "issueUpdated",
|
||||
issueRef: ref,
|
||||
version: ticket.version,
|
||||
});
|
||||
return { ref, ok: true, ticket: structuredClone(ticket) };
|
||||
} catch (error) {
|
||||
return { ref, ok: false, error: error as GatewayError };
|
||||
}
|
||||
});
|
||||
return { items };
|
||||
}
|
||||
|
||||
async bulkDelete(projectId: string, refs: string[]): Promise<TicketBulkResult> {
|
||||
const items = refs.map((ref) => {
|
||||
try {
|
||||
const ticket = this.require(projectId, ref);
|
||||
const deleted = structuredClone(ticket);
|
||||
const freedSprint = ticket.sprintId ?? null;
|
||||
this.projectTickets(projectId).delete(ref);
|
||||
this.projectCarnets(projectId).delete(ref);
|
||||
if (freedSprint) this.recountSprints(projectId);
|
||||
this.system?.emit({
|
||||
type: "issueDeleted",
|
||||
projectId,
|
||||
issueRef: ref,
|
||||
freedSprint,
|
||||
});
|
||||
return { ref, ok: true, ticket: deleted };
|
||||
} catch (error) {
|
||||
return { ref, ok: false, error: error as GatewayError };
|
||||
}
|
||||
});
|
||||
return { items };
|
||||
}
|
||||
|
||||
async readCarnet(projectId: string, ref: string): Promise<TicketCarnet> {
|
||||
const ticket = this.require(projectId, ref);
|
||||
return {
|
||||
|
||||
@ -17,6 +17,7 @@ import type {
|
||||
ReplyChunk,
|
||||
Sprint,
|
||||
Ticket,
|
||||
TicketBulkResult,
|
||||
TicketCarnet,
|
||||
TicketChat,
|
||||
TicketLinkKind,
|
||||
@ -90,6 +91,32 @@ export class TauriTicketGateway implements TicketGateway {
|
||||
});
|
||||
}
|
||||
|
||||
async bulkUpdateStatus(
|
||||
projectId: string,
|
||||
refs: string[],
|
||||
status: Ticket["status"],
|
||||
): Promise<TicketBulkResult> {
|
||||
return invoke<TicketBulkResult>("ticket_bulk_update_status", {
|
||||
request: { projectId, refs, status },
|
||||
});
|
||||
}
|
||||
|
||||
async bulkUpdatePriority(
|
||||
projectId: string,
|
||||
refs: string[],
|
||||
priority: Ticket["priority"],
|
||||
): Promise<TicketBulkResult> {
|
||||
return invoke<TicketBulkResult>("ticket_bulk_update_priority", {
|
||||
request: { projectId, refs, priority },
|
||||
});
|
||||
}
|
||||
|
||||
async bulkDelete(projectId: string, refs: string[]): Promise<TicketBulkResult> {
|
||||
return invoke<TicketBulkResult>("ticket_bulk_delete", {
|
||||
request: { projectId, refs },
|
||||
});
|
||||
}
|
||||
|
||||
async readCarnet(projectId: string, ref: string): Promise<TicketCarnet> {
|
||||
return invoke<TicketCarnet>("ticket_read_carnet", {
|
||||
request: { projectId, ref },
|
||||
|
||||
Reference in New Issue
Block a user