fix(tickets): normalise assignedAgentIds/links/attachments manquants sur les payloads legacy
Les lignes de ticket persistées avant l'introduction de ces champs peuvent arriver sans assignedAgentIds (ni links/attachments), ce que TicketsPanel déréférence sans garde côté rendu : la fenêtre de liste rend quelques lignes puis devient noire dès qu'une ligne legacy est itérée. Les deux gateways (Tauri et HTTP/stream) normalisent désormais chaque ticket et chaque item de liste avant de les retourner à l'UI. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@ -286,20 +286,53 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
private readonly ws: WsLiveClient,
|
||||
) {}
|
||||
|
||||
private normalizeTicket(ticket: Ticket): Ticket {
|
||||
return {
|
||||
...ticket,
|
||||
links: Array.isArray(ticket.links) ? ticket.links : [],
|
||||
assignedAgentIds: Array.isArray(ticket.assignedAgentIds)
|
||||
? ticket.assignedAgentIds
|
||||
: [],
|
||||
attachments: Array.isArray(ticket.attachments) ? ticket.attachments : [],
|
||||
};
|
||||
}
|
||||
|
||||
private normalizeTicketList(list: TicketList): TicketList {
|
||||
return {
|
||||
...list,
|
||||
items: Array.isArray(list.items)
|
||||
? list.items.map((item) => ({
|
||||
...item,
|
||||
assignedAgentIds: Array.isArray(item.assignedAgentIds)
|
||||
? item.assignedAgentIds
|
||||
: [],
|
||||
}))
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
create(projectId: string, input: CreateTicketInput): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_create", { request: { projectId, ...input } });
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_create", { request: { projectId, ...input } })
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
read(projectId: string, ref: string, includeCarnet = false): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_read", { request: { projectId, ref, includeCarnet } });
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_read", { request: { projectId, ref, includeCarnet } })
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
list(projectId: string, query?: TicketListQuery): Promise<TicketList> {
|
||||
const { statuses, priorities, ...rest } = query ?? {};
|
||||
return this.http.invoke<TicketList>("ticket_list", {
|
||||
request: { projectId, statuses: statuses ?? [], priorities: priorities ?? [], ...rest },
|
||||
});
|
||||
return this.http
|
||||
.invoke<TicketList>("ticket_list", {
|
||||
request: { projectId, statuses: statuses ?? [], priorities: priorities ?? [], ...rest },
|
||||
})
|
||||
.then((list) => this.normalizeTicketList(list));
|
||||
}
|
||||
update(projectId: string, ref: string, input: UpdateTicketInput): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_update", { request: { projectId, ref, ...input } });
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_update", { request: { projectId, ref, ...input } })
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
async delete(projectId: string, ref: string): Promise<void> {
|
||||
await this.http.invoke<void>("ticket_delete", { request: { projectId, ref } });
|
||||
@ -323,9 +356,11 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
return this.http.invoke<TicketCarnet>("ticket_read_carnet", { request: { projectId, ref } });
|
||||
}
|
||||
updateCarnet(projectId: string, ref: string, carnet: string, expectedVersion: number): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_update_carnet", {
|
||||
request: { projectId, ref, carnet, expectedVersion },
|
||||
});
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_update_carnet", {
|
||||
request: { projectId, ref, carnet, expectedVersion },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
addAttachment(
|
||||
projectId: string,
|
||||
@ -334,9 +369,11 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
expectedVersion: number,
|
||||
mime?: string | null,
|
||||
): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_attachment_add", {
|
||||
request: { projectId, ref, path, expectedVersion, mime },
|
||||
});
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_attachment_add", {
|
||||
request: { projectId, ref, path, expectedVersion, mime },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
readAttachment(
|
||||
projectId: string,
|
||||
@ -353,9 +390,11 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
attachmentId: string,
|
||||
expectedVersion: number,
|
||||
): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_attachment_mark_summarized", {
|
||||
request: { projectId, ref, attachmentId, expectedVersion },
|
||||
});
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_attachment_mark_summarized", {
|
||||
request: { projectId, ref, attachmentId, expectedVersion },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
link(
|
||||
projectId: string,
|
||||
@ -364,9 +403,11 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
kind: TicketLinkKind,
|
||||
expectedVersion: number,
|
||||
): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_link", {
|
||||
request: { projectId, ref, targetRef, kind, expectedVersion },
|
||||
});
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_link", {
|
||||
request: { projectId, ref, targetRef, kind, expectedVersion },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
unlink(
|
||||
projectId: string,
|
||||
@ -375,9 +416,11 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
expectedVersion: number,
|
||||
kind?: TicketLinkKind,
|
||||
): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_unlink", {
|
||||
request: { projectId, ref, targetRef, expectedVersion, kind },
|
||||
});
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_unlink", {
|
||||
request: { projectId, ref, targetRef, expectedVersion, kind },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
assign(
|
||||
projectId: string,
|
||||
@ -386,9 +429,11 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
assigned: boolean,
|
||||
expectedVersion: number,
|
||||
): Promise<Ticket> {
|
||||
return this.http.invoke<Ticket>("ticket_assign", {
|
||||
request: { projectId, ref, agentId, assigned, expectedVersion },
|
||||
});
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_assign", {
|
||||
request: { projectId, ref, agentId, assigned, expectedVersion },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
async listSprints(projectId: string): Promise<Sprint[]> {
|
||||
const list = await this.http.invoke<{ items: Sprint[] }>("sprint_list", { request: { projectId } });
|
||||
@ -401,11 +446,17 @@ export class HttpTicketGateway implements TicketGateway {
|
||||
expectedVersion: number,
|
||||
): Promise<Ticket> {
|
||||
if (sprintId === null) {
|
||||
return this.http.invoke<Ticket>("ticket_unassign_sprint", { request: { projectId, ref, expectedVersion } });
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_unassign_sprint", {
|
||||
request: { projectId, ref, expectedVersion },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
return this.http.invoke<Ticket>("ticket_assign_sprint", {
|
||||
request: { projectId, ref, sprintId, expectedVersion },
|
||||
});
|
||||
return this.http
|
||||
.invoke<Ticket>("ticket_assign_sprint", {
|
||||
request: { projectId, ref, sprintId, expectedVersion },
|
||||
})
|
||||
.then((ticket) => this.normalizeTicket(ticket));
|
||||
}
|
||||
createSprint(projectId: string, name: string): Promise<Sprint> {
|
||||
return this.http.invoke<Sprint>("sprint_create", { request: { projectId, name } });
|
||||
|
||||
Reference in New Issue
Block a user