authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-07 22:40:40-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-07 22:40:40-03:00
log8588d7f63bf57e6285daafe035708cc22a99619c
treee4879c3c0756b41cbdfb7514187d293eccc5447f
parent299404a754f52c02c69634528d8856b3c93b378c
signature Signed by PGP key B5690EEEBB952194

fix(web): open proactive panels when entering threads (#10610)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

4 files changed, 19 insertions(+), 12 deletions(-)

apps/web/src/components/ChatView.logic.test.ts+10-6
......@@ -190,7 +190,7 @@ describe("proactive panels", () => {
190190 expect(selectActiveRightPanelSurface(useRightPanelStore.getState().byThreadKey, ref)).toEqual(
191191 oldPr,
192192 );
193 expect(shouldOpenProactivePullRequest(loaded.targetKey, "owner/repo:2")).toBe(false);
193 expect(shouldOpenProactivePullRequest(loaded.targetKey, "owner/repo:2")).toBe(true);
194194 expect(
195195 shouldOpenProactiveTurnDiff({
196196 previousRunningTurnId: loaded.runningTurnId,
......@@ -198,7 +198,10 @@ describe("proactive panels", () => {
198198 settledTurnId: turnId,
199199 turnCompleted: true,
200200 }),
201 ).toBe(false);
201 ).toBe(true);
202 expect(panels.openProactive(ref, { id: "diff", kind: "diff" }, loaded.userActionRevision)).toBe(
203 false,
204 );
202205 });
203206
204207 it.each(["idle", "loading", "observed"] as const)(
......@@ -245,8 +248,9 @@ describe("proactive panels", () => {
245248 },
246249 );
247250
248 it("opens a pull request only after a newly observed link appears", () => {
249 expect(shouldOpenProactivePullRequest(undefined, "project:repo:42")).toBe(false);
251 it("opens an existing pull request on entry and follows newly observed links", () => {
252 expect(shouldOpenProactivePullRequest(undefined, "project:repo:42")).toBe(true);
253 expect(shouldOpenProactivePullRequest(undefined, null)).toBe(false);
250254 expect(shouldOpenProactivePullRequest(null, "project:repo:42")).toBe(true);
251255 expect(shouldOpenProactivePullRequest("project:repo:42", "project:repo:42")).toBe(false);
252256 expect(shouldOpenProactivePullRequest("project:repo:42", null)).toBe(false);
......@@ -286,7 +290,7 @@ describe("proactive panels", () => {
286290 ).toBe(false);
287291 });
288292
289 it("opens the diff only when the observed running turn settles", () => {
293 it("opens a completed diff on entry or when the observed running turn settles", () => {
290294 const turnId = TurnId.make("turn-1");
291295 expect(
292296 shouldOpenProactiveTurnDiff({
......@@ -295,7 +299,7 @@ describe("proactive panels", () => {
295299 settledTurnId: turnId,
296300 turnCompleted: true,
297301 }),
298 ).toBe(false);
302 ).toBe(true);
299303 expect(
300304 shouldOpenProactiveTurnDiff({
301305 previousRunningTurnId: turnId,
apps/web/src/components/ChatView.logic.ts+4-4
......@@ -104,7 +104,7 @@ export function shouldOpenProactivePullRequest(
104104 previousTargetKey: string | null | undefined,
105105 targetKey: string | null,
106106): boolean {
107 return previousTargetKey !== undefined && targetKey !== null && targetKey !== previousTargetKey;
107 return targetKey !== null && targetKey !== previousTargetKey;
108108}
109109
110110interface ProactivePanelObservation {
......@@ -158,11 +158,11 @@ export function shouldOpenProactiveTurnDiff(input: {
158158 turnCompleted: boolean;
159159}): boolean {
160160 return (
161 input.previousRunningTurnId !== undefined &&
162 input.previousRunningTurnId !== null &&
163161 input.runningTurnId === null &&
164162 input.turnCompleted &&
165 input.settledTurnId === input.previousRunningTurnId
163 input.settledTurnId !== null &&
164 (input.previousRunningTurnId === undefined ||
165 input.settledTurnId === input.previousRunningTurnId)
166166 );
167167}
168168
apps/web/src/components/ChatView.tsx+2-1
......@@ -4095,7 +4095,8 @@ export default function ChatView(props: ChatViewProps) {
40954095 const shouldDeferLink = eligibleLink && !pullRequestsCapabilityKnown;
40964096 proactivePanelObservationRef.current = {
40974097 ...observation,
4098 runningTurnId: diffAction === "defer" ? (previousRunningTurnId ?? null) : activeRunningTurnId,
4098 // Preserve first-entry eligibility while the checkpoint or repository is loading.
4099 runningTurnId: diffAction === "defer" ? previousRunningTurnId : activeRunningTurnId,
40994100 targetKey: shouldDeferLink ? (previousTargetKey ?? null) : linkedThreadPullRequestKey,
41004101 };
41014102
apps/web/src/rightPanelStore.test.ts+3-1
......@@ -29,15 +29,17 @@ describe("rightPanelStore", () => {
2929 });
3030
3131 it.each(["diff-first", "pull-request-first"])(
32 "keeps the linked pull request above the completed diff with %s delivery",
32 "prioritizes the linked pull request over browser and diff with %s delivery",
3333 (order) => {
3434 const store = useRightPanelStore.getState();
35 store.openBrowser(refA, "existing-browser");
3536 const revision = store.getUserActionRevision(refA);
3637 const requests =
3738 order === "diff-first"
3839 ? [completedDiff, linkedPullRequest]
3940 : [linkedPullRequest, completedDiff];
4041 for (const surface of requests) store.openProactive(refA, surface, revision);
42 store.reconcileBrowserSurfaces(refA, ["existing-browser", "agent-browser"]);
4143
4244 expect(
4345 selectActiveRightPanelSurface(useRightPanelStore.getState().byThreadKey, refA),