mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-18 11:40:39 +09:00
Improve queued comment thread UX
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
4226e15128
commit
74687553f3
4 changed files with 331 additions and 107 deletions
|
|
@ -2,6 +2,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|||
import {
|
||||
applyOptimisticIssueCommentUpdate,
|
||||
createOptimisticIssueComment,
|
||||
isQueuedIssueComment,
|
||||
mergeIssueComments,
|
||||
upsertIssueComment,
|
||||
} from "./optimistic-issue-comments";
|
||||
|
|
@ -46,6 +47,20 @@ describe("optimistic issue comments", () => {
|
|||
mathSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("supports queued optimistic comments for active-run follow-ups", () => {
|
||||
const comment = createOptimisticIssueComment({
|
||||
companyId: "company-1",
|
||||
issueId: "issue-1",
|
||||
body: "Queue this",
|
||||
authorUserId: "board-1",
|
||||
clientStatus: "queued",
|
||||
queueTargetRunId: "run-1",
|
||||
});
|
||||
|
||||
expect(comment.clientStatus).toBe("queued");
|
||||
expect(comment.queueTargetRunId).toBe("run-1");
|
||||
});
|
||||
|
||||
it("merges optimistic comments into the server thread in chronological order", () => {
|
||||
const merged = mergeIssueComments(
|
||||
[
|
||||
|
|
@ -161,4 +176,40 @@ describe("optimistic issue comments", () => {
|
|||
expect(next?.assigneeAgentId).toBeNull();
|
||||
expect(next?.assigneeUserId).toBe("board-2");
|
||||
});
|
||||
|
||||
it("treats comments without a run id as queued when they arrive during an active run", () => {
|
||||
expect(
|
||||
isQueuedIssueComment({
|
||||
comment: {
|
||||
createdAt: new Date("2026-03-28T16:20:05.000Z"),
|
||||
},
|
||||
activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"),
|
||||
runId: null,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("does not mark comments with an associated run as queued", () => {
|
||||
expect(
|
||||
isQueuedIssueComment({
|
||||
comment: {
|
||||
createdAt: new Date("2026-03-28T16:20:05.000Z"),
|
||||
},
|
||||
activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"),
|
||||
runId: "run-1",
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("does not mark interrupt comments as queued", () => {
|
||||
expect(
|
||||
isQueuedIssueComment({
|
||||
comment: {
|
||||
createdAt: new Date("2026-03-28T16:20:05.000Z"),
|
||||
},
|
||||
activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"),
|
||||
interruptedRunId: "run-1",
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ export interface IssueCommentReassignment {
|
|||
|
||||
export interface OptimisticIssueComment extends IssueComment {
|
||||
clientId: string;
|
||||
clientStatus: "pending";
|
||||
clientStatus: "pending" | "queued";
|
||||
queueTargetRunId?: string | null;
|
||||
}
|
||||
|
||||
export type IssueTimelineComment = IssueComment | OptimisticIssueComment;
|
||||
|
|
@ -37,23 +38,39 @@ export function createOptimisticIssueComment(params: {
|
|||
issueId: string;
|
||||
body: string;
|
||||
authorUserId: string | null;
|
||||
clientStatus?: OptimisticIssueComment["clientStatus"];
|
||||
queueTargetRunId?: string | null;
|
||||
}): OptimisticIssueComment {
|
||||
const now = new Date();
|
||||
const clientId = createOptimisticCommentId();
|
||||
return {
|
||||
id: clientId,
|
||||
clientId,
|
||||
clientStatus: "pending",
|
||||
companyId: params.companyId,
|
||||
issueId: params.issueId,
|
||||
authorAgentId: null,
|
||||
authorUserId: params.authorUserId,
|
||||
body: params.body,
|
||||
clientStatus: params.clientStatus ?? "pending",
|
||||
queueTargetRunId: params.queueTargetRunId ?? null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
}
|
||||
|
||||
export function isQueuedIssueComment(params: {
|
||||
comment: Pick<IssueTimelineComment, "createdAt"> & Partial<Pick<OptimisticIssueComment, "clientStatus">>;
|
||||
activeRunStartedAt?: Date | string | null;
|
||||
runId?: string | null;
|
||||
interruptedRunId?: string | null;
|
||||
}) {
|
||||
if (params.runId) return false;
|
||||
if (params.interruptedRunId) return false;
|
||||
if (params.comment.clientStatus === "queued") return true;
|
||||
if (!params.activeRunStartedAt) return false;
|
||||
return toTimestamp(params.comment.createdAt) >= toTimestamp(params.activeRunStartedAt);
|
||||
}
|
||||
|
||||
export function mergeIssueComments(
|
||||
comments: IssueComment[] | undefined,
|
||||
optimisticComments: OptimisticIssueComment[],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue