mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-09 16:02:36 +01:00
fix(ui): retain PR links while monitors wait for execution
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
ee030bdf22
commit
c3604bf4b4
2 files changed
+34
-2
No files matched your search
@@ -235,6 +235,34 @@ describe("IssueMonitorBanner / IssueMonitorComposerStrip rendering", () => {
|
|||||||
flushSync(() => root.unmount());
|
flushSync(() => root.unmount());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each([-120_000, 120_000])("keeps pending PR links visible during an active run (offset: %s)", offset => {
|
||||||
|
const issue = { ...issueWithMonitor(new Date(NOW.getTime() + offset).toISOString()), status: "in_progress" as const };
|
||||||
|
issue.executionState!.monitor!.serviceName = "github";
|
||||||
|
const product = {
|
||||||
|
id: "pr-1", type: "pull_request", title: "Update runtime probe",
|
||||||
|
url: "https://github.com/example/repo/pull/42", status: "ready_for_review",
|
||||||
|
reviewState: "needs_board_review", updatedAt: NOW,
|
||||||
|
} as unknown as IssueWorkProduct;
|
||||||
|
const root = createRoot(container);
|
||||||
|
const render = (hasActiveRun: boolean, products = [product]) => flushSync(() => root.render(<>
|
||||||
|
<IssueMonitorBanner issue={issue} hasActiveRun={hasActiveRun} workProducts={products} onCheckNow={vi.fn()} />
|
||||||
|
<IssueMonitorComposerStrip issue={issue} hasActiveRun={hasActiveRun} workProducts={products} onCheckNow={vi.fn()} />
|
||||||
|
</>));
|
||||||
|
try {
|
||||||
|
render(true);
|
||||||
|
expect(container.textContent).toContain("Monitor waits for current run");
|
||||||
|
expect(Array.from(container.querySelectorAll("a")).map(link => link.href)).toEqual([product.url, product.url]);
|
||||||
|
expect(container.querySelector("button")).toBeNull();
|
||||||
|
expect(container.textContent).toContain("Review on GitHub while the current run finishes saving its work.");
|
||||||
|
expect(container.textContent).not.toMatch(/overdue|next tick|then check status/i);
|
||||||
|
render(false);
|
||||||
|
expect(container.textContent).toContain("Pull request review requested");
|
||||||
|
expect(Array.from(container.querySelectorAll("button")).map(button => button.textContent)).toEqual(["Check status", "Check status"]);
|
||||||
|
render(true, [{ ...product, metadata: { state: "merged" } }]);
|
||||||
|
expect(container.querySelector("a")).toBeNull();
|
||||||
|
} finally { flushSync(() => root.unmount()); }
|
||||||
|
});
|
||||||
|
|
||||||
it("explains automatic workspace waiting without promising that a reply bypasses the lock", () => {
|
it("explains automatic workspace waiting without promising that a reply bypasses the lock", () => {
|
||||||
const issue = {
|
const issue = {
|
||||||
status: "todo", scheduledRetry: { status: "scheduled_retry", scheduledRetryReason: "workspace_busy", scheduledRetryAt: NOW.toISOString() },
|
status: "todo", scheduledRetry: { status: "scheduled_retry", scheduledRetryReason: "workspace_busy", scheduledRetryAt: NOW.toISOString() },
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ export function buildMonitorSurfaceCopy(
|
|||||||
|
|
||||||
const eta = formatMonitorEta(derived.nextCheckAt, now); // "in 2h 12m" | "due now" | "overdue by 18m"
|
const eta = formatMonitorEta(derived.nextCheckAt, now); // "in 2h 12m" | "due now" | "overdue by 18m"
|
||||||
const absolute = formatMonitorAbsolute(derived.nextCheckAt, {}, now); // local time, e.g. "Today, 4:08 PM"
|
const absolute = formatMonitorAbsolute(derived.nextCheckAt, {}, now); // local time, e.g. "Today, 4:08 PM"
|
||||||
|
const awaitingPullRequestReview = derived.source === "monitor" && derived.serviceName?.toLowerCase() === "github" && pendingPullRequestReviews > 0;
|
||||||
if (derived.source === "monitor" && hasActiveRun) {
|
if (derived.source === "monitor" && hasActiveRun) {
|
||||||
const hint = "The check can start after the current run finishes saving its work.";
|
const hint = "The check can start after the current run finishes saving its work.";
|
||||||
return {
|
return {
|
||||||
@@ -128,9 +129,10 @@ export function buildMonitorSurfaceCopy(
|
|||||||
tone: "info",
|
tone: "info",
|
||||||
executionWait: true,
|
executionWait: true,
|
||||||
checkUnavailable: true,
|
checkUnavailable: true,
|
||||||
|
pullRequestReview: awaitingPullRequestReview,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (derived.source === "monitor" && derived.serviceName?.toLowerCase() === "github" && pendingPullRequestReviews > 0) {
|
if (awaitingPullRequestReview) {
|
||||||
return {
|
return {
|
||||||
bannerTitle: "Pull request review requested",
|
bannerTitle: "Pull request review requested",
|
||||||
stripTitle: "Pull request review requested",
|
stripTitle: "Pull request review requested",
|
||||||
@@ -351,7 +353,9 @@ export function IssueMonitorComposerStrip({
|
|||||||
</div>
|
</div>
|
||||||
{!copy.automaticChecksPaused ? (
|
{!copy.automaticChecksPaused ? (
|
||||||
<p className="mt-1.5 text-xs text-muted-foreground">
|
<p className="mt-1.5 text-xs text-muted-foreground">
|
||||||
{copy.pullRequestReview
|
{copy.pullRequestReview && copy.executionWait
|
||||||
|
? "Review on GitHub while the current run finishes saving its work."
|
||||||
|
: copy.pullRequestReview
|
||||||
? "Review on GitHub, then check status to have the agent verify the result."
|
? "Review on GitHub, then check status to have the agent verify the result."
|
||||||
: copy.workspaceWait || copy.executionWait
|
: copy.workspaceWait || copy.executionWait
|
||||||
? "You can keep sending instructions while the agent waits."
|
? "You can keep sending instructions while the agent waits."
|
||||||
|
|||||||
Reference in new issue
Block a user