Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit e1d4e43

Browse files
authored
fix(product-view): PR URLs, toolbar overflow, and mid-login view resets
- parseGithubRemote: trim the remote URL — `git remote get-url` output ends with a newline, which stopped the ".git" suffix from being stripped, so merged-PR links pointed at github.com/<owner>/<repo>.git/pull/N (404) and the gh open-PR lookup got a garbage --repo value. Also accept ssh:// remotes. - toolbar: flex-wrap the row and truncate pill labels / the data badge so environments flow to a second line instead of crushing the URL bar. - stop resetting the embedded page mid-session: create() no longer navigates an existing view back to the environment's debounce-persisted URL, and the slot effect no longer tears down/reopens when the environments query refetches — either could yank a multi-step login back to a stale page. Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
1 parent e440bc3 commit e1d4e43

5 files changed

Lines changed: 46 additions & 22 deletions

File tree

apps/code/src/main/platform-adapters/electron-embedded-browser.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,14 @@ export class ElectronEmbeddedBrowser
7777
async create(options: EmbeddedBrowserCreateOptions): Promise<void> {
7878
const existing = this.views.get(options.viewId);
7979
if (existing) {
80-
// Re-opening a kept-alive view (tab switch back): re-glue and re-show it;
81-
// only navigate when the caller actually wants a different page.
80+
// Re-opening a kept-alive view (tab switch back): re-glue and re-show
81+
// it exactly where the user left it. Never navigate here — options.url
82+
// is the environment's SAVED url, which lags the live page (it's
83+
// debounce-persisted), so "restoring" it would yank an in-progress
84+
// flow (a multi-step login, a checkout) back to a stale page.
85+
// Explicit navigation goes through navigate().
8286
this.setBounds(options.viewId, options.bounds);
8387
existing.setVisible(true);
84-
if (existing.webContents.getURL() !== options.url) {
85-
await this.navigate(options.viewId, options.url);
86-
}
8788
this.emitPageState(options.viewId, existing);
8889
return;
8990
}

packages/ui/src/features/product-view/ProductView.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ function ProductBrowser(props: {
186186

187187
return (
188188
<div className="flex h-full flex-col">
189-
<div className="flex items-center gap-1 border-gray-4 border-b px-2 py-1.5">
189+
{/* flex-wrap: with several environments (or a narrow window) the row
190+
flows onto a second line instead of crushing the URL bar. */}
191+
<div className="flex flex-wrap items-center gap-1 border-gray-4 border-b px-2 py-1.5">
190192
<Button
191193
size="icon-sm"
192194
aria-label="Back"
@@ -211,7 +213,7 @@ function ProductBrowser(props: {
211213
<ArrowClockwiseIcon size={14} />
212214
</Button>
213215
<Input
214-
className="h-7 flex-1 font-mono text-xs"
216+
className="h-7 min-w-48 flex-1 font-mono text-xs"
215217
value={draftUrl ?? currentUrl}
216218
onChange={(e) => setDraftUrl(e.target.value)}
217219
onFocus={(e) => e.target.select()}
@@ -259,9 +261,9 @@ function ProductBrowser(props: {
259261
</Button>
260262
<Badge
261263
variant="default"
262-
title="Analytics overlaid on this page come from this PostHog project"
264+
title={`Analytics overlaid on this page come from the "${dataProjectName}" PostHog project`}
263265
>
264-
Data: {dataProjectName}
266+
<span className="max-w-40 truncate">Data: {dataProjectName}</span>
265267
</Badge>
266268
</div>
267269
<div className="flex min-h-0 flex-1 flex-row">
@@ -323,7 +325,7 @@ function EnvironmentPill(props: {
323325
) : (
324326
<GlobeIcon size={14} />
325327
)}
326-
{environment.label}
328+
<span className="max-w-32 truncate">{environment.label}</span>
327329
</Button>
328330
}
329331
/>

packages/ui/src/features/product-view/useProductView.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ export function useProductViewSlot(input: {
6767
const setBoundsMutate = setBounds.mutate;
6868
const setVisibleMutate = setVisible.mutate;
6969

70+
// url/dataProjectId are only consumed when the view is first opened; they
71+
// must NOT be effect deps. The url is the environment's persisted currentUrl,
72+
// which updates (via query refetch) as the user browses — re-running the
73+
// effect on that would hide/reopen the live view mid-session.
74+
const openParamsRef = useRef({ url, dataProjectId });
75+
openParamsRef.current = { url, dataProjectId };
76+
7077
useEffect(() => {
7178
const slot = slotRef.current;
7279
if (!slot) return;
@@ -89,7 +96,14 @@ export function useProductViewSlot(input: {
8996
lastRect = key;
9097
if (!openedRef.current) {
9198
openedRef.current = true;
92-
void openMutate({ viewId, url, bounds, dataProjectId }).catch(() => {
99+
const { url: openUrl, dataProjectId: openProjectId } =
100+
openParamsRef.current;
101+
void openMutate({
102+
viewId,
103+
url: openUrl,
104+
bounds,
105+
dataProjectId: openProjectId,
106+
}).catch(() => {
93107
openedRef.current = false;
94108
});
95109
} else {
@@ -117,14 +131,7 @@ export function useProductViewSlot(input: {
117131
setVisibleMutate({ viewId, visible: false });
118132
openedRef.current = false;
119133
};
120-
}, [
121-
viewId,
122-
url,
123-
dataProjectId,
124-
openMutate,
125-
setBoundsMutate,
126-
setVisibleMutate,
127-
]);
134+
}, [viewId, openMutate, setBoundsMutate, setVisibleMutate]);
128135

129136
// Renderer overlays (command menu, toolbar menus) cannot paint over the
130137
// native view — hide the view while any of them is open.

packages/workspace-server/src/services/product-view/prImpact.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ describe("parseGithubRemote", () => {
3232
"https://github.com/PostHog/posthog",
3333
{ owner: "PostHog", repo: "posthog" },
3434
],
35+
// `git remote get-url` output has a trailing newline — must not leak
36+
// ".git" into the repo name (broken /pull/ URLs).
37+
[
38+
"https://github.com/PostHog/posthog.git\n",
39+
{ owner: "PostHog", repo: "posthog" },
40+
],
41+
[
42+
"ssh://git@github.com/PostHog/posthog.git",
43+
{ owner: "PostHog", repo: "posthog" },
44+
],
3545
["https://gitlab.com/x/y.git", null],
3646
["nonsense", null],
3747
])("%s", (remote, expected) => {

packages/workspace-server/src/services/product-view/prImpact.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ export function extractPrNumber(subject: string): number | null {
3131
export function parseGithubRemote(
3232
remoteUrl: string,
3333
): { owner: string; repo: string } | null {
34-
const match = remoteUrl.match(
35-
/^(?:https:\/\/github\.com\/|git@github\.com:)([^/]+)\/([^/]+?)(?:\.git)?\/?$/,
36-
);
34+
// `git remote get-url` output arrives with a trailing newline; without the
35+
// trim the repo group swallows ".git" and every PR URL 404s.
36+
const match = remoteUrl
37+
.trim()
38+
.match(
39+
/^(?:https:\/\/github\.com\/|(?:ssh:\/\/)?git@github\.com[:/])([^/]+)\/([^/]+?)(?:\.git)?\/?$/,
40+
);
3741
if (!match) return null;
3842
return { owner: match[1], repo: match[2] };
3943
}

0 commit comments

Comments
 (0)