Make referrers clickable. #69
Conversation
|
@sbansal1999 is attempting to deploy a commit to the Databuddy Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThe Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~7 minutes Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (5)**/*.{ts,tsx}📄 CodeRabbit Inference Engine (.cursor/rules/01-MUST-DO.mdc)
Files:
**/*.{js,jsx,ts,tsx,css,scss}📄 CodeRabbit Inference Engine (.cursor/rules/01-MUST-DO.mdc)
Files:
**/*.{jsx,tsx}📄 CodeRabbit Inference Engine (.cursor/rules/01-MUST-DO.mdc)
|
There was a problem hiding this comment.
Actionable comments posted: 2
🔭 Outside diff range comments (3)
apps/dashboard/components/atomic/ReferrerSourceCell.tsx (3)
27-28: Guard against whitespace-only domainsIf domain is a string with only spaces, the current check will still render an anchor with an invalid href. Trim before deciding.
Apply this diff:
- if (displayName === 'Direct' || !domain) { + if (displayName === 'Direct' || !domain?.trim()) {
51-55: Conform to rounded class guidelinePer our CSS guideline, prefer rounded over rounded-sm.
Apply this diff:
- className="rounded-sm" + className="rounded"
29-33: Use cn in the “Direct” fallback for consistencyAvoid manual string concatenation; use cn like in the link path.
Apply this diff:
- <span - className={ - className ? `${className} font-medium text-sm` : 'font-medium text-sm' - } - id={id} - > + <span className={cn('font-medium text-sm', className)} id={id}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
apps/dashboard/components/atomic/ReferrerSourceCell.tsx(3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/01-MUST-DO.mdc)
Always ensure type-safety, don't use type: any unless needed, when creating APIs, responses, or components, create proper interfaces and make them in the shared types folders where it fits best, not in the same file
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use TypeScript namespaces.
Don't use the TypeScript directive @ts-ignore.
Don't use any type.
Don't use implicit any type on variable declarations.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't declare empty interfaces.
Use export type for types.
Use import type for types.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx
**/*.{js,jsx,ts,tsx,css,scss}
📄 CodeRabbit Inference Engine (.cursor/rules/01-MUST-DO.mdc)
Always use rounded, not rounded-xl or rounded-md, always rounded
Files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/01-MUST-DO.mdc)
**/*.{jsx,tsx}: Don't use lucide for icons, ONLY use phosphor icons, use width="duotone" for most, but for arrows use fill, for plus icons don't add width
ALWAYS use error boundaries properly
use Icon at the end of phosphor react icons, like CaretIcon not Caret
Almost NEVER use useEffect unless it's critical
**/*.{jsx,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't pass children as props.
Don't use the return value of React.render.
Make sure all dependencies are correctly specified in React hooks.
Make sure all React hooks are called from the top level of component functions.
Don't forget key props in iterators and collection literals.
Don't destructure props inside JSX components in Solid projects.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign to React component props.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use dangerous JSX props.
Don't use Array index in keys.
Don't insert comments as text nodes.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Watch out for possible "wrong" semicolons inside JSX elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Don't use distracting elements like or .
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use exp...Files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/01-MUST-DO.mdc)
**/*.{js,jsx,ts,tsx}: use console properly, like console.error, console.time, console.json, console.table, etc
Use Dayjs NEVER date-fns, and Tanstack query for hooks, NEVER SWR
Use ONLY Zod V4 from zod/v4 never zod 3 from zod
use json.stringify() when adding debugging
**/*.{js,jsx,ts,tsx}: Usebun <file>instead ofnode <file>orts-node <file>
Do not use dotenv; Bun automatically loads .env files
Do not useexpress; useBun.serve()for HTTP servers
Do not usebetter-sqlite3; usebun:sqlitefor SQLite
Do not useioredis; useBun.redisfor Redis
Do not usepgorpostgres.js; useBun.sqlfor Postgres
Do not usews; use built-inWebSocket
PreferBun.fileovernode:fs's readFile/writeFile
UseBun.$instead of execa for running shell commandsFiles:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx**/*.{js,ts,jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{js,ts,jsx,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't use global eval().
Don't use var.
Don't use console.
Don't use debugger.
Don't assign directly to document.cookie.
Don't use duplicate case labels.
Don't use duplicate class members.
Don't use duplicate function parameter names.
Don't use empty block statements and static blocks.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Use for...of statements instead of Array.forEach.
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names that aren't base 10 or use underscore separators.
Remove redundant terms from logical expressions.
Use while loops instead of for loops when you don't need initializer and update expressions.
Don't reassign const variables.
Don't use constant expressions in conditions.
Don't use Math.min and Math.max to clamp values when the result is constant.
Don't return a value from a constructor.
Don't use empty character classes in regular expression literals.
Don't use empty destructuring patterns.
Don't call global object properties as functions.
Don't declare functions and vars that are accessible outside their block.
Don't use variables and function parameters before they're declared.
Don't use 8 and 9 escape sequences in string literals.
Don't use literal numbers that lose precision.
Don't use duplicate conditions in if-else-if chains.
Don't use two keys with the same name inside objects...Files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx🧠 Learnings (14)
📓 Common learnings
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Make sure all anchors are valid and navigable.Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Make sure anchors have content that's accessible to screen readers.Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Make static elements with click handlers use a valid role attribute.📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Make sure all anchors are valid and navigable.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Make sure anchors have content that's accessible to screen readers.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Make static elements with click handlers use a valid role attribute.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Use semantic elements instead of role attributes in JSX.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Don't assign interactive ARIA roles to non-interactive HTML elements.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Don't use explicit role property that's the same as the implicit/default role.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Always include a title attribute for iframe elements.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Don't assign non-interactive ARIA roles to interactive HTML elements.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Use valid, non-abstract ARIA roles for elements with ARIA roles.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:40:18.511Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/01-MUST-DO.mdc:0-0 Timestamp: 2025-07-29T15:40:18.511Z Learning: Applies to **/*.{jsx,tsx} : use Icon at the end of phosphor react icons, like CaretIcon not CaretApplied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Accompany onMouseOver/onMouseOut with onFocus/onBlur.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.055Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.055Z Learning: Applies to **/*.{jsx,tsx} : Give all elements requiring alt text meaningful information for screen readers.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx📚 Learning: 2025-07-29T15:42:01.054Z
Learnt from: CR PR: databuddy-analytics/Databuddy#0 File: .cursor/rules/ultracite.mdc:0-0 Timestamp: 2025-07-29T15:42:01.054Z Learning: Applies to **/*.{jsx,tsx} : Use <>...</> instead of <Fragment>...</Fragment>.Applied to files:
apps/dashboard/components/atomic/ReferrerSourceCell.tsx⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
apps/dashboard/components/atomic/ReferrerSourceCell.tsx (2)
4-4: Import of cn utility looks goodConsistent with local utils and used correctly below.
42-45: Class composition is solid; keep using cn for consistencyUsing cn here is correct. Consider matching this approach in the “Direct” span for consistency (see separate comment).
| <a | ||
| className={cn( | ||
| 'flex cursor-pointer items-center gap-2 font-medium text-sm transition-colors hover:text-blue-600 hover:underline', | ||
| className | ||
| ? `${className} flex items-center gap-2 font-medium text-sm` | ||
| : 'flex items-center gap-2 font-medium text-sm' | ||
| } | ||
| )} | ||
| href={`https://${domain}`} | ||
| id={id} |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Normalize and validate href to ensure links are always valid
To align with our “anchors must be valid and navigable” learning, trim and encode the URL you generate. This avoids broken links from stray whitespace and unsafe characters.
Apply this diff:
- href={`https://${domain}`}
+ href={encodeURI(`https://${domain.trim()}`)}Optionally, for stronger validation, introduce a small helper and use it here:
// outside the component
function getValidatedHref(raw?: string): string | null {
if (!raw) return null;
const trimmed = raw.trim();
const prefixed = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
try {
const url = new URL(prefixed);
return url.protocol === 'http:' || url.protocol === 'https:' ? url.toString() : null;
} catch {
return null;
}
}Then inside the component:
const href = getValidatedHref(domain);and render span if !href.
🤖 Prompt for AI Agents
In apps/dashboard/components/atomic/ReferrerSourceCell.tsx around lines 41 to
47, the href attribute is directly constructed from the domain string without
normalization or validation, which can lead to broken or unsafe links. To fix
this, create a helper function that trims the domain, ensures it has an
http/https prefix, and validates it using the URL constructor, returning null if
invalid. Then, inside the component, use this helper to get a validated href; if
the href is null, render a span instead of an anchor to avoid invalid links.
|
Acknowledge coderabbit's comments please |
Fixes part of databuddy-analytics#26.
93862b6 to
0ad3773
Compare
|
Changes made:
Question: I wonder if we need to actually validate the URL using the function mentioned in this comment, due to how this data is coming. |
Fixes part of #26.
Not sure, what can be shown there as we already are showing the domain/name.
Summary by CodeRabbit