Skip to content

Copy rules#1111

Merged
elie222 merged 6 commits intomainfrom
feat/copy-rules
Dec 18, 2025
Merged

Copy rules#1111
elie222 merged 6 commits intomainfrom
feat/copy-rules

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Dec 18, 2025

Add rule copy flow to Accounts UI and implement rule.copyRulesFromAccountAction to transfer selected rules between email accounts

Introduce CopyRulesDialog for selecting a source account and rules, wire it via AccountOptionsDropdown, and implement rule.copyRulesFromAccountAction to create or update target rules by name or systemType, clearing account-specific IDs; add tests and minor Accounts UI tweaks.

📍Where to Start

Start with the server action rule.copyRulesFromAccountAction in rule.ts, then review the dialog integration in CopyRulesDialog.tsx and its trigger in page.tsx.


📊 Macroscope summarized 85e04eb. 5 files reviewed, 4 issues evaluated, 3 issues filtered, 1 comment posted

🗂️ Filtered Issues

apps/web/app/(app)/accounts/CopyRulesDialog.tsx — 1 comment posted, 2 evaluated, 1 filtered
  • line 74: The fetch call at lines 74-77 does not check the response status before calling .json(). If the API returns a non-2xx status (e.g., 401, 500), the error response body will be parsed and stored in rules instead of triggering SWR's error handling. This causes error objects to be treated as rule arrays, leading to incorrect behavior (showing "No rules found" instead of an error) or potential crashes when calling array methods like .map() or .every() on the error object. [ Already posted ]
apps/web/utils/actions/rule.ts — 0 comments posted, 2 evaluated, 2 filtered
  • line 533: Multiple database operations (prisma.rule.update and prisma.rule.create in the loop at lines 557-598) are not wrapped in a transaction. If an error occurs partway through copying multiple rules (e.g., network failure, constraint violation on rule 2 of 5), some rules will be copied/replaced while others won't be. This leaves the target account in an inconsistent state where only some rules were copied, and the user receives an error with no way to know which rules succeeded. [ Already posted ]
  • line 537: If a source rule has a null or undefined name (from legacy data or direct database manipulation bypassing validation), calling sourceRule.name.toLowerCase() at line 537 will throw a TypeError: Cannot read properties of null (reading 'toLowerCase'). While current validation requires names, existing database records may not conform to this constraint. [ Low confidence ]

Summary by CodeRabbit

  • New Features

    • Transfer email filtering rules between accounts via a Transfer option in account actions; dialog to select source account and pick rules with success/error feedback
  • Refactor

    • Accounts page reorganized into card/header/actions with a dropdown for management
    • Delete confirmation moved into dropdown flow
  • Tests

    • Comprehensive tests covering rule-copying scenarios
    • New test helper for mocking email accounts
  • Chores

    • Version bumped to v2.24.4

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 18, 2025

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

Project Deployment Review Updated (UTC)
inbox-zero Ready Ready Preview Dec 18, 2025 5:48pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 18, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a server action and validation to copy rules between email accounts, a client CopyRulesDialog for selecting/transferring rules, tests and a test helper; refactors the accounts page to use a dropdown-based account actions menu and moves delete confirmation into the dropdown.

Changes

Cohort / File(s) Summary
Test helper
apps/web/__tests__/helpers.ts
Added getMockEmailAccountWithAccount test helper returning mock account data (id, email, account).
Accounts UI refactor
apps/web/app/(app)/accounts/page.tsx
Componentized account rendering (AccountHeader/AccountActions); replaced inline action buttons with a DropdownMenu; moved delete confirmation into the dropdown and wired CopyRulesDialog open state.
Copy rules dialog (client)
apps/web/app/(app)/accounts/CopyRulesDialog.tsx
New modal component to select a source account and rules, fetch rules via SWR, support select-all/individual selection, and call the copyRulesFromAccountAction; includes loading/error handling and success toast/navigation.
Rule copy validation
apps/web/utils/actions/rule.validation.ts
Added copyRulesFromAccountBody zod schema and exported CopyRulesFromAccountBody type (sourceEmailAccountId, targetEmailAccountId, ruleIds).
Rule copy action
apps/web/utils/actions/rule.ts
New exported copyRulesFromAccountAction: validates source/target ownership, fetches source rules/actions, compares with target rules (name or systemType), updates matching rules or creates new ones (clearing certain IDs), recreates actions, and returns copied/replaced counts.
Rule copy tests
apps/web/utils/actions/__tests__/copy-rules-action.test.ts
Added comprehensive tests for validation, ownership checks, no-rules case, create vs update flows, field preservation/clearing, and mixed scenarios; uses Prisma mocks and fixtures.
Version bump
version.txt
Updated version string from v2.24.3 to v2.24.4.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as Accounts UI / CopyRulesDialog
    participant Server as copyRulesFromAccountAction
    participant DB as Prisma/Database

    User->>UI: Open dialog, select source account & rules, confirm
    UI->>Server: POST copyRulesFromAccountAction(sourceId, targetId, ruleIds)
    Server->>DB: Find source account by id
    DB-->>Server: source account or null
    alt source missing or not owned
        Server-->>UI: Error (not found / unauthorized)
    else
        Server->>DB: Find target account by id
        DB-->>Server: target account or null
        alt target missing or not owned
            Server-->>UI: Error (not found / unauthorized)
        else
            Server->>DB: Fetch source rules and actions
            DB-->>Server: rules list
            alt no rules
                Server-->>UI: Success (0 copied, 0 replaced)
            else
                Server->>DB: Fetch existing target rules (by name/systemType)
                DB-->>Server: existing rules
                loop per source rule
                    alt match found (name or systemType)
                        Server->>DB: Update target rule (replace fields, clear labelId/folderId, recreate actions)
                        DB-->>Server: updated
                    else
                        Server->>DB: Create new rule in target (copy fields, clear ids, create actions)
                        DB-->>Server: created
                    end
                end
                Server-->>UI: Success (copiedCount, replacedCount)
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Focus review on: apps/web/utils/actions/rule.ts (ownership checks, matching logic, ID clearing, action recreation), CopyRulesDialog.tsx (SWR fetch keys, select-all/checkbox logic, action invocation and state reset), and apps/web/app/(app)/accounts/page.tsx (dropdown wiring and ConfirmDialog placement).

Possibly related PRs

  • Add debug rules page #1102 — Modifies rule-related actions and schemas; overlaps with additions in apps/web/utils/actions/rule.ts and validation.
  • Copy fix #936 — Related to account deletion/confirmation flow and accounts page changes in apps/web/app/(app)/accounts/page.tsx.
  • Fix up cold email blocker for outlook #805 — Alters per-account rendering and action UI similar to the refactor in apps/web/app/(app)/accounts/page.tsx.

Poem

🐇 I hopped through folders, checked each rule,
I nudged them gently, one by one — so cool.
With checkboxes ticked and dialogs bright,
I copied, swapped, then tucked them right.
A tiny rabbit celebrates the night. 🥕

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
Title check ✅ Passed The title 'Copy rules' accurately reflects the main feature added: a new rule-copy capability allowing users to copy rules between email accounts.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 feat/copy-rules

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.

let copiedCount = 0;
let replacedCount = 0;

for (const sourceRule of sourceRules) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per-rule writes aren’t atomic. If one update/create fails mid-loop, the target account ends up partially copied. Consider wrapping the loop’s DB writes in a single prisma.$transaction (or document partial success and return per-rule results).

🚀 Reply to ask Macroscope to explain or update this suggestion.

👍 Helpful? React to give us feedback.

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: 0

🧹 Nitpick comments (1)
apps/web/app/(app)/accounts/page.tsx (1)

121-123: Button wrapping Link is not semantically correct.

The <Button> contains a <Link> as a child, which creates nested interactive elements (button containing an anchor). Use asChild prop to properly compose these components.

🔎 Apply this diff to fix the accessibility issue:
-      <Button variant="outline" size="sm">
-        <Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
-      </Button>
+      <Button variant="outline" size="sm" asChild>
+        <Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
+      </Button>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d813d92 and 9bccf33.

📒 Files selected for processing (5)
  • apps/web/__tests__/helpers.ts (1 hunks)
  • apps/web/app/(app)/accounts/page.tsx (5 hunks)
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts (1 hunks)
  • apps/web/utils/actions/rule.ts (3 hunks)
  • apps/web/utils/actions/rule.validation.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (31)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)

LLM-related code must be organized in specific directories: apps/web/utils/ai/ for main implementations, apps/web/utils/llms/ for core utilities and configurations, and apps/web/__tests__/ for LLM-specific tests

Files:

  • apps/web/__tests__/helpers.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Follow tailwindcss patterns with prettier-plugin-tailwindcss class organization
Prefix client-side environment variables with NEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

AI tests must be placed in the __tests__ directory and are not run by default (they use a real LLM)

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
  • apps/web/app/(app)/accounts/page.tsx
**/{scripts,tests,__tests__}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Use createScopedLogger only for code that doesn't run within a middleware chain, such as standalone scripts or tests

Files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
apps/web/utils/actions/*.ts

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

apps/web/utils/actions/*.ts: Use next-safe-action with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in apps/web/utils/actions/*.validation.ts
Server actions should use 'use server' directive and automatically receive authentication context (emailAccountId) from the actionClient

apps/web/utils/actions/*.ts: Create corresponding server action implementation files using the naming convention apps/web/utils/actions/NAME.ts with 'use server' directive
Use 'use server' directive at the top of server action implementation files
Implement all server actions using the next-safe-action library with actionClient, actionClientUser, or adminActionClient for type safety and validation
Use actionClientUser when only authenticated user context (userId) is needed
Use actionClient when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client
Use adminActionClient for actions restricted to admin users
Add metadata with a meaningful action name using .metadata({ name: "actionName" }) for Sentry instrumentation and monitoring
Use .schema() method with Zod validation schemas from corresponding .validation.ts files in next-safe-action configuration
Access context (userId, emailAccountId, etc.) via the ctx object parameter in the .action() handler
Use revalidatePath or revalidateTag from 'next/cache' within server action handlers when mutations modify data displayed elsewhere

Files:

  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
apps/web/utils/actions/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

apps/web/utils/actions/**/*.ts: Server actions must be located in apps/web/utils/actions folder
Server action files must start with use server directive

Files:

  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
apps/web/**/utils/actions/*.ts

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/utils/actions/*.ts: Use next-safe-action with proper Zod validation for server actions
Call revalidatePath in server actions for cache invalidation after mutations

Files:

  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
apps/web/**/{app/api,utils/actions}/**/*.ts

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/{app/api,utils/actions}/**/*.ts: Use server actions for all mutations (create/update/delete operations) instead of POST API routes
Use withAuth for user-level operations and withEmailAccount for email-account-level operations

Files:

  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
**/*.validation.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)

**/*.validation.{ts,tsx}: Define validation schemas using Zod
Use descriptive error messages in validation schemas

Files:

  • apps/web/utils/actions/rule.validation.ts
apps/web/utils/actions/*.validation.ts

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

apps/web/utils/actions/*.validation.ts: Define Zod validation schemas in separate *.validation.ts files and export both the schema and inferred type (e.g., CreateExampleBody)
Export types from Zod schemas using z.infer<> to maintain type safety between validation and client usage

apps/web/utils/actions/*.validation.ts: Create separate validation files for server actions using the naming convention apps/web/utils/actions/NAME.validation.ts containing Zod schemas and inferred types
Define input validation schemas using Zod in .validation.ts files and export both the schema and its inferred TypeScript type

Files:

  • apps/web/utils/actions/rule.validation.ts
apps/web/**/utils/actions/*.validation.ts

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Create separate Zod validation schema files for server action inputs

Files:

  • apps/web/utils/actions/rule.validation.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

**/*.test.{ts,tsx}: Use vitest for testing the application
Tests should be colocated next to the tested file with .test.ts or .test.tsx extension (e.g., dir/format.ts and dir/format.test.ts)
Mock server-only using vi.mock("server-only", () => ({}))
Mock Prisma using vi.mock("@/utils/prisma") and import the mock from @/utils/__mocks__/prisma
Use vi.clearAllMocks() in beforeEach to clean up mocks between tests
Each test should be independent
Use descriptive test names
Mock external dependencies in tests
Do not mock the Logger
Avoid testing implementation details
Use test helpers getEmail, getEmailAccount, and getRule from @/__tests__/helpers for mocking emails, accounts, and rules

Files:

  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests

Files:

  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
apps/web/app/(app)/*/page.tsx

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/*/page.tsx: Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directly

Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx with components either colocated in the same folder or in page.tsx

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/app/**

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks over class components
Use shadcn/ui components when available
Follow consistent naming conventions with PascalCase for component names
Use LoadingContent component for async data with loading and error states
Use result?.serverError with toastError and toastSuccess for mutation error handling

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/accounts/page.tsx
🧠 Learnings (35)
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules

Applied to files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers

Applied to files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/{app/api,utils/actions}/**/*.ts : Use `withAuth` for user-level operations and `withEmailAccount` for email-account-level operations

Applied to files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Mock 'server-only' module with empty object in LLM test files: `vi.mock("server-only", () => ({}))`

Applied to files:

  • apps/web/__tests__/helpers.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Mock external dependencies in tests

Applied to files:

  • apps/web/__tests__/helpers.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`

Applied to files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `actionClient` when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client

Applied to files:

  • apps/web/__tests__/helpers.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Mock Prisma using `vi.mock("@/utils/prisma")` and import the mock from `@/utils/__mocks__/prisma`

Applied to files:

  • apps/web/__tests__/helpers.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use 'use server' directive and automatically receive authentication context (`emailAccountId`) from the `actionClient`

Applied to files:

  • apps/web/utils/actions/rule.ts
  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-12-17T02:38:37.011Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1103
File: apps/web/utils/actions/rule.ts:447-457
Timestamp: 2025-12-17T02:38:37.011Z
Learning: In apps/web/utils/actions/rule.ts, revalidatePath is not needed for toggleAllRulesAction because rules data is fetched client-side using SWR, not server-side. Server-side cache revalidation is only needed when using Next.js server components or server-side data fetching.

Applied to files:

  • apps/web/utils/actions/rule.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Implement all server actions using the `next-safe-action` library with actionClient, actionClientUser, or adminActionClient for type safety and validation

Applied to files:

  • apps/web/utils/actions/rule.ts
  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `adminActionClient` for actions restricted to admin users

Applied to files:

  • apps/web/utils/actions/rule.ts
📚 Learning: 2025-11-25T14:42:11.919Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:11.919Z
Learning: Applies to utils/**/*.{js,ts,jsx,tsx} : The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/utils/actions/rule.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/utils/actions/rule.ts
  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:42:16.602Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:16.602Z
Learning: The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/utils/actions/rule.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `actionClientUser` when only authenticated user context (userId) is needed

Applied to files:

  • apps/web/utils/actions/rule.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Define Zod validation schemas in separate `*.validation.ts` files and export both the schema and inferred type (e.g., `CreateExampleBody`)

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Define input validation schemas using Zod in `.validation.ts` files and export both the schema and its inferred TypeScript type

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Create separate validation files for server actions using the naming convention `apps/web/utils/actions/NAME.validation.ts` containing Zod schemas and inferred types

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/utils/actions/*.validation.ts : Create separate Zod validation schema files for server action inputs

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Export types from Zod schemas using `z.infer<>` to maintain type safety between validation and client usage

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*.validation.ts : Define validation schemas using Zod

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `.schema()` method with Zod validation schemas from corresponding `.validation.ts` files in next-safe-action configuration

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*.validation.{ts,tsx} : Define validation schemas using Zod

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:08.150Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:08.150Z
Learning: Applies to apps/web/app/api/**/*.{ts,tsx} : Request bodies should use Zod schemas for validation to ensure type safety and prevent injection attacks

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to **/*.test.ts : Include security tests in test suites to verify: authentication is required, IDOR protection works (other users cannot access resources), parameter validation rejects invalid inputs, and error messages don't leak information

Applied to files:

  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use descriptive test names

Applied to files:

  • apps/web/utils/actions/__tests__/copy-rules-action.test.ts
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/components/ui/**/*.tsx : Shadcn UI components are located in `components/ui` directory

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 537
File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34
Timestamp: 2025-07-08T13:14:07.449Z
Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-06-05T09:49:12.168Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 485
File: apps/web/app/(landing)/login/page.tsx:41-43
Timestamp: 2025-06-05T09:49:12.168Z
Learning: In Next.js App Router, components that use the `useSearchParams` hook require a Suspense boundary to handle the asynchronous nature of search parameter access. The Suspense wrapper is necessary and should not be removed when a component uses useSearchParams.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2024-08-23T11:37:26.779Z
Learnt from: aryanprince
Repo: elie222/inbox-zero PR: 210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Import error and success toast utilities from '@/components/Toast' for displaying notifications

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use shadcn/ui components when available

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
🧬 Code graph analysis (2)
apps/web/utils/actions/rule.ts (3)
apps/web/utils/actions/safe-action.ts (1)
  • actionClientUser (131-155)
apps/web/utils/actions/rule.validation.ts (1)
  • copyRulesFromAccountBody (275-279)
apps/web/utils/error.ts (1)
  • SafeError (57-67)
apps/web/app/(app)/accounts/page.tsx (1)
apps/web/components/new-landing/common/Card.tsx (3)
  • Card (67-105)
  • CardHeader (22-54)
  • CardContent (10-12)
⏰ 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). (4)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Review for correctness
  • GitHub Check: test
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (9)
apps/web/utils/actions/rule.validation.ts (1)

275-280: LGTM!

The validation schema follows established patterns with descriptive error messages. Properly exports both the schema and inferred TypeScript type as per coding guidelines.

apps/web/app/(app)/accounts/page.tsx (1)

132-205: LGTM!

The dropdown menu implementation properly uses onSelect={(e) => e.preventDefault()} to prevent closing before confirmation. Error and success handling with toast notifications follows project patterns.

apps/web/__tests__/helpers.ts (1)

245-261: LGTM!

The new test helper follows the established patterns in this file and provides the necessary structure for testing account ownership in the copy rules feature.

apps/web/utils/actions/rule.ts (3)

462-472: LGTM!

Correctly uses actionClientUser since this action needs to validate ownership of both source and target accounts, rather than operating within a single email account context. The early validation that accounts are different prevents accidental self-copy operations.


474-499: Ownership validation is well-implemented.

The parallel fetching and combined "not found or unauthorized" error messages follow security best practices by preventing information disclosure about account existence.


533-599: LGTM!

The rule copying logic correctly:

  • Clears account-specific IDs (labelId, folderId, groupId) while preserving human-readable names
  • Matches system rules by systemType and regular rules by case-insensitive name
  • Uses deleteMany + createMany pattern to fully replace actions on update
apps/web/utils/actions/__tests__/copy-rules-action.test.ts (3)

1-23: LGTM!

Test setup properly mocks server-only, Prisma, and auth as per testing guidelines. Uses vi.clearAllMocks() in beforeEach to ensure test isolation.


25-125: Comprehensive authorization test coverage.

Good coverage of error scenarios including:

  • Same source/target validation
  • Source/target account not found
  • Source/target belonging to different user (IDOR protection)

These tests verify the security requirements are properly enforced.


127-413: LGTM!

Thorough functional tests covering:

  • Empty source rules edge case
  • New rule creation with proper ID clearing
  • Case-insensitive name matching for updates
  • SystemType matching for system rules
  • Field sanitization (labelId/folderId cleared, label/folderName preserved)
  • Mixed copy/replace scenarios

Test assertions verify both counts and the actual data passed to Prisma.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files

Prompt for AI agents (all 1 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/app/(app)/accounts/page.tsx">

<violation number="1" location="apps/web/app/(app)/accounts/page.tsx:121">
P2: Nesting `&lt;Link&gt;` inside `&lt;Button&gt;` creates invalid HTML (`&lt;a&gt;` inside `&lt;button&gt;`). Use the `asChild` prop to properly compose these components, consistent with how `DropdownMenuItem asChild` is used with Link in this same file.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

Comment on lines 121 to 123
<Button variant="outline" size="sm">
<Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
</Button>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Nesting <Link> inside <Button> creates invalid HTML (<a> inside <button>). Use the asChild prop to properly compose these components, consistent with how DropdownMenuItem asChild is used with Link in this same file.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/app/(app)/accounts/page.tsx, line 121:

<comment>Nesting `&lt;Link&gt;` inside `&lt;Button&gt;` creates invalid HTML (`&lt;a&gt;` inside `&lt;button&gt;`). Use the `asChild` prop to properly compose these components, consistent with how `DropdownMenuItem asChild` is used with Link in this same file.</comment>

<file context>
@@ -62,6 +68,77 @@ function AccountItem({
+}) {
+  return (
+    &lt;CardContent className=&quot;flex justify-between items-center gap-2 flex-wrap&quot;&gt;
+      &lt;Button variant=&quot;outline&quot; size=&quot;sm&quot;&gt;
+        &lt;Link href={prefixPath(emailAccount.id, &quot;/automation&quot;)}&gt;View&lt;/Link&gt;
+      &lt;/Button&gt;
</file context>
Suggested change
<Button variant="outline" size="sm">
<Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
</Button>
<Button variant="outline" size="sm" asChild>
<Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
</Button>

✅ Addressed in 1980f99

onError: (error) => {
toastError({
title: "Error transferring rules",
description: error.error.serverError || "An unknown error occurred",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing error.error.serverError assumes error.error exists and can throw. Consider using optional chaining so the toast always renders.

Suggested change
description: error.error.serverError || "An unknown error occurred",
description: error.error?.serverError || "An unknown error occurred",

🚀 Reply to ask Macroscope to explain or update this suggestion.

👍 Helpful? React to give us feedback.

Comment on lines +71 to +73
fetch(url, {
headers: { [EMAIL_ACCOUNT_HEADER]: selectedSourceId },
}).then((res) => res.json()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SWR fetcher parses error responses as data. If res.ok is false, rules won’t be an array and rules.every/map can break. Consider throwing on non-2xx so SWR surfaces the error.

Suggested change
fetch(url, {
headers: { [EMAIL_ACCOUNT_HEADER]: selectedSourceId },
}).then((res) => res.json()),
fetch(url, {
headers: { [EMAIL_ACCOUNT_HEADER]: selectedSourceId },
}).then(async (res) => {
if (!res.ok) {
const text = await res.text();
throw new Error(text || `Request failed: ${res.status}`);
}
return res.json();
}),

🚀 Reply to ask Macroscope to explain or update this suggestion.

👍 Helpful? React to give us feedback.

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: 1

♻️ Duplicate comments (1)
apps/web/app/(app)/accounts/page.tsx (1)

138-140: Use asChild prop to avoid invalid HTML nesting.

Nesting <Link> inside <Button> creates invalid HTML structure. Use the asChild prop pattern, as correctly demonstrated in lines 202-210 with DropdownMenuItem.

🔎 Apply this diff:
-      <Button variant="outline" size="sm">
-        <Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
-      </Button>
+      <Button variant="outline" size="sm" asChild>
+        <Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
+      </Button>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9bccf33 and c700f48.

📒 Files selected for processing (2)
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx (1 hunks)
  • apps/web/app/(app)/accounts/page.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
apps/web/app/(app)/*/page.tsx

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/*/page.tsx: Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directly

Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx with components either colocated in the same folder or in page.tsx

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Follow tailwindcss patterns with prettier-plugin-tailwindcss class organization
Prefix client-side environment variables with NEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
apps/web/**/app/**

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks over class components
Use shadcn/ui components when available
Follow consistent naming conventions with PascalCase for component names
Use LoadingContent component for async data with loading and error states
Use result?.serverError with toastError and toastSuccess for mutation error handling

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
apps/web/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/accounts/page.tsx
  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
🧠 Learnings (16)
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/{app/api,utils/actions}/**/*.ts : Use `withAuth` for user-level operations and `withEmailAccount` for email-account-level operations

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/components/ui/**/*.tsx : Shadcn UI components are located in `components/ui` directory

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-06-05T09:49:12.168Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 485
File: apps/web/app/(landing)/login/page.tsx:41-43
Timestamp: 2025-06-05T09:49:12.168Z
Learning: In Next.js App Router, components that use the `useSearchParams` hook require a Suspense boundary to handle the asynchronous nature of search parameter access. The Suspense wrapper is necessary and should not be removed when a component uses useSearchParams.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2024-08-23T11:37:26.779Z
Learnt from: aryanprince
Repo: elie222/inbox-zero PR: 210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Implement all server actions using the `next-safe-action` library with actionClient, actionClientUser, or adminActionClient for type safety and validation

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actions

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:42:11.919Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:11.919Z
Learning: Applies to utils/**/*.{js,ts,jsx,tsx} : The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `revalidatePath` or `revalidateTag` from 'next/cache' within server action handlers when mutations modify data displayed elsewhere

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Import error and success toast utilities from '@/components/Toast' for displaying notifications

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use shadcn/ui components when available

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `actionClient` when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 537
File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34
Timestamp: 2025-07-08T13:14:07.449Z
Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-12-17T02:38:37.011Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1103
File: apps/web/utils/actions/rule.ts:447-457
Timestamp: 2025-12-17T02:38:37.011Z
Learning: In apps/web/utils/actions/rule.ts, revalidatePath is not needed for toggleAllRulesAction because rules data is fetched client-side using SWR, not server-side. Server-side cache revalidation is only needed when using Next.js server components or server-side data fetching.

Applied to files:

  • apps/web/app/(app)/accounts/CopyRulesDialog.tsx
🧬 Code graph analysis (2)
apps/web/app/(app)/accounts/page.tsx (2)
apps/web/components/new-landing/common/Card.tsx (3)
  • Card (67-105)
  • CardHeader (22-54)
  • CardContent (10-12)
apps/web/app/(app)/accounts/CopyRulesDialog.tsx (1)
  • CopyRulesDialog (51-261)
apps/web/app/(app)/accounts/CopyRulesDialog.tsx (5)
apps/web/app/api/user/rules/route.ts (1)
  • RulesResponse (5-5)
apps/web/utils/config.ts (1)
  • EMAIL_ACCOUNT_HEADER (3-3)
apps/web/utils/actions/rule.ts (1)
  • copyRulesFromAccountAction (462-610)
apps/web/components/ui/select.tsx (5)
  • Select (150-150)
  • SelectTrigger (153-153)
  • SelectValue (152-152)
  • SelectContent (154-154)
  • SelectItem (156-156)
apps/web/components/LoadingContent.tsx (1)
  • LoadingContent (13-31)
⏰ 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). (3)
  • GitHub Check: test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Review for correctness
🔇 Additional comments (10)
apps/web/app/(app)/accounts/CopyRulesDialog.tsx (5)

1-49: LGTM!

Clean imports and well-defined TypeScript types. The component properly declares itself as a client component.


51-74: LGTM!

Proper use of SWR for data fetching with conditional key and custom headers. State management is clean.


94-128: LGTM!

Well-structured selection logic with proper memoization and efficient Set-based state management.


130-149: LGTM!

Proper guards and state cleanup handlers ensure good user experience and prevent invalid operations.


151-260: LGTM!

Well-structured dialog UI with proper loading states, accessibility labels, and user feedback. The table-based rule selection is intuitive and follows shadcn/ui patterns.

apps/web/app/(app)/accounts/page.tsx (5)

1-59: LGTM!

Clean imports and proper refactoring to support multi-account operations. The addition of allAccounts prop enables the new rules transfer functionality.


61-117: LGTM!

Excellent refactoring with clear separation of concerns. The extracted AccountHeader component is reusable and handles nullable properties safely with optional chaining.


167-192: LGTM!

Good state management for the dialog and clean filtering logic to compute source accounts for the transfer feature.


193-240: LGTM!

Well-structured dropdown menu with proper use of asChild pattern (lines 202-210) and correct onSelect preventDefault handling for the ConfirmDialog trigger (line 220). The delete confirmation provides clear messaging for both primary and non-primary accounts.


242-250: LGTM!

Clean integration of the CopyRulesDialog component with properly passed props for account transfer functionality.

Comment on lines +86 to +92
onError: (error) => {
toastError({
title: "Error transferring rules",
description: error.error.serverError || "An unknown error occurred",
});
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add optional chaining to error access.

The error handler accesses error.error.serverError without optional chaining. If error.error is undefined, this will throw an error.

🔎 Apply this diff to add safe error access:
     onError: (error) => {
       toastError({
         title: "Error transferring rules",
-        description: error.error.serverError || "An unknown error occurred",
+        description: error.error?.serverError || "An unknown error occurred",
       });
     },

As per coding guidelines: Use result?.serverError with toastError for error handling in async operations.

📝 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.

Suggested change
onError: (error) => {
toastError({
title: "Error transferring rules",
description: error.error.serverError || "An unknown error occurred",
});
},
});
onError: (error) => {
toastError({
title: "Error transferring rules",
description: error.error?.serverError || "An unknown error occurred",
});
},
});
🤖 Prompt for AI Agents
In apps/web/app/(app)/accounts/CopyRulesDialog.tsx around lines 86 to 92, the
error handler accesses error.error.serverError directly which can throw if
error.error is undefined; update the handler to use optional chaining (e.g.,
error?.error?.serverError) and fall back to "An unknown error occurred" before
calling toastError so the description is safely resolved.

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: 0

♻️ Duplicate comments (1)
apps/web/app/(app)/accounts/page.tsx (1)

138-140: Well done fixing the Button/Link composition! ✅

The asChild prop correctly addresses the past review feedback about invalid HTML from nesting interactive elements.

🧹 Nitpick comments (1)
apps/web/app/(app)/accounts/page.tsx (1)

189-191: Consider memoizing sourceAccounts for consistency.

The filtering creates a new array on every render. While the performance impact is minimal for typical account counts, memoizing would follow React optimization best practices.

🔎 Optional: Memoize sourceAccounts
+import { useMemo } from "react";
+
 function AccountOptionsDropdown({
   emailAccount,
   allAccounts,
   onAccountDeleted,
 }: {
   // ... types
 }) {
   const [copyRulesDialogOpen, setCopyRulesDialogOpen] = useState(false);
 
-  const sourceAccounts = allAccounts.filter(
-    (account) => account.id !== emailAccount.id,
-  );
+  const sourceAccounts = useMemo(
+    () => allAccounts.filter((account) => account.id !== emailAccount.id),
+    [allAccounts, emailAccount.id],
+  );
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83a9be0 and 1980f99.

📒 Files selected for processing (1)
  • apps/web/app/(app)/accounts/page.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/app/(app)/*/page.tsx

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/*/page.tsx: Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directly

Create new pages at apps/web/app/(app)/PAGE_NAME/page.tsx with components either colocated in the same folder or in page.tsx

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Follow tailwindcss patterns with prettier-plugin-tailwindcss class organization
Prefix client-side environment variables with NEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/accounts/page.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/app/(app)/accounts/page.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/app/**

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks over class components
Use shadcn/ui components when available
Follow consistent naming conventions with PascalCase for component names
Use LoadingContent component for async data with loading and error states
Use result?.serverError with toastError and toastSuccess for mutation error handling

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/app/(app)/accounts/page.tsx
apps/web/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/accounts/page.tsx
🧠 Learnings (15)
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/{app/api,utils/actions}/**/*.ts : Use `withAuth` for user-level operations and `withEmailAccount` for email-account-level operations

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-06-05T09:49:12.168Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 485
File: apps/web/app/(landing)/login/page.tsx:41-43
Timestamp: 2025-06-05T09:49:12.168Z
Learning: In Next.js App Router, components that use the `useSearchParams` hook require a Suspense boundary to handle the asynchronous nature of search parameter access. The Suspense wrapper is necessary and should not be removed when a component uses useSearchParams.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2024-08-23T11:37:26.779Z
Learnt from: aryanprince
Repo: elie222/inbox-zero PR: 210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Implement all server actions using the `next-safe-action` library with actionClient, actionClientUser, or adminActionClient for type safety and validation

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actions

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:42:11.919Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:11.919Z
Learning: Applies to utils/**/*.{js,ts,jsx,tsx} : The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `revalidatePath` or `revalidateTag` from 'next/cache' within server action handlers when mutations modify data displayed elsewhere

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Import error and success toast utilities from '@/components/Toast' for displaying notifications

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/components/ui/**/*.tsx : Shadcn UI components are located in `components/ui` directory

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use shadcn/ui components when available

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `actionClient` when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 537
File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34
Timestamp: 2025-07-08T13:14:07.449Z
Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.

Applied to files:

  • apps/web/app/(app)/accounts/page.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/accounts/page.tsx (2)
apps/web/components/new-landing/common/Card.tsx (3)
  • Card (67-105)
  • CardHeader (22-54)
  • CardContent (10-12)
apps/web/app/(app)/accounts/CopyRulesDialog.tsx (1)
  • CopyRulesDialog (54-270)
⏰ 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). (2)
  • GitHub Check: test
  • GitHub Check: Review for correctness
🔇 Additional comments (3)
apps/web/app/(app)/accounts/page.tsx (3)

195-240: Dropdown implementation follows best practices.

The DropdownMenu structure correctly uses:

  • asChild for composing Button and DropdownMenuItem with Link
  • e.preventDefault() to keep the dropdown open when triggering ConfirmDialog
  • Conditional rendering for the Transfer rules option
  • Proper accessibility through shadcn/ui components

242-248: CopyRulesDialog integration looks clean.

The controlled dialog pattern with local state management and proper prop passing follows React best practices.


61-117: Well-structured component refactoring.

Breaking AccountItem into AccountHeader and AccountActions subcomponents improves:

  • Separation of concerns (display vs actions)
  • Code readability and maintainability
  • Component reusability

The placement of helper components at the bottom follows project guidelines.

</div>

{selectedSourceId && (
<LoadingContent loading={isLoading} error={error}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useSWR returns an Error, but LoadingContent expects a structured error. Consider mapping the SWR error to { error: error.message } when passing it so ErrorDisplay shows failures correctly.

Suggested change
<LoadingContent loading={isLoading} error={error}>
<LoadingContent loading={isLoading} error={error ? { error: error.message } : undefined}>

🚀 Reply to ask Macroscope to explain or update this suggestion.

👍 Helpful? React to give us feedback.

@elie222 elie222 merged commit 86a3cf3 into main Dec 18, 2025
16 checks passed
@elie222 elie222 deleted the feat/copy-rules branch December 18, 2025 19:04
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.

1 participant

Comments