Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughAdds 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| let copiedCount = 0; | ||
| let replacedCount = 0; | ||
|
|
||
| for (const sourceRule of sourceRules) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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). UseasChildprop 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
📒 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 theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/__tests__/helpers.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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, andapps/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/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/__tests__/helpers.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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 withNEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes
Files:
apps/web/__tests__/helpers.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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'sselectoption. 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. AllfindUnique/findFirstcalls 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
AllfindManyqueries 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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/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.tsapps/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
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/__tests__/helpers.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/web/app/(app)/accounts/page.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/__tests__/copy-rules-action.test.tsapps/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.tsapps/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: Usenext-safe-actionwith Zod schemas for all server actions (create/update/delete mutations), storing validation schemas inapps/web/utils/actions/*.validation.ts
Server actions should use 'use server' directive and automatically receive authentication context (emailAccountId) from theactionClient
apps/web/utils/actions/*.ts: Create corresponding server action implementation files using the naming conventionapps/web/utils/actions/NAME.tswith 'use server' directive
Use 'use server' directive at the top of server action implementation files
Implement all server actions using thenext-safe-actionlibrary with actionClient, actionClientUser, or adminActionClient for type safety and validation
UseactionClientUserwhen only authenticated user context (userId) is needed
UseactionClientwhen both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client
UseadminActionClientfor 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.tsfiles in next-safe-action configuration
Access context (userId, emailAccountId, etc.) via thectxobject parameter in the.action()handler
UserevalidatePathorrevalidateTagfrom 'next/cache' within server action handlers when mutations modify data displayed elsewhere
Files:
apps/web/utils/actions/rule.tsapps/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 inapps/web/utils/actionsfolder
Server action files must start withuse serverdirective
Files:
apps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/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: Usenext-safe-actionwith proper Zod validation for server actions
CallrevalidatePathin server actions for cache invalidation after mutations
Files:
apps/web/utils/actions/rule.tsapps/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
UsewithAuthfor user-level operations andwithEmailAccountfor email-account-level operations
Files:
apps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/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.tsapps/web/utils/actions/rule.validation.tsapps/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.tsfiles and export both the schema and inferred type (e.g.,CreateExampleBody)
Export types from Zod schemas usingz.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 conventionapps/web/utils/actions/NAME.validation.tscontaining Zod schemas and inferred types
Define input validation schemas using Zod in.validation.tsfiles 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}: Usevitestfor testing the application
Tests should be colocated next to the tested file with.test.tsor.test.tsxextension (e.g.,dir/format.tsanddir/format.test.ts)
Mockserver-onlyusingvi.mock("server-only", () => ({}))
Mock Prisma usingvi.mock("@/utils/prisma")and import the mock from@/utils/__mocks__/prisma
Usevi.clearAllMocks()inbeforeEachto 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 helpersgetEmail,getEmailAccount, andgetRulefrom@/__tests__/helpersfor 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 atapps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directlyCreate new pages at
apps/web/app/(app)/PAGE_NAME/page.tsxwith components either colocated in the same folder or inpage.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 inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/accounts/page.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor 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 bothchildrenanddangerouslySetInnerHTMLprops 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 usetarget="_blank"withoutrel="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
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor 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.tsapps/web/utils/actions/rule.tsapps/web/utils/actions/rule.validation.tsapps/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.tsapps/web/utils/actions/rule.tsapps/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.tsapps/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.tsapps/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.tsapps/web/utils/actions/rule.tsapps/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.tsapps/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.tsapps/web/utils/actions/rule.tsapps/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.tsapps/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.tsapps/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.tsapps/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.tsapps/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.tsapps/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
actionClientUsersince 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
systemTypeand regular rules by case-insensitive name- Uses
deleteMany+createManypattern to fully replace actions on updateapps/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. Usesvi.clearAllMocks()inbeforeEachto 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.
There was a problem hiding this comment.
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 `<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.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
apps/web/app/(app)/accounts/page.tsx
Outdated
| <Button variant="outline" size="sm"> | ||
| <Link href={prefixPath(emailAccount.id, "/automation")}>View</Link> | ||
| </Button> |
There was a problem hiding this comment.
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 `<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.</comment>
<file context>
@@ -62,6 +68,77 @@ function AccountItem({
+}) {
+ return (
+ <CardContent className="flex justify-between items-center gap-2 flex-wrap">
+ <Button variant="outline" size="sm">
+ <Link href={prefixPath(emailAccount.id, "/automation")}>View</Link>
+ </Button>
</file context>
| <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", |
There was a problem hiding this comment.
Accessing error.error.serverError assumes error.error exists and can throw. Consider using optional chaining so the toast always renders.
| 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.
| fetch(url, { | ||
| headers: { [EMAIL_ACCOUNT_HEADER]: selectedSourceId }, | ||
| }).then((res) => res.json()), |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/web/app/(app)/accounts/page.tsx (1)
138-140: UseasChildprop to avoid invalid HTML nesting.Nesting
<Link>inside<Button>creates invalid HTML structure. Use theasChildprop pattern, as correctly demonstrated in lines 202-210 withDropdownMenuItem.🔎 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
📒 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 theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/(app)/accounts/page.tsxapps/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 atapps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directlyCreate new pages at
apps/web/app/(app)/PAGE_NAME/page.tsxwith components either colocated in the same folder or inpage.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 inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/accounts/page.tsxapps/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/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/(app)/accounts/page.tsxapps/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 withNEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes
Files:
apps/web/app/(app)/accounts/page.tsxapps/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
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/(app)/accounts/page.tsxapps/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.tsxapps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/accounts/CopyRulesDialog.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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.tsxapps/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 bothchildrenanddangerouslySetInnerHTMLprops 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 usetarget="_blank"withoutrel="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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor mutation error handling
Files:
apps/web/app/(app)/accounts/page.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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
allAccountsprop enables the new rules transfer functionality.
61-117: LGTM!Excellent refactoring with clear separation of concerns. The extracted
AccountHeadercomponent 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
asChildpattern (lines 202-210) and correctonSelectpreventDefault 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
CopyRulesDialogcomponent with properly passed props for account transfer functionality.
| onError: (error) => { | ||
| toastError({ | ||
| title: "Error transferring rules", | ||
| description: error.error.serverError || "An unknown error occurred", | ||
| }); | ||
| }, | ||
| }); |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
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
📒 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 theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor 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 atapps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directlyCreate new pages at
apps/web/app/(app)/PAGE_NAME/page.tsxwith components either colocated in the same folder or inpage.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 inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse 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/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport 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 withNEXT_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
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor 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 theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor 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 useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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 bothchildrenanddangerouslySetInnerHTMLprops 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 usetarget="_blank"withoutrel="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
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor 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}> |
There was a problem hiding this comment.
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.
| <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.
Add rule copy flow to Accounts UI and implement
rule.copyRulesFromAccountActionto transfer selected rules between email accountsIntroduce
CopyRulesDialogfor selecting a source account and rules, wire it viaAccountOptionsDropdown, and implementrule.copyRulesFromAccountActionto create or update target rules by name orsystemType, clearing account-specific IDs; add tests and minor Accounts UI tweaks.📍Where to Start
Start with the server action
rule.copyRulesFromAccountActionin 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
.json(). If the API returns a non-2xx status (e.g., 401, 500), the error response body will be parsed and stored inrulesinstead 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
prisma.rule.updateandprisma.rule.createin 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 ]nullorundefinedname (from legacy data or direct database manipulation bypassing validation), callingsourceRule.name.toLowerCase()at line 537 will throw aTypeError: 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
Refactor
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.