Core: In app hint to discover v1 beta#1749
Conversation
Greptile SummaryThis PR adds a v1 beta badge to the app titlebar and consolidates the beta destination URL across existing in-app entry points (changelog modal and notification card), backed by a new Confidence Score: 5/5Safe to merge; all findings are P2 style suggestions with no correctness or data-integrity concerns. The implementation is correct — Electron-safe link handling, proper Radix Slot pattern, existing tests updated, and new tests added. The only open items are a cosmetic campaign name and a trivial missing useMemo, both P2. src/shared/urls.ts — minor campaign name clarification worth considering before the analytics data accumulates.
|
| Filename | Overview |
|---|---|
| src/shared/urls.ts | Adds EMDASH_DOWNLOAD_URL constant, withUtmParams helper, and getEmdashV1BetaUrl factory; campaign value 'v0-banner-link' is misleading for a v1-beta promotion |
| src/renderer/components/ui/badge.tsx | Extended Badge with asChild/Slot pattern using standard Radix UI approach; clean and correct |
| src/renderer/components/titlebar/Titlebar.tsx | Adds v1 beta badge to titlebar using asChild Badge + anchor with Electron-safe openExternal handler; betaUrl could be memoized |
| src/renderer/components/ChangelogModal.tsx | Swaps static EMDASH_WEBSITE_URL for tracked beta URL via getEmdashV1BetaUrl; straightforward and correct |
| src/renderer/components/sidebar/ChangelogNotificationCard.tsx | Same URL swap as ChangelogModal for the sidebar notification card; no issues |
| src/renderer/components/ProjectMainView.tsx | Project header layout updated to flex-col/sm:flex-row for responsive wrapping; visual-only change |
| src/test/renderer/Badge.test.tsx | New test verifying asChild renders an anchor with correct href and class; adequate coverage |
| src/test/shared/urls.test.ts | Tests UTM param construction and preservation of pre-existing query params; good coverage |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User clicks beta link] --> B{Entry point}
B --> |Titlebar Badge| C["getEmdashV1BetaUrl('titlebar-badge')"]
B --> |Changelog Modal| D["getEmdashV1BetaUrl('changelog-modal')"]
B --> |Notification Card| E["getEmdashV1BetaUrl('changelog-notification-card')"]
C --> F["withUtmParams(EMDASH_DOWNLOAD_URL, utm)"]
D --> F
E --> F
F --> G["URL with utm_source=emdash-app, utm_medium=in-app, utm_campaign=v0-banner-link, utm_content=entry-point"]
G --> H["window.electronAPI.openExternal(url)"]
H --> I[System browser → emdash.sh/download]
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/shared/urls.ts
Line: 29
Comment:
**Campaign name mismatch**
The campaign value is `'v0-banner-link'`, but `getEmdashV1BetaUrl` is used in three call sites (titlebar badge, changelog modal, and changelog notification card) — only the titlebar badge could be described as a "banner." More importantly, the campaign name reads as if it belongs to a v0 product while the function explicitly promotes the v1 beta. Analytics dashboards will attribute all three entry points to "v0-banner-link," which could make it harder to reason about the campaign's performance.
```suggestion
campaign: 'v1-beta-download',
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/renderer/components/titlebar/Titlebar.tsx
Line: 137
Comment:
**URL constructed on every render**
`getEmdashV1BetaUrl` allocates a `URL` object and calls `searchParams.set` on every render of `Titlebar`. Since the result is a deterministic constant, wrapping it in `useMemo` (or hoisting it outside the component) avoids unnecessary allocations on each render cycle.
```suggestion
const betaUrl = useMemo(() => getEmdashV1BetaUrl('titlebar-badge'), []);
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "Add a subtle v1 beta entry point" | Re-trigger Greptile
| return withUtmParams(EMDASH_DOWNLOAD_URL, { | ||
| source: 'emdash-app', | ||
| medium: 'in-app', | ||
| campaign: 'v0-banner-link', |
There was a problem hiding this comment.
The campaign value is 'v0-banner-link', but getEmdashV1BetaUrl is used in three call sites (titlebar badge, changelog modal, and changelog notification card) — only the titlebar badge could be described as a "banner." More importantly, the campaign name reads as if it belongs to a v0 product while the function explicitly promotes the v1 beta. Analytics dashboards will attribute all three entry points to "v0-banner-link," which could make it harder to reason about the campaign's performance.
| campaign: 'v0-banner-link', | |
| campaign: 'v1-beta-download', |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/shared/urls.ts
Line: 29
Comment:
**Campaign name mismatch**
The campaign value is `'v0-banner-link'`, but `getEmdashV1BetaUrl` is used in three call sites (titlebar badge, changelog modal, and changelog notification card) — only the titlebar badge could be described as a "banner." More importantly, the campaign name reads as if it belongs to a v0 product while the function explicitly promotes the v1 beta. Analytics dashboards will attribute all three entry points to "v0-banner-link," which could make it harder to reason about the campaign's performance.
```suggestion
campaign: 'v1-beta-download',
```
How can I resolve this? If you propose a fix, please make it concise.| const [isHeaderHovered, setIsHeaderHovered] = useState(false); | ||
| const feedbackButtonRef = useRef<HTMLButtonElement | null>(null); | ||
| const headerRef = useRef<HTMLElement | null>(null); | ||
| const betaUrl = getEmdashV1BetaUrl('titlebar-badge'); |
There was a problem hiding this comment.
URL constructed on every render
getEmdashV1BetaUrl allocates a URL object and calls searchParams.set on every render of Titlebar. Since the result is a deterministic constant, wrapping it in useMemo (or hoisting it outside the component) avoids unnecessary allocations on each render cycle.
| const betaUrl = getEmdashV1BetaUrl('titlebar-badge'); | |
| const betaUrl = useMemo(() => getEmdashV1BetaUrl('titlebar-badge'), []); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/renderer/components/titlebar/Titlebar.tsx
Line: 137
Comment:
**URL constructed on every render**
`getEmdashV1BetaUrl` allocates a `URL` object and calls `searchParams.set` on every render of `Titlebar`. Since the result is a deterministic constant, wrapping it in `useMemo` (or hoisting it outside the component) avoids unnecessary allocations on each render cycle.
```suggestion
const betaUrl = useMemo(() => getEmdashV1BetaUrl('titlebar-badge'), []);
```
How can I resolve this? If you propose a fix, please make it concise.
Summary
Validation