-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Remove prefixWorkspaceId from recordLink, update admin #3024
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
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThis PR removes workspace ID prefixing in several places, adds partner program aggregations and ordering to the impersonate API, enhances the admin UserInfo component to render programs with metrics and status badges, and deletes a client-side WorkspaceId UI file (and its usage). Changes
Sequence Diagram(s)sequenceDiagram
participant AdminUI as Admin UI
participant ImpersonateAPI as Impersonate API
participant DB as Prisma DB
participant UserInfo as UserInfo Component
AdminUI->>ImpersonateAPI: request impersonation data
activate ImpersonateAPI
ImpersonateAPI->>DB: query workspaces (order by totalClicks)
DB-->>ImpersonateAPI: workspaces w/ aggregates
ImpersonateAPI->>DB: query partner programs (order by totalCommissions)
DB-->>ImpersonateAPI: programs w/ aggregates
ImpersonateAPI-->>AdminUI: response includes workspaces + programs
deactivate ImpersonateAPI
AdminUI->>UserInfo: render with programs array
activate UserInfo
UserInfo->>UserInfo: map workspaceItems (nFormatter)
UserInfo->>UserInfo: map programItems (nFormatter + $ prefix + status badge)
UserInfo-->>AdminUI: rendered Workspaces and Programs sections (divider if both)
deactivate UserInfo
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
💤 Files with no reviewable changes (2)
⏰ 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)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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
🧹 Nitpick comments (7)
apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx (5)
19-29: Tighten status typing to prevent runtime lookups from breaking.Constrain status to keys of PartnerStatusBadges so TS catches unsupported values at compile time.
Apply this diff:
programs: { id: string; name: string; slug: string; - status: string; + status: keyof typeof PartnerStatusBadges; totalClicks: number; totalLeads: number; totalConversions: number; totalSaleAmount: number; totalCommissions: number; }[];
36-41: Give workspaceItems a keyed union for type-safe access.This avoids
workspace[item.id]being typed asanyand ensures only allowed keys are used.Apply this diff:
-const workspaceItems = [ - { id: "clicks", label: "Clicks" }, - { id: "links", label: "Links" }, - { id: "totalClicks", label: "Total Clicks" }, - { id: "totalLinks", label: "Total Links" }, -]; +const workspaceItems = [ + { id: "clicks", label: "Clicks" }, + { id: "links", label: "Links" }, + { id: "totalClicks", label: "Total Clicks" }, + { id: "totalLinks", label: "Total Links" }, +] as const satisfies ReadonlyArray<{ + id: keyof UserInfoProps["workspaces"][number]; + label: string; +}>;
43-49: Same for programItems: type-safe ids and currency flag.Apply this diff:
-const programItems = [ - { id: "totalClicks", label: "Total Clicks" }, - { id: "totalLeads", label: "Total Leads" }, - { id: "totalConversions", label: "Total Conversions" }, - { id: "totalSaleAmount", label: "Total Sales", isCurrency: true }, - { id: "totalCommissions", label: "Total Commissions", isCurrency: true }, -]; +const programItems = [ + { id: "totalClicks", label: "Total Clicks" }, + { id: "totalLeads", label: "Total Leads" }, + { id: "totalConversions", label: "Total Conversions" }, + { id: "totalSaleAmount", label: "Total Sales", isCurrency: true }, + { id: "totalCommissions", label: "Total Commissions", isCurrency: true }, +] as const satisfies ReadonlyArray<{ + id: keyof UserInfoProps["programs"][number]; + label: string; + isCurrency?: boolean; +}>;
64-103: Use a stable key and keep grid responsive.
- Prefer workspace.id over slug for React keys.
- Optional: improve small-screen layout with a 1-col fallback.
Apply this diff:
- <div className="grid grid-cols-2 gap-4"> + <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> {data.workspaces.map((workspace) => ( <div - key={workspace.slug} + key={workspace.id} className="flex flex-col space-y-2 rounded-lg border border-neutral-200 p-2" >
109-152: Harden StatusBadge lookup and optionally improve currency formatting.Guard against unknown statuses to avoid runtime errors, and consider a currency formatter for dollar values.
Apply this diff:
<div className="flex justify-between text-sm"> <span className="font-medium text-neutral-700">Status</span> - <StatusBadge - variant={PartnerStatusBadges[program.status].variant} - > - {PartnerStatusBadges[program.status].label} - </StatusBadge> + <StatusBadge + variant={ + PartnerStatusBadges[ + program.status as keyof typeof PartnerStatusBadges + ]?.variant ?? "neutral" + } + > + { + PartnerStatusBadges[ + program.status as keyof typeof PartnerStatusBadges + ]?.label ?? capitalize(program.status) + } + </StatusBadge> </div> {programItems.map((item) => ( <div key={item.id} className="flex justify-between text-sm"> <span className="font-medium text-neutral-700"> {item.label} </span> <span className="text-neutral-500"> - {item.isCurrency - ? `$${nFormatter(program[item.id], { full: true })}` - : nFormatter(program[item.id], { full: true })} + {item.isCurrency + ? `$${nFormatter(program[item.id], { full: true })}` + : nFormatter(program[item.id], { full: true })} </span> </div> ))}Optional: if available in @dub/utils, prefer a money formatter:
// replace `$${nFormatter(...)}` with formatCurrency(program[item.id])apps/web/lib/tinybird/record-link.ts (1)
45-49: Remove redundant workspace_id override in recordLinkTB.The
dubLinksMetadataSchemaalready definesworkspace_idwith the exact same transformation (.string().nullish().transform((v) => (v ? v : ""))). The extend override duplicates this logic unnecessarily. Removing it maintains identical behavior while keeping a single source of truth.export const recordLinkTB = tb.buildIngestEndpoint({ datasource: "dub_links_metadata", - event: dubLinksMetadataSchema.extend({ - workspace_id: z - .string() - .nullish() - .transform((v) => (v ? v : "")), - }), + event: dubLinksMetadataSchema, wait: true, });apps/web/app/(ee)/api/admin/impersonate/route.ts (1)
41-46: Add index onProject.totalClicksfor nested orderBy performance.Prisma 5.18.0 supports nested orderBy on relations, so the syntax is compatible. However, the
totalClickscolumn lacks an index in the Project model (packages/prisma/schema/workspace.prisma). Ordering by an unindexed column can degrade performance at scale. Add@@index(totalClicks(sort: Desc))to the Project model.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx(3 hunks)apps/web/app/(ee)/api/admin/impersonate/route.ts(2 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/settings/(basic-layout)/page-client.tsx(0 hunks)apps/web/lib/tinybird/record-link.ts(1 hunks)
💤 Files with no reviewable changes (1)
- apps/web/app/app.dub.co/(dashboard)/[slug]/settings/(basic-layout)/page-client.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx (1)
apps/web/ui/partners/partner-status-badges.ts (1)
PartnerStatusBadges(11-60)
⏰ 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: build
🔇 Additional comments (3)
apps/web/app/(ee)/api/admin/impersonate/route.ts (1)
47-74: Programs selection looks good; ordering by totalCommissions is clear.apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx (2)
2-3: LGTM on imports.
105-107: Divider conditional looks good.
| programs: response.partners[0].partner.programs.map( | ||
| ({ program, ...rest }) => ({ | ||
| ...program, | ||
| ...rest, | ||
| }), | ||
| ), |
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 potential crash and include programs from all partners.
response.partners[0] can be undefined, causing a runtime error. Also, limiting to index 0 drops programs from other partners. Flatten safely.
Apply this diff:
- programs: response.partners[0].partner.programs.map(
- ({ program, ...rest }) => ({
- ...program,
- ...rest,
- }),
- ),
+ programs: (response.partners ?? [])
+ .flatMap((p) => p.partner?.programs ?? [])
+ .map(({ program, ...rest }) => ({ ...program, ...rest })),📝 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.
| programs: response.partners[0].partner.programs.map( | |
| ({ program, ...rest }) => ({ | |
| ...program, | |
| ...rest, | |
| }), | |
| ), | |
| programs: (response.partners ?? []) | |
| .flatMap((p) => p.partner?.programs ?? []) | |
| .map(({ program, ...rest }) => ({ ...program, ...rest })), |
🤖 Prompt for AI Agents
In apps/web/app/(ee)/api/admin/impersonate/route.ts around lines 91 to 96, the
code assumes response.partners[0] exists and only uses its programs which can
crash when partners is undefined and drops programs from other partners; change
this to safely iterate over all partners (guarding for response.partners being
undefined) and flatten their programs, e.g. treat response.partners as an array
(default to []), use flatMap or reduce to collect every partner.programs, and
inside the iterator merge each partner-program item by spreading program and the
rest as before so the result includes programs from all partners without
throwing.
Summary by CodeRabbit