feat(tickets): surface frontend V1 du système de tickets
Surface UI complète des tickets (domaine Issue exposé « ticket »), validée QA de bout en bout : cargo build + tests backend verts, npm run build + npm test (459) verts. - Domaine : DTO Ticket, 9 events Issue* + guard isTicketEvent. - Ports : TicketGateway (+ types query/input) ajouté à Gateways. - Adapters : TauriTicketGateway réel (+ isTicketVersionConflict), wiring, et MockTicketGateway pour les tests. - Feature tickets : hooks (useTickets, useTicketDetail, useProjectAgents), TicketsPanel, TicketDetail, TicketsView, ticketMeta + tests. - ProjectsView : onglet sidebar « Tickets ». Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -41,6 +41,12 @@ import type {
|
||||
SkillScope,
|
||||
Template,
|
||||
TerminalSession,
|
||||
Ticket,
|
||||
TicketCarnet,
|
||||
TicketLinkKind,
|
||||
TicketList,
|
||||
TicketPriority,
|
||||
TicketStatus,
|
||||
TurnPage,
|
||||
Unsubscribe,
|
||||
} from "@/domain";
|
||||
@ -688,6 +694,98 @@ export interface ConversationGateway {
|
||||
): Promise<TurnPage>;
|
||||
}
|
||||
|
||||
/** Filter/search criteria for {@link TicketGateway.list}. */
|
||||
export interface TicketListQuery {
|
||||
status?: TicketStatus;
|
||||
priority?: TicketPriority;
|
||||
assignedAgentId?: string;
|
||||
/** Free-text match over title/description. */
|
||||
text?: string;
|
||||
limit?: number;
|
||||
cursor?: string;
|
||||
}
|
||||
|
||||
/** Input for {@link TicketGateway.create}. */
|
||||
export interface CreateTicketInput {
|
||||
title: string;
|
||||
description?: string;
|
||||
priority?: TicketPriority;
|
||||
status?: TicketStatus;
|
||||
assignedAgentIds?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields to change on {@link TicketGateway.update}. Only the provided keys are
|
||||
* touched; `expectedVersion` is mandatory (optimistic concurrency — a stale
|
||||
* value surfaces a `versionConflict` {@link GatewayError}).
|
||||
*/
|
||||
export interface UpdateTicketInput {
|
||||
title?: string;
|
||||
description?: string;
|
||||
status?: TicketStatus;
|
||||
priority?: TicketPriority;
|
||||
assignedAgentIds?: string[];
|
||||
expectedVersion: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ticket gateway (public wire name for the backend `Issue` model). The only
|
||||
* frontend place that knows the `ticket_*` command names; features consume this
|
||||
* port through DI. Every mutation carries an `expectedVersion` and rejects with
|
||||
* a `versionConflict` {@link GatewayError} when the ticket moved underneath.
|
||||
*/
|
||||
export interface TicketGateway {
|
||||
/** Creates a ticket and returns it. */
|
||||
create(projectId: string, input: CreateTicketInput): Promise<Ticket>;
|
||||
/** Reads one ticket, optionally including its carnet body. */
|
||||
read(
|
||||
projectId: string,
|
||||
ref: string,
|
||||
includeCarnet?: boolean,
|
||||
): Promise<Ticket>;
|
||||
/** Lists tickets matching the (optional) filter/search query. */
|
||||
list(projectId: string, query?: TicketListQuery): Promise<TicketList>;
|
||||
/** Applies partial edits (title/description/status/priority/assignees). */
|
||||
update(
|
||||
projectId: string,
|
||||
ref: string,
|
||||
input: UpdateTicketInput,
|
||||
): Promise<Ticket>;
|
||||
/** Reads the ticket-scoped Markdown carnet. */
|
||||
readCarnet(projectId: string, ref: string): Promise<TicketCarnet>;
|
||||
/** Replaces (not appends) the ticket-scoped carnet body. */
|
||||
updateCarnet(
|
||||
projectId: string,
|
||||
ref: string,
|
||||
carnet: string,
|
||||
expectedVersion: number,
|
||||
): Promise<Ticket>;
|
||||
/** Links this ticket to another `#id` with the given relationship kind. */
|
||||
link(
|
||||
projectId: string,
|
||||
ref: string,
|
||||
targetRef: string,
|
||||
kind: TicketLinkKind,
|
||||
expectedVersion: number,
|
||||
): Promise<Ticket>;
|
||||
/** Removes a link (optionally scoped to a single kind). */
|
||||
unlink(
|
||||
projectId: string,
|
||||
ref: string,
|
||||
targetRef: string,
|
||||
expectedVersion: number,
|
||||
kind?: TicketLinkKind,
|
||||
): Promise<Ticket>;
|
||||
/** Assigns/unassigns an agent to the ticket. */
|
||||
assign(
|
||||
projectId: string,
|
||||
ref: string,
|
||||
agentId: string,
|
||||
assigned: boolean,
|
||||
expectedVersion: number,
|
||||
): Promise<Ticket>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The full set of gateways the app depends on, injected via the DI provider.
|
||||
* The composition (real vs mock) is chosen in `app/`.
|
||||
@ -709,4 +807,5 @@ export interface Gateways {
|
||||
permission: PermissionGateway;
|
||||
workState: WorkStateGateway;
|
||||
conversation: ConversationGateway;
|
||||
ticket: TicketGateway;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user