-
Notifications
You must be signed in to change notification settings - Fork 619
Dashboard: Update Project header style #7920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dashboard: Update Project header style #7920
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
WalkthroughReplace avatar-based header with an icon renderer and optional settings button; remove the "settings" LinkType from LinkGroup and simplify single-link vs dropdown rendering; update many UI icons, button variants, and sizing. No backend or control-flow changes beyond header/link rendering. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Page as Page (various)
participant Header as ProjectPageHeader
participant LG as LinkGroup
Page->>Header: Render(header: { icon?, isProjectIcon?, title, description, links?, settings?, actions? })
alt header.settings exists
Header->>Header: Render Settings button -> link to header.settings.href
end
alt header.links exists
Header->>LG: Render LinkGroup(links)
alt links.length == 1
LG->>LG: Render direct Link (outline Button with Icon + label)
else multiple links
LG->>LG: Render "Resources" Button (label + chevron) -> open DropdownMenu
note right of LG: DropdownMenuItems = Link-wrapped DropdownMenuItem (external handling preserved)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7920 +/- ##
=======================================
Coverage 56.53% 56.53%
=======================================
Files 904 904
Lines 58592 58592
Branches 4143 4143
=======================================
Hits 33126 33126
Misses 25360 25360
Partials 106 106
🚀 New features to boost your workflow:
|
size-limit report 📦
|
671b409 to
d5eb851
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx (1)
186-193: Disable submit while pending to avoid duplicate importsWithout disabling, rapid clicks can fire multiple mutations and create duplicate Engine records. You already render a spinner; wire it to the disabled state.
Apply this diff:
- <Button className="min-w-28 gap-1.5 rounded-full" type="submit"> + <Button + className="min-w-28 gap-1.5 rounded-full" + type="submit" + disabled={importMutation.isPending} + aria-busy={importMutation.isPending} + >Optional follow-up: also disable the form fields while
isPendingto prevent edits mid-request.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx (1)
3-9: Fixparamstyping and avoid unnecessaryasync
paramsis not a Promise in Next.js app router layouts, and the function isn’t awaiting anything. Also add an explicit return type.Apply:
-export default async function Layout(props: { - children: React.ReactNode; - params: Promise<{ - team_slug: string; - project_slug: string; - }>; -}) { +export default function Layout(props: { + children: React.ReactNode; + params: { + team_slug: string; + project_slug: string; + }; +}): JSX.Element {
🧹 Nitpick comments (12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx (5)
110-116: Prevent accidental form submit: set the trigger button’s type to "button"The DialogTrigger sits inside a form. Depending on our Button default, this may submit the form when opening the dialog. Be explicit.
Apply this diff:
- <Button - className="gap-2 rounded-full bg-card" - size="sm" - variant="outline" - > + <Button + type="button" + className="gap-2 rounded-full bg-card" + size="sm" + variant="outline" + >
114-114: Icon sizing nit: size-3.5 is fine and on-scaleThe 14px target works well for a small trigger. No issues.
If you want tighter optical alignment with the label baseline, consider size-4 with a slight negative tracking on the text, but current choice is acceptable.
74-80: Prefer defaultValues over values to avoid unintended resetsUsing
valuescan cause form resets when the object identity changes across renders.defaultValuesis safer here; if you need to react toprefillImportUrlchanges, callform.resetin an effect.Apply this diff:
const form = useForm<ImportEngineParams>({ resolver: zodResolver(formSchema), - values: { + defaultValues: { name: "", url: props.prefillImportUrl || "", }, });
82-87: Move navigation to onSuccess for cleaner separation of concernsKeep the mutation function pure (data work only) and handle side-effects in React Query callbacks.
Apply this diff:
- const importMutation = useMutation({ - mutationFn: async (importParams: ImportEngineParams) => { - await importEngine({ ...importParams, teamIdOrSlug: props.teamSlug }); - router.push(`/team/${props.teamSlug}/${props.projectSlug}/engine`); - }, - }); + const importMutation = useMutation({ + mutationFn: async (importParams: ImportEngineParams) => + importEngine({ ...importParams, teamIdOrSlug: props.teamSlug }), + onSuccess: () => { + router.push(`/team/${props.teamSlug}/${props.projectSlug}/engine`); + }, + });
63-66: Verify apiServerProxy error shape before accessing res.errorIf apiServerProxy returns a Fetch Response-like object,
res.errormay be undefined. Guard the access or provide a fallback message.Possible tweak:
- if (!res.ok) { - throw new Error(res.error); - } + if (!res.ok) { + const message = + typeof (res as any).error === "string" + ? (res as any).error + : "Failed to import Engine"; + throw new Error(message); + }If
apiServerProxyguarantees{ ok: boolean; error?: string }, feel free to ignore this.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx (1)
8-8: InsightIcon import resolves locally; consider centralizing duplicate implementationsImporting
import { InsightIcon } from "@/icons/InsightIcon";in the dashboard app correctly resolves to
apps/dashboard/src/@/icons/InsightIcon.tsxand does not pull in the playground-web or portal versions.• apps/dashboard/src/@/icons/InsightIcon.tsx (local implementation)
• apps/playground-web/src/icons/InsightIcon.tsx (duplicate in playground-web)
• apps/portal/src/icons/products/InsightIcon.tsx (duplicate in portal)Optional refactor: extract all icons into a shared package (e.g.
packages/ui/icons), export them from a single barrel (e.g.packages/ui/icons/index.ts), and update imports across apps to eliminate drift.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx (1)
1-1: Mark this as a Server ComponentPer dashboard guidelines, add the server-only directive to prevent accidental client-side import of this module.
Apply this diff:
+import "server-only"; import { ArrowUpFromLineIcon } from "lucide-react";apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx (1)
23-27: Add an explicit return type for the componentKeep TS strict and consistent with repo guidelines by annotating the return type.
Apply:
-export function ProjectSidebarLayout(props: { +export function ProjectSidebarLayout(props: { layoutPath: string; children: React.ReactNode; hasEngineInstances: boolean; -}) { +}): JSX.Element {apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (4)
60-62: Broaden icon type to accept lucide and custom iconslucide-react icons are
ComponentType/forwardRef-based, not strictlyReact.FC. UsingReact.ComponentTypeis more accurate and flexible.Apply:
- icon: React.FC<{ className?: string }>; + icon: React.ComponentType<{ className?: string }>;
26-41: Map “secondary” to the new outline style and add bg-cardThe PR standardizes secondary actions to
variant="outline"withbg-card. Reflect that here.Apply:
-function Action(props: { action: Action; variant?: "default" | "secondary" }) { +function Action(props: { action: Action; variant?: "default" | "secondary" }) { const action = props.action; + const buttonVariant = props.variant === "secondary" ? "outline" : (props.variant ?? "default"); return "component" in action ? ( action.component ) : ( <Button asChild className={cn( "rounded-full", - props.variant === "secondary" && "border border-border", + buttonVariant === "outline" && "border border-border bg-card", )} size="sm" - variant={props.variant} + variant={buttonVariant} >
77-79: Add explicit return typeKeep component signatures explicit per TS guidelines.
Apply:
-export function ProjectPageHeader(props: ProjectPageHeaderProps) { +export function ProjectPageHeader(props: ProjectPageHeaderProps): JSX.Element {
55-75: Remove unusedclientandimageUrlprops fromProjectPageHeaderPropsI ran the ripgrep checks and confirmed:
- No instances of
client=orimageUrl=when rendering<ProjectPageHeader />anywhere inapps/dashboard.- No internal references to
props.clientorprops.imageUrlwithinproject-page-header.tsxbeyond their type declarations.Those props are unused and can safely be removed to slim the API surface and avoid confusion.
• File needing update:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx(lines 55–75)
• Removeclient: ThirdwebClient;
• RemoveimageUrl?: string | null;• Call sites: none found—no further updates required.
If you anticipate future use for either prop, please reintroduce and implement accordingly; otherwise, go ahead and delete them.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (24)
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx(4 hunks)apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx(2 hunks)apps/dashboard/src/@/components/contracts/import-contract/modal.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/import-contract-button.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/overview/engine-instances-table.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx(4 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/rpc/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/cards.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contracts/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (18)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/page.tsx
- apps/dashboard/src/@/components/contracts/import-contract/modal.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/overview/engine-instances-table.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/rpc/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/cards.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/import-contract-button.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contracts/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx
- apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx
🧠 Learnings (8)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Layouts should reuse `SidebarLayout` / `FullWidthSidebarLayout` (`@/components/blocks/SidebarLayout`).
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
PR: thirdweb-dev/js#7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-06-24T21:38:03.155Z
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx (1)
apps/playground-web/src/icons/ContractIcon.tsx (1)
ContractIcon(1-21)
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (1)
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx (2)
ActionLink(51-54)LinkGroup(56-119)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx (1)
apps/playground-web/src/icons/InsightIcon.tsx (1)
InsightIcon(1-21)
🔇 Additional comments (11)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx (2)
6-9: Icon swap to ArrowDownToLineIcon matches repo convention and PR intent — LGTM
- Uses the Icon-suffixed lucide exports as per repo lint rule.
- Consistent with the PR-wide replacement of Import/Download icons.
190-190: Submit button icon swap — consistent with trigger iconUsing ArrowDownToLineIcon here keeps the pattern consistent. Good.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx (2)
53-53: Header icon prop is correctly typed as React.FC<{ className?: string }>I’ve confirmed in apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx that ProjectPageHeaderProps.icon is declared as React.FC<{ className?: string }> (line 55), so passing InsightIcon (satisfying React.FC<{ className?: string }>) is fully compatible with the header API. No changes are required here.
57-57: Please verify thatProjectPageproperly omits its actions container whenheader.actionsis nullI wasn’t able to locate a guard in the
ProjectPageimplementation that skips rendering (and any associated spacing) whenactionsis null. Since you’re explicitly passingactions: nullon the Insight page (and elsewhere in the sidebar), please confirm both in code and in the running UI that:
- No empty wrapper is rendered for actions.
- No horizontal padding, margin, or reserved space remains when
actionsis null.If you find that an empty container or gap still appears, wrap the actions block in a conditional, for example:
{header.actions && ( <div className="project-page__actions"> {header.actions} </div> )}And gate any related layout styles on
Boolean(header.actions)so the header collapses fully when there are no actions.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx (4)
1-1: Lucide import naming LGTMArrowUpFromLineIcon follows the repo rule to import lucide-react icons with the Icon suffix. Consistent with prior learnings.
59-59: Icon sizing change aligns with the PR’s design updateUsing size-3.5 on the primary action icon matches the global change in this PR and keeps icons visually balanced with text.
8-8: ContractIcon import path is validI confirmed that the dashboard app includes its own
ContractIconimplementation atapps/dashboard/src/@/icons/ContractIcon.tsx, so the import from@/icons/ContractIconwill resolve correctly in this workspace. No further changes are needed here.
46-46: No change needed for theiconpropThe
ProjectPageHeaderPropsdefinition specifies:export type ProjectPageHeaderProps = { // … icon: React.FC<{ className?: string }>; // … };Since
iconexpects a component type (i.e. aReact.FCaccepting aclassName), passingContractIcondirectly is correct. No conversion to a ReactNode (e.g.<ContractIcon />) is required.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx (2)
10-12: Settings icon swap LGTMUsing Settings2Icon aligns with the repo-wide icon convention and the PR’s visual direction. No behavioral impact.
Also applies to: 140-143
132-138: Contracts is the intended default Webhooks destinationThe root Webhooks page at
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/page.tsx
performs a redirect to/webhooks/contracts, confirming that contracts is the default landing route. The sidebar’shref:${props.layoutPath}/webhooks/contracts`` in
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
lines 132–138 correctly matches this behavior. No code changes are required unless you intend to switch the default to payments.If you do want payments as the new default, please update both:
- the redirect target in
…/webhooks/page.tsx- and the sidebar
hrefinProjectSidebarLayout.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (1)
100-111: Settings button rendering LGTMButton variant/class matches the updated design tokens and icon usage is consistent.
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
Show resolved
Hide resolved
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx
Show resolved
Hide resolved
d5eb851 to
b015f20
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (1)
1-4: Make this a Client Component and use the dashboard Button importThis header renders interactive controls and consumes a client subcomponent (LinkGroup). Add the "use client" directive and switch the Button import to the app’s UI primitive path.
Apply:
+ "use client"; -import { Button } from "@workspace/ui/components/button"; +import { Button } from "@/components/ui/button";
🧹 Nitpick comments (6)
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (6)
60-62: Unify icon rendering and ensure predictable sizingWhen isProjectIcon is true, the icon is rendered without a className, leading to inconsistent sizes across pages. Pass a default className in both branches and mark decorative icons aria-hidden.
- icon: React.FC<{ className?: string }>; + icon: React.ComponentType<{ className?: string }>; isProjectIcon?: boolean;And below (see top-row icon):
- {props.isProjectIcon ? ( - <props.icon /> - ) : ( - <div className="border rounded-full p-2.5 bg-card"> - <props.icon className="size-5 text-muted-foreground" /> - </div> - )} + {props.isProjectIcon ? ( + <props.icon className="size-6" aria-hidden="true" /> + ) : ( + <div className="border rounded-full p-2.5 bg-card"> + <props.icon className="size-5 text-muted-foreground" aria-hidden="true" /> + </div> + )}
68-70: settings prop shape looks goodSimple and focused API for a Settings link. Consider allowing an optional label for localization in the future, defaulting to “Settings”.
76-89: Add explicit return types and root className override
- Per guidelines, add explicit return types on components.
- Expose a className prop and merge with cn for theming/overrides.
-export function ProjectPageHeader(props: ProjectPageHeaderProps) { +export function ProjectPageHeader(props: ProjectPageHeaderProps): JSX.Element { return ( - <header className="container max-w-7xl py-6 relative"> + <header className={cn("container max-w-7xl py-6 relative", (props as any).className)}>And extend the props:
export type ProjectPageHeaderProps = { title: string; description?: React.ReactNode; icon: React.ComponentType<{ className?: string }>; isProjectIcon?: boolean; + className?: string; actions: { primary: Action; secondary?: Action; } | null;
78-89: Optional: expose iconContainerClassName for styling hooksIf consumers need to tweak the container (e.g., remove border on specific pages), add an iconContainerClassName prop and merge with cn.
- <div className="border rounded-full p-2.5 bg-card"> + <div className={cn("border rounded-full p-2.5 bg-card", (props as any).iconContainerClassName)}> <props.icon className="size-5 text-muted-foreground" aria-hidden="true" /> </div>
113-124: Align secondary action styling with outline patternPR-wide changes prefer outline with bg-card. Consider migrating the “secondary” action here to outline for consistency, and widen the Action helper’s variant type accordingly.
-function Action(props: { action: Action; variant?: "default" | "secondary" }) { +function Action(props: { action: Action; variant?: "default" | "secondary" | "outline" }): JSX.Element { const action = props.action; return "component" in action ? ( action.component ) : ( <Button asChild - className={cn( - "rounded-full", - props.variant === "secondary" && "border border-border", - )} + className={cn("rounded-full", props.variant === "outline" && "gap-2 bg-card")} size="sm" variant={props.variant} >And use outline for the secondary call site:
- {props.actions.secondary && ( - <Action action={props.actions.secondary} variant="secondary" /> - )} + {props.actions.secondary && ( + <Action action={props.actions.secondary} variant="outline" /> + )}
92-110: Replace Next.js Link with NavLink for internal “Settings” navigationNavLink is already defined in
apps/dashboard/src/@/components/ui/NavLink.tsxand imported elsewhere to provide automatic active‐state styling and consistent prefetch behavior. Swapping in NavLink here will align this internal link with the rest of the dashboard.Files to update:
- apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (lines 92–110)
Suggested diff:
-import Link from "next/link"; +import { NavLink } from "@/components/ui/NavLink"; … - {props.settings && ( - <Link href={props.settings.href}> + {props.settings && ( + <NavLink href={props.settings.href}> <Button variant="outline" size="sm" className="rounded-full gap-2 bg-card" > <Settings2Icon className="size-4 text-muted-foreground" /> Settings </Button> - </Link> + </NavLink> )}• Don’t forget to remove the unused
Linkimport if it’s no longer referenced.
• This change is optional but recommended to ensure internal links use NavLink’s built-in active states.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (24)
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx(4 hunks)apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx(2 hunks)apps/dashboard/src/@/components/contracts/import-contract/modal.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/import-contract-button.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/overview/engine-instances-table.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx(4 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/rpc/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/cards.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contracts/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx(3 hunks)
✅ Files skipped from review due to trivial changes (2)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/overview/engine-instances-table.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
🚧 Files skipped from review as they are similar to previous changes (21)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/page.tsx
- apps/dashboard/src/@/components/contracts/import-contract/modal.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/import-contract-button.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/cards.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/rpc/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contracts/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx
- apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
🧠 Learnings (18)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.client.tsx : Client components must start with `'use client';` before imports.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use the `container` class with a `max-w-7xl` cap for page width consistency.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{tsx} : Expose `className` prop on root element of components for overrides
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Add `className` to the root element of every component for external overrides.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
PR: thirdweb-dev/js#7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
🧬 Code graph analysis (1)
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (1)
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx (2)
ActionLink(51-54)LinkGroup(56-119)
⏰ 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). (6)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (4)
2-2: Icon import style is correctGood use of lucide-react with the required Icon suffix (ArrowUpRightIcon, Settings2Icon).
128-139: Typography and description layout look solidGood use of tracking-tight and muted foreground. The description is safely clamped for both sm and md viewports.
140-151: Mobile actions grouping: good separationHiding the action cluster on lg+ and providing a compact mobile row is consistent with the rest of the dashboard.
55-60: The scripts will output the component’s code and any usage ofclient,imageUrl, andiconwithin it so we can confirm which props are truly unused and whether theicontype should be widened. Once we have that, I’ll update the review comment accordingly.
Merge activity
|
<!--
## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"
If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):
## Notes for the reviewer
Anything important to call out? Be sure to also clarify these in your comments.
## How to test
Unit tests, playground, etc.
-->
<!-- start pr-codex -->
---
## PR-Codex overview
This PR primarily focuses on updating UI components across various files in the application. It includes adjustments to icon sizes, component styles, and the introduction of new icons, enhancing the overall user interface and experience.
### Detailed summary
- Changed `PlusIcon` size from `size-4` to `size-3.5` in multiple buttons.
- Replaced `SettingsIcon` with `Settings2Icon`.
- Added `DatabaseIcon`, `WebhookIcon`, `TokenIcon`, `ArrowDownToLineIcon`, and others to various headers.
- Updated button styles to `bg-card` and changed variants to `outline`.
- Modified header layouts to include new icons and adjusted spacing.
- Removed actions from several `ProjectPage` components and replaced them with links.
- Adjusted descriptions and added new links in the `ContractsPage`, `PaymentsPage`, and other components.
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
<!-- end pr-codex -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
- New Features
- Header icons added across many pages; Settings now appears as a dedicated header control where provided.
- Single link renders as a direct action button; multiple links grouped under a labeled "Resources" menu with chevron.
- Refactor
- Project header redesigned to an icon-driven layout; mobile-specific branching removed and actions reorganized.
- Style
- Button variants, spacing, iconography, and dropdown alignment adjusted (smaller icons, new arrow/chevron visuals, reduced item padding).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
b015f20 to
e651d0a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx (1)
3-3: Use the dashboard Button primitiveFollow the dashboard convention to import UI primitives from "@/components/ui/*".
Apply:
-import { Button } from "@workspace/ui/components/button"; +import { Button } from "@/components/ui/button";
♻️ Duplicate comments (1)
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (1)
1-3: Make this a client component and use the dashboard UI Button importThis header composes LinkGroup (a client component) and renders interactive Buttons. Align with app conventions.
Apply:
+ "use client"; - -import { Button } from "@workspace/ui/components/button"; +import { Button } from "@/components/ui/button"; import { ArrowUpRightIcon, Settings2Icon } from "lucide-react";
🧹 Nitpick comments (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx (1)
112-119: Potential TS type mismatch for header.iconheader.icon is typed as React.FC<{ className?: string }>, but the inline icon is declared as () => JSX.Element (no props). Depending on tsconfig settings, this can fail assignability. Minimal fix: accept an optional props object (even if unused).
Apply:
- icon: () => ( + icon: (_?: { className?: string }) => ( <ProjectAvatar className="size-12" client={client} src={project.image ?? ""} /> ),Alternatively, define a named component with the prop typed and pass it.
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (2)
60-62: Broaden icon prop to React.ComponentType for better interoperabilityReact.ComponentType is more idiomatic and accepts both FC and forwardRef components. This also improves compatibility with parameterless components.
Apply:
- icon: React.FC<{ className?: string }>; + icon: React.ComponentType<{ className?: string }>; isProjectIcon?: boolean;
59-61: Remove unusedimageUrlprop from ProjectPageHeaderPropsAfter verifying that
props.imageUrlis never referenced inProjectPageHeader(only declared on line 59) and there are no direct JSX calls passing animageUrlprop into that component, it’s safe—and clearer—to drop it entirely.• In
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
– Remove line
ts imageUrl?: string | null;
• Call sites spread in all ofprops.header(e.g. inproject-page.tsx) won’t break—any existingimageUrlfield on those header objects will simply be ignored by the component.
• For full cleanup, you may also omit theimageUrlproperty from whatever object buildsprops.headerin the parentProjectPagecomponent.apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx (2)
82-89: Minor: outline variant already adds a borderborder class is likely redundant with variant="outline". Consider removing to avoid double borders if themes change.
Apply:
- <Button - variant="outline" - size="sm" - className="rounded-full border gap-2 bg-card [&[data-state=open]>svg]:rotate-180" - > + <Button + variant="outline" + size="sm" + className="rounded-full gap-2 bg-card [&[data-state=open]>svg]:rotate-180" + >
105-112: Optional: Use NavLink for internal resourcesFor internal links (non-http), prefer NavLink to get active states “for free” per dashboard guidelines. You can keep Link for external URLs.
Example:
- <Link + {isExternal ? ( + <Link href={link.href} target={isExternal ? "_blank" : undefined} rel={isExternal ? "noopener noreferrer" : undefined} - > - <Icon className="size-4 text-muted-foreground" /> - {linkTypeToLabel[link.type]} - </Link> + > + <Icon className="size-4 text-muted-foreground" /> + {linkTypeToLabel[link.type]} + </Link> + ) : ( + <NavLink href={link.href}> + <Icon className="size-4 text-muted-foreground" /> + {linkTypeToLabel[link.type]} + </NavLink> + )}Note: import { NavLink } from "@/components/ui/NavLink".
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (24)
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx(4 hunks)apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx(2 hunks)apps/dashboard/src/@/components/contracts/import-contract/modal.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/import-contract-button.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/overview/engine-instances-table.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx(4 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/rpc/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/cards.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contracts/page.tsx(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (20)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/layout.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/overview/engine-instances-table.tsx
- apps/dashboard/src/@/components/contracts/import-contract/modal.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/cards.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/rpc/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/import-contract-button.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/ai/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/contracts/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/(general)/import/import-engine-dialog.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/insight/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsxapps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsxapps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsxapps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
🧠 Learnings (22)
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsxapps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.client.tsx : Client components must start with `'use client';` before imports.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use the `container` class with a `max-w-7xl` cap for page width consistency.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{tsx} : Expose `className` prop on root element of components for overrides
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Add `className` to the root element of every component for external overrides.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
PR: thirdweb-dev/js#7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsxapps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.
Applied to files:
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
🧬 Code graph analysis (1)
apps/dashboard/src/@/components/blocks/project-page/project-page-header.tsx (1)
apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx (2)
ActionLink(51-54)LinkGroup(56-119)
⏰ 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). (6)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx (4)
10-10: Icon import looks correct and aligns with the new header API.Importing WalletProductIcon and using it as header.icon is consistent with the PR’s icon-driven headers.
58-59: Good use of the new icon slot.Passing WalletProductIcon via header.icon (without isProjectIcon) correctly renders it inside the bordered circular container in the header.
69-69: Explicitly nulling actions matches the new header contract.Setting actions: null is consistent with the removal of per-page action buttons in favor of links/settings.
70-72: Route Verification Completed: Thesettings/walletsroute exists• Confirmed presence of
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/page.tsxcontaining the wallet settings page.
• Noted ancillary files under that directory (e.g.components/InAppWalletSettingsUI.stories.tsx) and references such asloginRedirect('/team/${team_slug}/settings/wallets')andinAppConfig:${projectLayout}/settings/wallets``.No broken link risk—this route is implemented. Proceed with merge.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx (1)
29-29: Avatar import for project header: looks good.Using ProjectAvatar for the project overview icon aligns with the new isProjectIcon flow.
| <Link | ||
| href={link.href} | ||
| target={link.href.startsWith("http") ? "_blank" : undefined} | ||
| > | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| className="rounded-full border gap-2 bg-card" | ||
| > | ||
| <Icon className="size-3.5 text-muted-foreground" /> | ||
| {linkTypeToLabel[link.type]} | ||
| </Button> | ||
| </Link> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix invalid nesting (Link wrapping Button) and add rel for external links
Current markup likely renders , which is invalid and harms accessibility. Use Button asChild to render an anchor styled as a button and add rel for external links.
Apply:
- <Link
- href={link.href}
- target={link.href.startsWith("http") ? "_blank" : undefined}
- >
- <Button
- variant="outline"
- size="sm"
- className="rounded-full border gap-2 bg-card"
- >
- <Icon className="size-3.5 text-muted-foreground" />
- {linkTypeToLabel[link.type]}
- </Button>
- </Link>
+ <Button
+ asChild
+ variant="outline"
+ size="sm"
+ className="rounded-full border gap-2 bg-card"
+ >
+ <Link
+ href={link.href}
+ target={link.href.startsWith("http") ? "_blank" : undefined}
+ rel={link.href.startsWith("http") ? "noopener noreferrer" : undefined}
+ >
+ <Icon className="size-3.5 text-muted-foreground" />
+ {linkTypeToLabel[link.type]}
+ </Link>
+ </Button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Link | |
| href={link.href} | |
| target={link.href.startsWith("http") ? "_blank" : undefined} | |
| > | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| className="rounded-full border gap-2 bg-card" | |
| > | |
| <Icon className="size-3.5 text-muted-foreground" /> | |
| {linkTypeToLabel[link.type]} | |
| </Button> | |
| </Link> | |
| <Button | |
| asChild | |
| variant="outline" | |
| size="sm" | |
| className="rounded-full border gap-2 bg-card" | |
| > | |
| <Link | |
| href={link.href} | |
| target={link.href.startsWith("http") ? "_blank" : undefined} | |
| rel={link.href.startsWith("http") ? "noopener noreferrer" : undefined} | |
| > | |
| <Icon className="size-3.5 text-muted-foreground" /> | |
| {linkTypeToLabel[link.type]} | |
| </Link> | |
| </Button> |
🤖 Prompt for AI Agents
In apps/dashboard/src/@/components/blocks/project-page/header/link-group.tsx
around lines 63 to 75, the code currently wraps a Button inside a Link which
produces invalid <a><button/></a> nesting; replace this by rendering the Button
as the anchor (use Button's asChild prop) and forward href/target/rel to the
anchor: remove the outer Link, render Button asChild so it outputs an <a> with
href; set target to "_blank" for external hrefs and add rel="noopener
noreferrer" for those external links; keep Icon and label children unchanged.

PR-Codex overview
This PR focuses on updating various UI components in the dashboard, primarily adjusting icon sizes, replacing some icons, and enhancing layout elements for improved aesthetics and usability.
Detailed summary
PlusIconinCreateWebhookModaland other components fromsize-4tosize-3.5.SettingsIconwithSettings2IconinProjectSidebarLayout.DatabaseIconto theProjectPageheader.VaultPageactions tonull.ImportIconwithArrowDownToLineIconin multiple components.iconprops to severalProjectPageheaders, includingWebhookIcon,TokenIcon, andPayIcon.Layoutcomponent andProjectPageHeader.nullin several pages.Summary by CodeRabbit
New Features
Refactor
Style