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", () => {...@@ -190,7 +190,7 @@ describe("proactive panels", () => {
190 expect(selectActiveRightPanelSurface(useRightPanelStore.getState().byThreadKey, ref)).toEqual(190 expect(selectActiveRightPanelSurface(useRightPanelStore.getState().byThreadKey, ref)).toEqual(
191 oldPr,191 oldPr,
192 );192 );
193 expect(shouldOpenProactivePullRequest(loaded.targetKey, "owner/repo:2")).toBe(false);193 expect(shouldOpenProactivePullRequest(loaded.targetKey, "owner/repo:2")).toBe(true);
194 expect(194 expect(
195 shouldOpenProactiveTurnDiff({195 shouldOpenProactiveTurnDiff({
196 previousRunningTurnId: loaded.runningTurnId,196 previousRunningTurnId: loaded.runningTurnId,
...@@ -198,7 +198,10 @@ describe("proactive panels", () => {...@@ -198,7 +198,10 @@ describe("proactive panels", () => {
198 settledTurnId: turnId,198 settledTurnId: turnId,
199 turnCompleted: true,199 turnCompleted: true,
200 }),200 }),
201 ).toBe(false);201 ).toBe(true);
202 expect(panels.openProactive(ref, { id: "diff", kind: "diff" }, loaded.userActionRevision)).toBe(
203 false,
204 );
202 });205 });
203206
204 it.each(["idle", "loading", "observed"] as const)(207 it.each(["idle", "loading", "observed"] as const)(
...@@ -245,8 +248,9 @@ describe("proactive panels", () => {...@@ -245,8 +248,9 @@ describe("proactive panels", () => {
245 },248 },
246 );249 );
247250
248 it("opens a pull request only after a newly observed link appears", () => {251 it("opens an existing pull request on entry and follows newly observed links", () => {
249 expect(shouldOpenProactivePullRequest(undefined, "project:repo:42")).toBe(false);252 expect(shouldOpenProactivePullRequest(undefined, "project:repo:42")).toBe(true);
253 expect(shouldOpenProactivePullRequest(undefined, null)).toBe(false);
250 expect(shouldOpenProactivePullRequest(null, "project:repo:42")).toBe(true);254 expect(shouldOpenProactivePullRequest(null, "project:repo:42")).toBe(true);
251 expect(shouldOpenProactivePullRequest("project:repo:42", "project:repo:42")).toBe(false);255 expect(shouldOpenProactivePullRequest("project:repo:42", "project:repo:42")).toBe(false);
252 expect(shouldOpenProactivePullRequest("project:repo:42", null)).toBe(false);256 expect(shouldOpenProactivePullRequest("project:repo:42", null)).toBe(false);
...@@ -286,7 +290,7 @@ describe("proactive panels", () => {...@@ -286,7 +290,7 @@ describe("proactive panels", () => {
286 ).toBe(false);290 ).toBe(false);
287 });291 });
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", () => {
290 const turnId = TurnId.make("turn-1");294 const turnId = TurnId.make("turn-1");
291 expect(295 expect(
292 shouldOpenProactiveTurnDiff({296 shouldOpenProactiveTurnDiff({
...@@ -295,7 +299,7 @@ describe("proactive panels", () => {...@@ -295,7 +299,7 @@ describe("proactive panels", () => {
295 settledTurnId: turnId,299 settledTurnId: turnId,
296 turnCompleted: true,300 turnCompleted: true,
297 }),301 }),
298 ).toBe(false);302 ).toBe(true);
299 expect(303 expect(
300 shouldOpenProactiveTurnDiff({304 shouldOpenProactiveTurnDiff({
301 previousRunningTurnId: turnId,305 previousRunningTurnId: turnId,
apps/web/src/components/ChatView.logic.ts+4-4
...@@ -104,7 +104,7 @@ export function shouldOpenProactivePullRequest(...@@ -104,7 +104,7 @@ export function shouldOpenProactivePullRequest(
104 previousTargetKey: string | null | undefined,104 previousTargetKey: string | null | undefined,
105 targetKey: string | null,105 targetKey: string | null,
106): boolean {106): boolean {
107 return previousTargetKey !== undefined && targetKey !== null && targetKey !== previousTargetKey;107 return targetKey !== null && targetKey !== previousTargetKey;
108}108}
109109
110interface ProactivePanelObservation {110interface ProactivePanelObservation {
...@@ -158,11 +158,11 @@ export function shouldOpenProactiveTurnDiff(input: {...@@ -158,11 +158,11 @@ export function shouldOpenProactiveTurnDiff(input: {
158 turnCompleted: boolean;158 turnCompleted: boolean;
159}): boolean {159}): boolean {
160 return (160 return (
161 input.previousRunningTurnId !== undefined &&
162 input.previousRunningTurnId !== null &&
163 input.runningTurnId === null &&161 input.runningTurnId === null &&
164 input.turnCompleted &&162 input.turnCompleted &&
165 input.settledTurnId === input.previousRunningTurnId163 input.settledTurnId !== null &&
164 (input.previousRunningTurnId === undefined ||
165 input.settledTurnId === input.previousRunningTurnId)
166 );166 );
167}167}
168168
apps/web/src/components/ChatView.tsx+2-1
...@@ -4095,7 +4095,8 @@ export default function ChatView(props: ChatViewProps) {...@@ -4095,7 +4095,8 @@ export default function ChatView(props: ChatViewProps) {
4095 const shouldDeferLink = eligibleLink && !pullRequestsCapabilityKnown;4095 const shouldDeferLink = eligibleLink && !pullRequestsCapabilityKnown;
4096 proactivePanelObservationRef.current = {4096 proactivePanelObservationRef.current = {
4097 ...observation,4097 ...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,
4099 targetKey: shouldDeferLink ? (previousTargetKey ?? null) : linkedThreadPullRequestKey,4100 targetKey: shouldDeferLink ? (previousTargetKey ?? null) : linkedThreadPullRequestKey,
4100 };4101 };
41014102
apps/web/src/rightPanelStore.test.ts+3-1
...@@ -29,15 +29,17 @@ describe("rightPanelStore", () => {...@@ -29,15 +29,17 @@ describe("rightPanelStore", () => {
29 });29 });
3030
31 it.each(["diff-first", "pull-request-first"])(31 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",
33 (order) => {33 (order) => {
34 const store = useRightPanelStore.getState();34 const store = useRightPanelStore.getState();
35 store.openBrowser(refA, "existing-browser");
35 const revision = store.getUserActionRevision(refA);36 const revision = store.getUserActionRevision(refA);
36 const requests =37 const requests =
37 order === "diff-first"38 order === "diff-first"
38 ? [completedDiff, linkedPullRequest]39 ? [completedDiff, linkedPullRequest]
39 : [linkedPullRequest, completedDiff];40 : [linkedPullRequest, completedDiff];
40 for (const surface of requests) store.openProactive(refA, surface, revision);41 for (const surface of requests) store.openProactive(refA, surface, revision);
42 store.reconcileBrowserSurfaces(refA, ["existing-browser", "agent-browser"]);
4143
42 expect(44 expect(
43 selectActiveRightPanelSurface(useRightPanelStore.getState().byThreadKey, refA),45 selectActiveRightPanelSurface(useRightPanelStore.getState().byThreadKey, refA),