Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@steven-tey
Copy link
Collaborator

@steven-tey steven-tey commented Oct 22, 2025

CleanShot 2025-10-22 at 14 08 15

Summary by CodeRabbit

  • New Features

    • Transfer modals redesigned with workspace selector, mobile-friendly layout, and a confirmation verification step.
    • Webhook modal updated to use a Combobox for event selection.
  • Bug Fixes

    • Domain and link transfers now reset link metrics and clear related metadata and folder associations.
    • Transfers validated to prevent invalid or self-transfers.
  • Chores

    • Removed legacy InputSelect from the UI package (affects public export).

@vercel
Copy link
Contributor

vercel bot commented Oct 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Oct 22, 2025 9:22pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 22, 2025

Walkthrough

Backend and frontend transfer flows were simplified and hardened: transfers now validate domains/workspaces, reset per-link metrics and folder/tags on move, remove analytics/usage adjustments, and modals were refactored to use WorkspaceSelector/Combobox with verification steps; the InputSelect component was removed from the UI package.

Changes

Cohort / File(s) Summary
Domain cron & API routes
apps/web/app/(ee)/api/cron/domains/transfer/route.ts, apps/web/app/api/domains/[domain]/transfer/route.ts
Domain transfer flow simplified: single-domain update retained, analytics/usage adjustments removed; moved links now have per-link metrics reset (clicks, leads, sales, saleAmount, conversions β†’ 0; lastClicked, lastLeadAt, lastConversionAt β†’ null) and folderId cleared; error message refined for same-workspace transfer.
Link Transfer API
apps/web/app/api/links/[linkId]/transfer/route.ts
Adds domain validation (isDubDomain) and self-transfer guard (bad_request); resets link stats and timestamps, clears tags and folderId when moving; removes analytics-based workspace usage increments.
Transfer Domain Modal (UI)
apps/web/ui/modals/transfer-domain-modal.tsx
Refactors into modal wrapper + inner component, adds WorkspaceSelector, verification step, mobile-aware behavior, onSuccess callback support, updated useTransferDomainModal signature and UI/interaction changes.
Transfer Link Modal (UI)
apps/web/ui/modals/transfer-link-modal.tsx
Simplifies UI to SimpleLinkCard + WorkspaceSelector, adds verification text requirement, updates API call body to include newWorkspaceId, clears stats/tags on success, improves mobile layout and control flow.
Send Test Webhook Modal (UI)
apps/web/ui/modals/send-test-webhook-modal.tsx
Replaces InputSelect with Combobox for event selection, adjusts option types and payload wiring, updates modal header and footer actions/layout.
UI package exports
packages/ui/src/index.tsx
Removed public re-export of the InputSelect module (export * from "./input-select" removed).
InputSelect component removed
packages/ui/src/input-select.tsx
The entire InputSelect implementation (component, context, types, helpers, mobile drawer behavior, filtering, keyboard interactions, and exported interfaces) was deleted.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant Modal as Transfer Modal (UI)
    participant API as Transfer API Route
    participant DB as Database

    User->>Modal: Select workspace + enter verification
    Modal->>API: POST /api/domains/[domain]/transfer (newWorkspaceId)
    API->>API: Validate target workspace (not same)
    API->>DB: Transfer domain ownership
    API->>DB: For each moved link -- reset metrics, null timestamps, clear folderId
    API-->>Modal: 200 OK
    Modal->>User: Trigger onSuccess, refresh domains, close
Loading
sequenceDiagram
    autonumber
    participant User
    participant Modal as Transfer Link Modal (UI)
    participant API as Link Transfer Route
    participant DB as Database

    User->>Modal: Select target workspace + enter "confirm transfer link"
    Modal->>API: POST /api/links/{linkId}/transfer (newWorkspaceId)
    API->>API: Check isDubDomain(link.domain)
    alt non-Dub domain or same-workspace
        API-->>Modal: 400 bad_request (reject)
        Modal->>User: Show error toast
    else valid
        API->>DB: Move link to new workspace
        API->>DB: Reset stats (clicks/leads/sales/conversions), null timestamps, clear tags & folderId
        API-->>Modal: 200 OK
        Modal->>User: Close modal, refresh links
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Rationale: changes span API and UI layers, include deletion of a large UI component (InputSelect) which affects exports and multiple modals, add validation and repeated metric-reset logic, and introduce new modal structures β€” review requires checking backend correctness, UI replacements, and export surface impact.

Possibly related PRs

  • Add domain, createdAt indexΒ #2481 β€” Modifies the same cron domain-transfer handler (ordering/index changes for link queries); directly relevant to link processing during domain transfers.

Poem

🐰 I hopped through code with eager paws,

Cleared old stats and fixed the laws,
Verified hops before they go,
Picked a workspace β€” nice and slow,
Now links move fresh through meadow's cause.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
βœ… Passed checks (2 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check βœ… Passed The title succinctly reflects the main changes by referencing updates to both domain and link transfer modals and their underlying logic, which correspond to the extensive UI refactoring and API side-effect adjustments present in this PR. It clearly conveys the primary feature being worked on without extraneous detail or ambiguity. Team members reviewing the history will understand this PR centers on enhancing transfer workflows.
✨ Finishing touches
  • πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch transfer-modal-updates

πŸ“œ Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 52ebba1 and caf4ea8.

πŸ“’ Files selected for processing (3)
  • apps/web/ui/modals/send-test-webhook-modal.tsx (5 hunks)
  • packages/ui/src/index.tsx (0 hunks)
  • packages/ui/src/input-select.tsx (0 hunks)
πŸ’€ Files with no reviewable changes (2)
  • packages/ui/src/index.tsx
  • packages/ui/src/input-select.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/ui/modals/send-test-webhook-modal.tsx (2)
packages/ui/src/combobox/index.tsx (2)
  • ComboboxOption (29-37)
  • Combobox (85-367)
apps/web/lib/types.ts (1)
  • WebhookTrigger (397-397)
⏰ 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 (1)
apps/web/ui/modals/send-test-webhook-modal.tsx (1)

90-95: Confirm cancel button doesn't submit the form

This new Cancel button sits inside the <form>. If @dub/ui’s Button defaults to type="submit", clicking it will still invoke the onSubmit handler before setShowSendTestWebhookModal(false), resulting in an accidental webhook send. Please confirm the default type; if it is submit, pass type="button" here to avoid the unintended submit.


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.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (1)
apps/web/app/(ee)/api/cron/domains/transfer/route.ts (1)

118-121: Harden error logging for non-Error throwables.

error is unknown; error.message can throw. Guard it.

-    await log({
-      message: `Error transferring domain: ${error.message}`,
+    const msg =
+      error instanceof Error ? error.message : JSON.stringify(error);
+    await log({
+      message: `Error transferring domain: ${msg}`,
       type: "cron",
     });
🧹 Nitpick comments (5)
apps/web/app/(ee)/api/cron/domains/transfer/route.ts (1)

29-36: Optional: fetch only needed fields to reduce payload.

findMany pulls full rows; you only use id (and fields mirrored in cache/analytics). Selecting minimal fields lowers memory and network I/O.

-    const links = await prisma.link.findMany({
+    const links = await prisma.link.findMany({
       where: { domain, projectId: currentWorkspaceId },
       take: 100,
       orderBy: {
         createdAt: "desc",
       },
+      select: {
+        id: true,
+        domain: true,
+        key: true,
+        url: true,
+        projectId: true,
+        folderId: true,
+        clicks: true,
+        leads: true,
+        sales: true,
+        saleAmount: true,
+        conversions: true,
+        lastClicked: true,
+        lastLeadAt: true,
+        lastConversionAt: true,
+      },
     });
apps/web/app/api/links/[linkId]/transfer/route.ts (1)

55-69: Destination role check (optional but safer).

You fetch role but only validate membership. If viewers exist, consider requiring a role with write privileges.

-    if (!newWorkspace || newWorkspace.users.length === 0) {
+    const member = newWorkspace?.users[0];
+    if (!newWorkspace || !member) {
       throw new DubApiError({
         code: "not_found",
         message: "New workspace not found.",
       });
     }
+    if (member.role === "viewer") {
+      throw new DubApiError({
+        code: "forbidden",
+        message:
+          "You don't have permission to add links in the destination workspace.",
+      });
+    }
apps/web/app/api/domains/[domain]/transfer/route.ts (1)

105-115: Optional: preflight for destination domain conflicts and wrap in try/catch to tailor errors.

While unlikely, defensive checks can turn a DB unique error into a user-friendly response.

-    const domainResponse = await prisma.domain.update({
+    const existsInDest = newWorkspace.domains.some((d) => d.slug === domain);
+    if (existsInDest) {
+      throw new DubApiError({
+        code: "conflict",
+        message: `Workspace ${newWorkspace.name} already has this domain.`,
+      });
+    }
+    const domainResponse = await prisma.domain.update({
       where: { slug: domain, projectId: workspace.id },
       data: {
         projectId: newWorkspaceId,
         primary: newWorkspace.domains.length === 0,
       },
       include: {
         registeredDomain: true,
       },
     });
apps/web/ui/modals/transfer-domain-modal.tsx (1)

182-191: Optional: include props and onSuccess in hook deps to avoid stale closures.

Keeps the modal in sync if these change.

-  }, [showTransferDomainModal, setShowTransferDomainModal]);
+  }, [showTransferDomainModal, setShowTransferDomainModal, props, onSuccess]);
apps/web/ui/modals/transfer-link-modal.tsx (1)

174-184: Optional: include props and onSuccess in hook deps to avoid stale closures.

Matches the domain modal hook tweak.

-  }, [showTransferLinkModal, setShowTransferLinkModal]);
+  }, [showTransferLinkModal, setShowTransferLinkModal, props, onSuccess]);
πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between c72b71e and 52ebba1.

πŸ“’ Files selected for processing (5)
  • apps/web/app/(ee)/api/cron/domains/transfer/route.ts (1 hunks)
  • apps/web/app/api/domains/[domain]/transfer/route.ts (2 hunks)
  • apps/web/app/api/links/[linkId]/transfer/route.ts (4 hunks)
  • apps/web/ui/modals/transfer-domain-modal.tsx (4 hunks)
  • apps/web/ui/modals/transfer-link-modal.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
πŸ“š Learning: 2025-08-26T15:05:55.081Z
Learnt from: TWilson023
PR: dubinc/dub#2736
File: apps/web/lib/swr/use-bounty.ts:11-16
Timestamp: 2025-08-26T15:05:55.081Z
Learning: In the Dub codebase, workspace authentication and route structures prevent endless loading states when workspaceId or similar route parameters are missing, so gating SWR loading states on parameter availability is often unnecessary.

Applied to files:

  • apps/web/ui/modals/transfer-link-modal.tsx
🧬 Code graph analysis (2)
apps/web/ui/modals/transfer-domain-modal.tsx (1)
apps/web/lib/types.ts (1)
  • DomainProps (258-274)
apps/web/app/api/links/[linkId]/transfer/route.ts (1)
apps/web/lib/api/errors.ts (1)
  • DubApiError (75-92)
⏰ 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 (4)
apps/web/app/api/links/[linkId]/transfer/route.ts (3)

29-35: Domain guard reads well.

Clear message and correct error code for non-default-domain links.


48-53: Self-transfer guard is correct.

Prevents no-op transfers with a precise error.


85-105: Remove preflight check for domain+key collision
The Prisma Link model defines no @@unique([projectId, domain, key]), so updating projectId cannot violate a non-existent database constraint.

Likely an incorrect or invalid review comment.

apps/web/app/api/domains/[domain]/transfer/route.ts (1)

33-35: Error text improvement LGTM.

Clearer message for same-workspace transfers.

@steven-tey steven-tey merged commit 8b1089f into main Oct 22, 2025
7 checks passed
@steven-tey steven-tey deleted the transfer-modal-updates branch October 22, 2025 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants