Skip to content

Commit 7b14693

Browse files
arul28claude
andcommitted
ship: iter 1 — address greptile #3133271501 and copilot #4307244389
- Memoize readInitialRouteState in PrsProvider so the four useState initializers share one window.location read (greptile P2). - Mirror PRsPage's resolveRouteRebaseSelection inside readInitialRouteState so the initial selectedRebaseItemId has the same shape as the post-effect value. - QueueTab.openRebaseTab now navigates to ?tab=workflows&workflow=rebase to keep URL in sync with state. - Normalize the "Open Rebase/Merge tab" label to sentence case across CreatePrModal, IntegrationTab; keep LaneGitActionsPane tooltip title case to match its sibling tooltips. - Restore prRebaseResolver.sendMessage displayText — it is used by agentChatService for the transcript text bubble. Verified locally: desktop tsc clean; 46 affected tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 19f429a commit 7b14693

7 files changed

Lines changed: 30 additions & 7 deletions

File tree

apps/desktop/src/main/services/prs/prRebaseResolver.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ describe("launchRebaseResolutionChat", () => {
142142
expect.objectContaining({
143143
sessionId: "session-rebase-1",
144144
reasoningEffort: "high",
145+
displayText: "Rebase feature/rebase-target onto main",
145146
}),
146147
);
147-
expect(sendMessage.mock.calls[0]?.[0]).not.toHaveProperty("displayText");
148148
expect(result).toEqual({
149149
sessionId: "session-rebase-1",
150150
laneId: lane.id,

apps/desktop/src/main/services/prs/prRebaseResolver.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ export async function launchRebaseResolutionChat(
158158
await deps.agentChatService.sendMessage({
159159
sessionId: session.id,
160160
text: prompt,
161+
// Show the short human-readable title in the transcript instead of the
162+
// full composed prompt (which is long and technical). Mirrors
163+
// prIssueResolver's pattern; agentChatService falls back to `text` when
164+
// displayText is absent, which would surface the raw prompt to the user.
165+
displayText: title,
161166
...(reasoningEffort ? { reasoningEffort } : {}),
162167
});
163168

apps/desktop/src/renderer/components/lanes/LaneGitActionsPane.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1571,7 +1571,7 @@ export function LaneGitActionsPane({
15711571
{autoRebaseStatus.state !== "autoRebased" ? (
15721572
isAutoRebaseFailure ? (
15731573
<SmartTooltip content={{
1574-
label: "Open Rebase/Merge tab",
1574+
label: "Open Rebase/Merge Tab",
15751575
description: "View detailed rebase information and resolve issues.",
15761576
effect: "Navigate to the rebase details view",
15771577
}}>

apps/desktop/src/renderer/components/prs/CreatePrModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ function LaneWarningPanel({
447447
cursor: "pointer",
448448
}}
449449
>
450-
Open Rebase/Merge Tab
450+
Open Rebase/Merge tab
451451
</button>
452452
<span style={{ fontSize: 10, color: C.textMuted, fontFamily: MONO_FONT }}>
453453
Review rebase status before PR creation{rebaseLaneIds.length > 1 ? ` (${rebaseLaneIds.length} lanes)` : ""}.

apps/desktop/src/renderer/components/prs/state/PrsContext.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { DEFAULT_PR_TIMELINE_FILTERS } from "../shared/PrTimeline";
3535
import { buildPrAiResolutionContextKey } from "../../../../shared/types";
3636
import { getModelById } from "../../../../shared/modelRegistry";
3737
import { parsePrsRouteState, resolvePrsActiveTab } from "../prsRouteState";
38+
import { resolveRouteRebaseSelection } from "../shared/rebaseNeedUtils";
3839

3940
type PrTab = "normal" | "queue" | "integration" | "rebase";
4041

@@ -232,7 +233,14 @@ function readInitialRouteState(): {
232233
? route.prId
233234
: null,
234235
selectedQueueGroupId: resolved.effectiveWorkflow === "queue" ? route.queueGroupId : null,
235-
selectedRebaseItemId: resolved.effectiveWorkflow === "rebase" ? route.laneId : null,
236+
// Mirror PRsPage's resolver so the shape of this id matches what the
237+
// rebase UI later expects. rebaseNeeds are empty at provider mount, so
238+
// this returns the bare lane id; PRsPage's syncFromLocation effect runs
239+
// the same resolver again once needs load and upgrades it to the
240+
// canonical need-item key.
241+
selectedRebaseItemId: resolved.effectiveWorkflow === "rebase"
242+
? resolveRouteRebaseSelection({ rebaseNeeds: [], routeItemId: route.laneId })
243+
: null,
236244
};
237245
} catch { /* ignore */ }
238246
return {
@@ -284,7 +292,11 @@ function diffPrIds(prev: PrWithConflicts[], next: PrWithConflicts[]): string[] {
284292
}
285293

286294
export function PrsProvider({ children }: { children: React.ReactNode }) {
287-
const initialRouteState = readInitialRouteState();
295+
// Compute initial route state exactly once per provider mount. Reading
296+
// window.location + running parsePrsRouteState/resolvePrsActiveTab on every
297+
// render would be wasteful; useMemo with empty deps captures it once so all
298+
// four useState calls below share a single computation.
299+
const initialRouteState = useMemo(() => readInitialRouteState(), []);
288300
const [activeTab, setActiveTab] = useState<PrTab>(initialRouteState.activeTab);
289301
const [prs, setPrs] = useState<PrWithConflicts[]>([]);
290302
const [lanes, setLanes] = useState<LaneSummary[]>([]);

apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ function RebaseGuidancePanel({
161161
navigate({ pathname: "/prs", search: `?${search.toString()}` });
162162
}}
163163
>
164-
OPEN REBASE/MERGE TAB
164+
Open Rebase/Merge tab
165165
</button>
166166
{onResimulate ? (
167167
<button

apps/desktop/src/renderer/components/prs/tabs/QueueTab.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,13 @@ export function QueueTab({
469469
const need = findLaneBaseNeed(visibleRebaseNeeds, laneId);
470470
setSelectedRebaseItemId(need ? rebaseNeedItemKey(need) : null);
471471
setActiveTab("rebase");
472-
}, [setActiveTab, setSelectedRebaseItemId, visibleRebaseNeeds]);
472+
// Keep the URL in sync with the tab switch so deep links / back-button
473+
// behaviour match other openRebaseTab migrations (CreatePrModal,
474+
// IntegrationTab). The `laneId` drives PRsPage's resolveRouteRebaseSelection
475+
// on the receiving side.
476+
const search = new URLSearchParams({ tab: "workflows", workflow: "rebase", laneId });
477+
navigate({ pathname: "/prs", search: `?${search.toString()}` });
478+
}, [navigate, setActiveTab, setSelectedRebaseItemId, visibleRebaseNeeds]);
473479

474480
const handleLandCurrentPr = React.useCallback(async () => {
475481
if (!selectedGroup) return;

0 commit comments

Comments
 (0)