[PULSE-52] Top Referrers favicons, display names, and merge by name #22

Merged
uz1mani merged 4 commits from staging into main 2026-02-11 16:07:28 +00:00
uz1mani commented 2026-02-11 16:03:58 +00:00 (Migrated from github.com)

Work Item

PULSE-52

Summary

  • Top Referrers card shows real site favicons (with fallback to icon for Direct/Unknown or on load failure).
  • Referrers show friendly names (e.g. "Google", "ChatGPT") via a heuristic from hostname plus a small override map for famous brands; new sites get a name without being added to a list.
  • Rows that map to the same display name are merged into one row with summed pageviews (e.g. one "ChatGPT" row instead of duplicates).

Changes

  • lib/utils/icons.tsx: getReferrerFavicon returns null for Direct/Unknown; added getReferrerDisplayName (heuristic: hostname → main label + capitalize, with REFERRER_DISPLAY_OVERRIDES for ChatGPT, LinkedIn, X, YouTube, etc.); added mergeReferrersByDisplayName to group by display name, sum pageviews, keep one referrer per group; expanded subdomain-skip set for label derivation.
  • components/dashboard/TopReferrers.tsx: Favicon-first rendering with onError fallback; display names via getReferrerDisplayName; merge via mergeReferrersByDisplayName for card and "View All" modal; tooltip still shows actual referrer.
  • components/dashboard/ExportModal.tsx: Import and use mergeReferrersByDisplayName and getReferrerDisplayName for PDF Top Referrers table so export uses merged rows and friendly names.
  • CHANGELOG.md: Entries under [0.3.0-alpha] for favicons (PULSE-52), display names (heuristic + overrides), and merge by name.

Test Plan

[ ] Open a site dashboard with Top Referrers data; confirm domain referrers show favicons and "Direct" shows globe icon.
[ ] Confirm friendly names (e.g. Google, Kagi, ChatGPT) and that unknown domains get a derived name (e.g. "Example" from example.com).
[ ] If multiple referrer strings map to the same name (e.g. chatgpt.com and https://chatgpt.com/...), confirm a single row with combined pageviews in card and "View All" modal.
[ ] Hover a row; tooltip shows actual referrer. Export PDF; Top Referrers table shows merged rows and same display names.

## Work Item PULSE-52 ## Summary - Top Referrers card shows real site favicons (with fallback to icon for Direct/Unknown or on load failure). - Referrers show friendly names (e.g. "Google", "ChatGPT") via a heuristic from hostname plus a small override map for famous brands; new sites get a name without being added to a list. - Rows that map to the same display name are merged into one row with summed pageviews (e.g. one "ChatGPT" row instead of duplicates). ## Changes - **lib/utils/icons.tsx:** `getReferrerFavicon` returns null for Direct/Unknown; added `getReferrerDisplayName` (heuristic: hostname → main label + capitalize, with `REFERRER_DISPLAY_OVERRIDES` for ChatGPT, LinkedIn, X, YouTube, etc.); added `mergeReferrersByDisplayName` to group by display name, sum pageviews, keep one referrer per group; expanded subdomain-skip set for label derivation. - **components/dashboard/TopReferrers.tsx:** Favicon-first rendering with `onError` fallback; display names via `getReferrerDisplayName`; merge via `mergeReferrersByDisplayName` for card and "View All" modal; tooltip still shows actual referrer. - **components/dashboard/ExportModal.tsx:** Import and use `mergeReferrersByDisplayName` and `getReferrerDisplayName` for PDF Top Referrers table so export uses merged rows and friendly names. - **CHANGELOG.md:** Entries under [0.3.0-alpha] for favicons (PULSE-52), display names (heuristic + overrides), and merge by name. ## Test Plan [ ] Open a site dashboard with Top Referrers data; confirm domain referrers show favicons and "Direct" shows globe icon. [ ] Confirm friendly names (e.g. Google, Kagi, ChatGPT) and that unknown domains get a derived name (e.g. "Example" from example.com). [ ] If multiple referrer strings map to the same name (e.g. chatgpt.com and https://chatgpt.com/...), confirm a single row with combined pageviews in card and "View All" modal. [ ] Hover a row; tooltip shows actual referrer. Export PDF; Top Referrers table shows merged rows and same display names.
greptile-apps[bot] commented 2026-02-11 16:20:19 +00:00 (Migrated from github.com)

Greptile Overview

Greptile Summary

This PR improves how referrers are presented across the dashboard and exports:

  • Adds referrer hostname parsing and a display-name heuristic (plus brand overrides), a favicon URL helper, and a merge-by-display-name utility in lib/utils/icons.tsx.
  • Updates TopReferrers.tsx to render favicons with a fallback icon, show friendly display names, and merge duplicate sources into a single row.
  • Updates the PDF export in ExportModal.tsx so the “Top Referrers” table uses the same merged rows and friendly names.
  • Updates CHANGELOG.md and bumps package.json version.

Main concerns are around stability/correctness of merging and favicon failure caching: the UI currently keys favicon failures by the raw referrer string even though merged groups can change which referrer string is retained, and the merge/display-name heuristic won’t merge certain non-URL referrer variants that fail URL parsing.

Confidence Score: 3/5

  • This PR is mergeable after addressing a couple of user-visible correctness/performance edge cases in referrer merging and favicon failure caching.
  • Core logic is straightforward and localized, but current grouping/normalization can still leave duplicates in realistic input formats, and favicon failure caching is keyed in a way that can repeatedly retry failing icons when the representative referrer changes after merging/fetching.
  • components/dashboard/TopReferrers.tsx, lib/utils/icons.tsx, package.json

Important Files Changed

Filename Overview
CHANGELOG.md Adds 0.3.0-alpha changelog entries and updates compare links for the new version.
components/dashboard/ExportModal.tsx Updates PDF export Top Referrers table to use merged rows and friendly display names.
components/dashboard/TopReferrers.tsx Renders favicons with onError fallback, uses friendly display names, and merges rows by display name; failure caching keyed by raw referrer may cause repeated retries when representative referrer changes.
lib/utils/icons.tsx Adds referrer hostname parsing, display-name heuristic/overrides, merge-by-display-name helper, and favicon URL helper; merging can miss non-URL referrer variants that fail URL parsing.
package.json Bumps package version to 0.3.0-alpha; may be premature depending on release process.

Sequence Diagram

sequenceDiagram
  participant Dashboard as Dashboard Page
  participant TR as TopReferrers.tsx
  participant Icons as lib/utils/icons.tsx
  participant API as lib/api/stats.getTopReferrers
  participant Google as google s2 favicon
  participant Export as ExportModal.tsx

  Dashboard->>TR: render(referrers[])
  TR->>Icons: mergeReferrersByDisplayName(referrers)
  Icons-->>TR: merged list (sorted)
  loop each displayed referrer
    TR->>Icons: getReferrerDisplayName(referrer)
    Icons-->>TR: display name
    TR->>Icons: getReferrerFavicon(referrer)
    Icons-->>TR: favicon URL or null
    alt favicon URL returned
      TR->>Google: GET /s2/favicons?domain=...
      alt load success
        Google-->>TR: image bytes
      else load error
        Google-->>TR: error
        TR-->>TR: mark faviconFailed(referrer)
        TR-->>TR: render getReferrerIcon fallback
      end
    else null favicon
      TR-->>TR: render getReferrerIcon
    end
  end

  TR->>API: getTopReferrers(siteId, start, end, 100) when modal opens
  API-->>TR: fullData[]
  TR->>Icons: mergeReferrersByDisplayName(fullData)
  Icons-->>TR: merged modal list

  Dashboard->>Export: export PDF(topReferrers[])
  Export->>Icons: mergeReferrersByDisplayName(topReferrers)
  Icons-->>Export: merged list
  Export->>Icons: getReferrerDisplayName(referrer)
  Icons-->>Export: display name for table
<h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR improves how referrers are presented across the dashboard and exports: - Adds referrer hostname parsing and a display-name heuristic (plus brand overrides), a favicon URL helper, and a merge-by-display-name utility in `lib/utils/icons.tsx`. - Updates `TopReferrers.tsx` to render favicons with a fallback icon, show friendly display names, and merge duplicate sources into a single row. - Updates the PDF export in `ExportModal.tsx` so the “Top Referrers” table uses the same merged rows and friendly names. - Updates `CHANGELOG.md` and bumps `package.json` version. Main concerns are around stability/correctness of merging and favicon failure caching: the UI currently keys favicon failures by the raw referrer string even though merged groups can change which referrer string is retained, and the merge/display-name heuristic won’t merge certain non-URL referrer variants that fail URL parsing. <h3>Confidence Score: 3/5</h3> - This PR is mergeable after addressing a couple of user-visible correctness/performance edge cases in referrer merging and favicon failure caching. - Core logic is straightforward and localized, but current grouping/normalization can still leave duplicates in realistic input formats, and favicon failure caching is keyed in a way that can repeatedly retry failing icons when the representative referrer changes after merging/fetching. - components/dashboard/TopReferrers.tsx, lib/utils/icons.tsx, package.json <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | CHANGELOG.md | Adds 0.3.0-alpha changelog entries and updates compare links for the new version. | | components/dashboard/ExportModal.tsx | Updates PDF export Top Referrers table to use merged rows and friendly display names. | | components/dashboard/TopReferrers.tsx | Renders favicons with onError fallback, uses friendly display names, and merges rows by display name; failure caching keyed by raw referrer may cause repeated retries when representative referrer changes. | | lib/utils/icons.tsx | Adds referrer hostname parsing, display-name heuristic/overrides, merge-by-display-name helper, and favicon URL helper; merging can miss non-URL referrer variants that fail URL parsing. | | package.json | Bumps package version to 0.3.0-alpha; may be premature depending on release process. | </details> </details> <h3>Sequence Diagram</h3> ```mermaid sequenceDiagram participant Dashboard as Dashboard Page participant TR as TopReferrers.tsx participant Icons as lib/utils/icons.tsx participant API as lib/api/stats.getTopReferrers participant Google as google s2 favicon participant Export as ExportModal.tsx Dashboard->>TR: render(referrers[]) TR->>Icons: mergeReferrersByDisplayName(referrers) Icons-->>TR: merged list (sorted) loop each displayed referrer TR->>Icons: getReferrerDisplayName(referrer) Icons-->>TR: display name TR->>Icons: getReferrerFavicon(referrer) Icons-->>TR: favicon URL or null alt favicon URL returned TR->>Google: GET /s2/favicons?domain=... alt load success Google-->>TR: image bytes else load error Google-->>TR: error TR-->>TR: mark faviconFailed(referrer) TR-->>TR: render getReferrerIcon fallback end else null favicon TR-->>TR: render getReferrerIcon end end TR->>API: getTopReferrers(siteId, start, end, 100) when modal opens API-->>TR: fullData[] TR->>Icons: mergeReferrersByDisplayName(fullData) Icons-->>TR: merged modal list Dashboard->>Export: export PDF(topReferrers[]) Export->>Icons: mergeReferrersByDisplayName(topReferrers) Icons-->>Export: merged list Export->>Icons: getReferrerDisplayName(referrer) Icons-->>Export: display name for table ```
greptile-apps[bot] (Migrated from github.com) reviewed 2026-02-11 16:20:26 +00:00
greptile-apps[bot] (Migrated from github.com) left a comment

5 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

<sub>5 files reviewed, 3 comments</sub> <sub>[Edit Code Review Agent Settings](https://app.greptile.com/review/github) | [Greptile](https://greptile.com?utm_source=greptile_expert&utm_medium=github&utm_campaign=code_reviews)</sub>
greptile-apps[bot] (Migrated from github.com) commented 2026-02-11 16:20:23 +00:00

Favicon failures not stable
faviconFailed is keyed by the raw referrer string, but the list is merged by display name and mergeReferrersByDisplayName can swap which referrer is kept for a group (it picks the maxSingle row). That means a group whose favicon URL consistently fails can keep retrying if the representative referrer changes (e.g., modal fetch vs card data), causing repeated failing requests and flicker.

Consider keying failures by a stable group key (e.g. hostname or display name) rather than the chosen representative referrer string.

Prompt To Fix With AI
This is a comment left during a code review.
Path: components/dashboard/TopReferrers.tsx
Line: 36:46

Comment:
**Favicon failures not stable**
`faviconFailed` is keyed by the raw `referrer` string, but the list is merged by display name and `mergeReferrersByDisplayName` can swap which `referrer` is kept for a group (it picks the maxSingle row). That means a group whose favicon URL consistently fails can keep retrying if the representative `referrer` changes (e.g., modal fetch vs card data), causing repeated failing requests and flicker.

Consider keying failures by a stable group key (e.g. hostname or display name) rather than the chosen representative referrer string.

How can I resolve this? If you propose a fix, please make it concise.
**Favicon failures not stable** `faviconFailed` is keyed by the raw `referrer` string, but the list is merged by display name and `mergeReferrersByDisplayName` can swap which `referrer` is kept for a group (it picks the maxSingle row). That means a group whose favicon URL consistently fails can keep retrying if the representative `referrer` changes (e.g., modal fetch vs card data), causing repeated failing requests and flicker. Consider keying failures by a stable group key (e.g. hostname or display name) rather than the chosen representative referrer string. <details><summary>Prompt To Fix With AI</summary> `````markdown This is a comment left during a code review. Path: components/dashboard/TopReferrers.tsx Line: 36:46 Comment: **Favicon failures not stable** `faviconFailed` is keyed by the raw `referrer` string, but the list is merged by display name and `mergeReferrersByDisplayName` can swap which `referrer` is kept for a group (it picks the maxSingle row). That means a group whose favicon URL consistently fails can keep retrying if the representative `referrer` changes (e.g., modal fetch vs card data), causing repeated failing requests and flicker. Consider keying failures by a stable group key (e.g. hostname or display name) rather than the chosen representative referrer string. How can I resolve this? If you propose a fix, please make it concise. ````` </details>
@@ -88,0 +161,4 @@
* Merges referrer rows that share the same display name (e.g. chatgpt.com and https://chatgpt.com/...),
* summing pageviews and keeping one referrer per group for icon/tooltip. Sorted by pageviews desc.
*/
export function mergeReferrersByDisplayName(
greptile-apps[bot] (Migrated from github.com) commented 2026-02-11 16:20:24 +00:00

Merge misses non-URLs
mergeReferrersByDisplayName groups by getReferrerDisplayName(), but getReferrerDisplayName returns the original trimmed string when getReferrerHostname() fails. If the backend sometimes returns referrers in slightly different non-URL formats (e.g. example.com/ vs example.com without a scheme so URL parsing fails), those won’t merge and you’ll still get duplicates.

If you intend to merge “domain-ish” strings that don’t parse as URLs, you likely need to normalize those cases before grouping.

Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/utils/icons.tsx
Line: 146:158

Comment:
**Merge misses non-URLs**
`mergeReferrersByDisplayName` groups by `getReferrerDisplayName()`, but `getReferrerDisplayName` returns the original trimmed string when `getReferrerHostname()` fails. If the backend sometimes returns referrers in slightly different non-URL formats (e.g. `example.com/` vs `example.com` without a scheme so URL parsing fails), those won’t merge and you’ll still get duplicates.

If you intend to merge “domain-ish” strings that don’t parse as URLs, you likely need to normalize those cases before grouping.

How can I resolve this? If you propose a fix, please make it concise.
**Merge misses non-URLs** `mergeReferrersByDisplayName` groups by `getReferrerDisplayName()`, but `getReferrerDisplayName` returns the original trimmed string when `getReferrerHostname()` fails. If the backend sometimes returns referrers in slightly different non-URL formats (e.g. `example.com/` vs `example.com` without a scheme so URL parsing fails), those won’t merge and you’ll still get duplicates. If you intend to merge “domain-ish” strings that don’t parse as URLs, you likely need to normalize those cases before grouping. <details><summary>Prompt To Fix With AI</summary> `````markdown This is a comment left during a code review. Path: lib/utils/icons.tsx Line: 146:158 Comment: **Merge misses non-URLs** `mergeReferrersByDisplayName` groups by `getReferrerDisplayName()`, but `getReferrerDisplayName` returns the original trimmed string when `getReferrerHostname()` fails. If the backend sometimes returns referrers in slightly different non-URL formats (e.g. `example.com/` vs `example.com` without a scheme so URL parsing fails), those won’t merge and you’ll still get duplicates. If you intend to merge “domain-ish” strings that don’t parse as URLs, you likely need to normalize those cases before grouping. How can I resolve this? If you propose a fix, please make it concise. ````` </details>
@@ -3,3 +3,3 @@
"version": "0.1.0-alpha",
"version": "0.3.0-alpha",
"private": true,
"scripts": {
greptile-apps[bot] (Migrated from github.com) commented 2026-02-11 16:20:25 +00:00

Version bump impacts releases
This PR bumps package.json to 0.3.0-alpha and updates the changelog links for v0.3.0-alpha. If your release/versioning flow expects versions to only change during an actual release/tag step, this will make future release automation or comparisons inconsistent.

Please confirm this version bump is intended for this PR (vs. leaving version unchanged until release).

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: package.json
Line: 1:4

Comment:
**Version bump impacts releases**
This PR bumps `package.json` to `0.3.0-alpha` and updates the changelog links for `v0.3.0-alpha`. If your release/versioning flow expects versions to only change during an actual release/tag step, this will make future release automation or comparisons inconsistent.

Please confirm this version bump is intended for this PR (vs. leaving version unchanged until release).

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.
**Version bump impacts releases** This PR bumps `package.json` to `0.3.0-alpha` and updates the changelog links for `v0.3.0-alpha`. If your release/versioning flow expects versions to only change during an actual release/tag step, this will make future release automation or comparisons inconsistent. Please confirm this version bump is intended for this PR (vs. leaving version unchanged until release). <sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub> <details><summary>Prompt To Fix With AI</summary> `````markdown This is a comment left during a code review. Path: package.json Line: 1:4 Comment: **Version bump impacts releases** This PR bumps `package.json` to `0.3.0-alpha` and updates the changelog links for `v0.3.0-alpha`. If your release/versioning flow expects versions to only change during an actual release/tag step, this will make future release automation or comparisons inconsistent. Please confirm this version bump is intended for this PR (vs. leaving version unchanged until release). <sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub> How can I resolve this? If you propose a fix, please make it concise. ````` </details>
Sign in to join this conversation.
No description provided.