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 live batched activity log with SWR polling, a reducer-based bulk-run FSM and tests, AI-queue control helpers and higher concurrency, a beforeunload hook, and landing-page demos; integrates these into bulk-run UI and polls /api/user/executed-rules/batch. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as BulkRunRules (UI)
participant Reducer as bulkRunReducer
participant Queue as AI Queue (PQueue)
participant BAL as BulkProcessActivityLog
participant SWR as SWR hook
participant API as /api/user/executed-rules/batch
UI->>Reducer: dispatch START
UI->>Queue: resumeAiQueue() / enqueue tasks
UI->>Reducer: dispatch THREADS_QUEUED (threads[])
UI->>BAL: render with threads, processedThreadIds, aiQueue
BAL->>SWR: start polling (every 2s) with messageIds
loop every 2s
SWR->>API: fetch executed rules batch
API-->>SWR: executed rules payload
SWR-->>BAL: executedRulesData
BAL->>BAL: map executedRules → mark entries completed, set ruleName
BAL-->>UI: activity log updates (re-render)
end
Queue->>Queue: process AI tasks (concurrency 3)
Queue-->>UI: task complete events
UI->>Reducer: dispatch COMPLETE / update processedThreadIds
Reducer-->>UI: updated state (isProcessing/isPaused/stopped)
UI->>Queue: pauseAiQueue() / resumeAiQueue() / clearAiQueue() (user actions)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 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 |
Add bulk processing UI with pause/resume/stop controls, a live activity log capped at 50 entries, and raise AI queue concurrency to 3 in BulkRunRules.tsxIntroduce a reducer-driven bulk run flow with queue pause/resume/stop, integrate a polling activity log, add a before-unload guard, and switch the AI queue to concurrency 3. The activity log renders per-email status and rule labels while polling executed rules. 📍Where to StartStart with the state machine and UI wiring in Macroscope summarized 46d6ca5. |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (2)
76-119: Consider cleanup on component unmount.The handlers are well-implemented with proper validation and error recovery. However, if the dialog is closed or component unmounts while processing is active, the async operation continues. Consider adding a cleanup effect.
🔎 Suggested cleanup on unmount
+ import { useEffect, useReducer, useRef, useState } from "react"; ... const abortRef = useRef<() => void>(undefined); + // Cleanup on unmount + useEffect(() => { + return () => { + abortRef.current?.(); + }; + }, []);
354-358: Consider awaiting therun()call or documenting fire-and-forget intent.The
run()function is called withoutawait, making it fire-and-forget. This is likely intentional (the abort function is returned immediately), but unhandled promise rejections could occur if an unexpected error happens. Consider adding a.catch()handler.🔎 Suggested error boundary for run()
- run(); + run().catch((err) => { + console.error("Unexpected error in bulk run:", err); + onComplete("error", totalProcessed); + });apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (2)
147-154: Add error handling for SWR polling.The SWR hook lacks error handling. While polling failures are non-critical here, handling errors gracefully improves user experience and prevents silent failures.
🔎 Add error handling
const { data: executedRulesData } = useSWR<BatchExecutedRulesResponse>( messageIds.length > 0 && !allCompleted ? `/api/user/executed-rules/batch?messageIds=${messageIds.join(",")}` : null, { refreshInterval: messageIds.length > 0 && !allCompleted ? 2000 : 0, + onError: (error) => { + console.error("Failed to fetch executed rules:", error); + }, }, );Alternatively, for user-facing errors:
+ import { toastError } from "@/components/Toast"; - const { data: executedRulesData } = useSWR<BatchExecutedRulesResponse>( + const { data: executedRulesData, error: executedRulesError } = useSWR<BatchExecutedRulesResponse>( messageIds.length > 0 && !allCompleted ? `/api/user/executed-rules/batch?messageIds=${messageIds.join(",")}` : null, { refreshInterval: messageIds.length > 0 && !allCompleted ? 2000 : 0, }, ); + useEffect(() => { + if (executedRulesError?.serverError) { + toastError({ description: "Failed to fetch rule execution status" }); + } + }, [executedRulesError]);As per coding guidelines, async operations should use
result?.serverErrorwithtoastErrorfor error handling.
33-56: Consider mobile-responsive max-height.The fixed
max-h-72(18rem) on line 43 works on desktop but might be too tall on smaller mobile screens, potentially pushing other content off-screen.🔎 Responsive height adjustment
- <div className="max-h-72 overflow-y-auto overflow-x-hidden"> + <div className="max-h-48 overflow-y-auto overflow-x-hidden sm:max-h-72">As per coding guidelines, implement responsive design with Tailwind CSS using a mobile-first approach.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx(7 hunks)apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.ts(1 hunks)apps/web/app/(landing)/components/page.tsx(3 hunks)apps/web/store/ai-queue.ts(1 hunks)apps/web/utils/queue/ai-queue.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
**/*.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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
**/*.{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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
**/*.{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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
!(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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
**/*.{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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
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/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/store/ai-queue.tsapps/web/utils/queue/ai-queue.tsapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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/queue/ai-queue.ts
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)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
apps/web/**/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
**/{pages,routes,components}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/gmail-api.mdc)
Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder
Files:
apps/web/app/(landing)/components/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/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
apps/web/**/*.{tsx,jsx,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Ensure responsive design with mobile-first approach
Files:
apps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
**/*.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/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
🧠 Learnings (18)
📚 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 : Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments
Applied to files:
apps/web/store/ai-queue.tsapps/web/utils/queue/ai-queue.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 : Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using `withRetry`
Applied to files:
apps/web/utils/queue/ai-queue.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 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 : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Applied to files:
apps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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 LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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 : 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/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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 test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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} : Avoid testing implementation details
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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 **/__tests__/**/*.{ts,tsx} : AI tests must be placed in the `__tests__` directory and are not run by default (they use a real LLM)
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.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 **/*.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/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts
🧬 Code graph analysis (4)
apps/web/app/(landing)/components/page.tsx (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (2)
ActivityLog(18-58)ActivityLogEntry(10-16)
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (4)
apps/web/components/new-landing/common/Badge.tsx (1)
Badge(24-99)apps/web/app/api/threads/route.ts (1)
ThreadsResponse(56-56)apps/web/app/api/user/executed-rules/batch/route.ts (1)
BatchExecutedRulesResponse(8-8)apps/web/utils/queue/ai-queue.ts (1)
aiQueue(6-6)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (3)
apps/web/utils/queue/ai-queue.ts (3)
resumeAiQueue(9-9)pauseAiQueue(8-8)clearAiQueue(10-10)apps/web/app/(app)/[emailAccountId]/assistant/SetDateDropdown.tsx (1)
SetDateDropdown(14-57)apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (1)
BulkProcessActivityLog(115-243)
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts (1)
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.ts (4)
bulkRunReducer(26-96)initialBulkRunState(19-24)BulkRunState(3-8)getProgressMessage(98-115)
⏰ 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: cubic · AI code reviewer
- GitHub Check: test
- GitHub Check: Review for correctness
🔇 Additional comments (13)
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.test.ts (1)
1-328: LGTM! Comprehensive test coverage for the reducer and progress message utility.The test suite effectively covers all reducer actions (START, THREADS_QUEUED, COMPLETE, PAUSE, RESUME, STOP, RESET) with proper state transition verification and edge case handling. Tests are well-organized, independent, and follow the project's testing conventions with descriptive names.
apps/web/store/ai-queue.ts (1)
29-31: LGTM! Consistent implementation with existing atom update patterns.The
clearAiQueueAtomfunction follows the same pattern aspushToAiQueueAtomandremoveFromAiQueueAtom, correctly resetting the atom to an empty Set.apps/web/app/(landing)/components/page.tsx (3)
42-45: LGTM! Proper import of ActivityLog component for demo purposes.The import follows the project's path alias conventions and correctly imports both the component and its type.
560-628: Good demo coverage for the ActivityLog component.The demo section effectively showcases various states of the ActivityLog component including default mixed states, paused state, long text truncation handling, and all-completed state. This provides good visual testing coverage.
792-828: LGTM! Helper function correctly placed at bottom of file.The
getActivityLogEntrieshelper follows the coding guidelines by being placed at the bottom of the file and provides realistic sample data for the demo.apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (2)
3-41: LGTM! Clean imports following project conventions.The imports are well-organized, using the
@/path alias consistently. The separation of queue controls fromutils/queue/ai-queue.tsand atom operations from@/store/ai-queueis appropriate.
131-260: Well-structured UI with proper state-based rendering.The dialog content correctly uses
LoadingContentfor async states, conditionally renders controls based on processing state, and properly disables inputs when processing is active. The integration withBulkProcessActivityLogprovides good user feedback.apps/web/utils/queue/ai-queue.ts (1)
5-11: Concurrency level increase appears safe for Gmail API constraints.Increasing concurrency to 3 improves bulk processing speed. The Gmail API has a per-user-per-second limit of 250 quota units, and a concurrency level of 3 is conservative enough to respect this limit and per-user concurrent request constraints. The queue control helper functions are well-implemented wrappers.
The exports are properly separated:
apps/web/store/ai-queue.tshandles state management whileapps/web/utils/queue/ai-queue.tsprovides the queue instance and control functions—no duplication exists.apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.ts (2)
1-96: LGTM! Well-structured reducer implementation.The reducer follows React best practices with immutable state updates, clear action types, and proper state transition guards. The logic for handling pause/resume/stop states is sound, and the protection against overriding stopped state (lines 53, 83) prevents race conditions.
98-115: LGTM! Clear progress messaging logic.The function correctly handles different state scenarios and provides appropriate user feedback for idle, processing, stopped, and completed states.
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (3)
157-193: LGTM! Robust activity log state management.The effect correctly:
- Prevents duplicate entries using
existingMessageIdsSet- Handles initial status based on executed rules data
- Maintains a fixed-size log (last 50 entries)
- Uses immutable updates
The dependency on
processedThreadIds(a Set) works correctly since the reducer creates new Set instances on updates.
196-214: LGTM! Clean completion status updates.The effect efficiently updates entries to "completed" status when rule execution data becomes available, preserving already-completed entries.
8-8: The Badge import and usage are correct. The component at@/components/Badgeuses acolorprop, and lines 86-92 correctly pass thecolorprop. The separate Badge component at@/components/new-landing/common/Badge.tsxusesvariant, but that is a different component not being imported here. No issues found.Likely an incorrect or invalid review comment.
| // Get message IDs from processed threads | ||
| const messageIds = Array.from(processedThreadIds) | ||
| .map((threadId) => { | ||
| const thread = threads.find((t) => t.id === threadId); |
There was a problem hiding this comment.
threads.find(...) assumes processed threads are in the current inbox list. When bulk-processing older threads, this returns undefined and those entries are skipped, so the log looks empty/incomplete. Consider decoupling from the inbox snapshot: pass a complete thread/message map (or fetch missing threads by ID) from the bulk-run flow so all processed IDs are represented; otherwise, consider documenting that the log only shows currently visible threads.
🚀 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
♻️ Duplicate comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (2)
67-74: Consider refiningisProcessingto prevent UI state mismatch.The current logic
isActive || queue.size > 0keeps controls visible whenstatusis "processing" but the queue is empty. This can occur afterCOMPLETEis dispatched (which keeps status as "processing") but before the user manually stops, leaving pause/stop buttons visible with nothing to control.However, using only
queue.size > 0would hide controls during the fetching phase before items are queued. A more robust solution might be to track fetching separately in the reducer state (e.g.,isFetching: boolean) or ensure the queue is always resumed on start and the reducer transitions to "idle" when both fetching completes and the queue is empty.Related to past review feedback about
isProcessingstaying true incorrectly.
106-115: Resume the AI queue at the start of each run.If a previous run was paused and then stopped, the queue remains in a paused state. Starting a new run without resuming would enqueue tasks that never execute until the user manually resumes. Call
resumeAiQueue()at the beginning ofhandleStartto ensure the queue is always active when starting a new run.🔎 Proposed fix
const handleStart = async () => { dispatch({ type: "START" }); + resumeAiQueue(); if (!startDate) {Related to past review feedback about ensuring the queue is resumed on start.
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (1)
134-141: Activity log may not show threads outside the current inbox view.The
threads.find()call assumes all processed threads exist in thethreadsarray (from the inbox query). When bulk-processing threads older than the current page or outside the inbox (e.g., archived),findreturnsundefinedand those threads are filtered out, resulting in an incomplete activity log.Consider one of these approaches:
- Pass a dedicated thread map that accumulates all processed threads rather than relying on the inbox snapshot
- Fetch missing threads by ID when needed
- Document this limitation in the component or UI if it's an acceptable trade-off
Related to past review feedback about the
threads.find()limitation.
🧹 Nitpick comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (1)
128-133: Consider resuming the queue inhandleStopfor defensive cleanup.While the queue is cleared, it may still be left in a paused state if the user paused before stopping. Although resuming on start (as suggested above) addresses this, defensively calling
resumeAiQueue()here ensures the queue is always reset to a ready state after stopping.🔎 Proposed addition
const handleStop = () => { dispatch({ type: "STOP", completedCount: completed }); clearAiQueue(); clearAiQueueAtom(); + resumeAiQueue(); abortRef.current?.(); };apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (1)
158-195: Consider removingexecutedRulesDatafrom effect dependencies for efficiency.Including
executedRulesDatain the dependency array causes this effect to re-run every 2 seconds (the SWR polling interval), even when no new threads are added. While the duplicate check prevents incorrect behavior, the effect still executes the entire loop unnecessarily.Since the second effect (lines 197-216) already handles updating entries when
executedRulesDatachanges, consider removingexecutedRulesDatafrom this effect's dependencies and always initializing new entries withstatus: "processing". The second effect will update them to "completed" when the data arrives.🔎 Proposed refactor
- }, [processedThreadIds, executedRulesData, threads]); + }, [processedThreadIds, threads]);And update the entry initialization:
newEntries.push({ threadId: thread.id, messageId: message.id, from: message.headers.from || "Unknown", subject: message.headers.subject || "(No subject)", - status: executedRule ? "completed" : "processing", + status: "processing", - ruleName: executedRule?.rule?.name, timestamp: Date.now(), });
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx(6 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
apps/web/**/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
🧠 Learnings (6)
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 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 : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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 LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (3)
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.ts (3)
bulkRunReducer(26-96)initialBulkRunState(19-24)getProgressMessage(98-115)apps/web/utils/queue/ai-queue.ts (3)
resumeAiQueue(9-9)pauseAiQueue(8-8)clearAiQueue(10-10)apps/web/store/ai-queue.ts (1)
clearAiQueueAtom(29-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: cubic · AI code reviewer
- GitHub Check: Review for correctness
🔇 Additional comments (5)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (2)
77-88: Good use of beforeunload protection.The implementation correctly prevents users from accidentally leaving the page during active processing, providing a safety net for long-running operations.
118-126: LGTM!The pause/resume handler correctly synchronizes both the queue state and the reducer state, ensuring UI and processing stay in sync.
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (3)
18-58: Well-structured presentational component.The
ActivityLogcomponent follows good React patterns with clear props, appropriate null-rendering when empty, and clean visual hierarchy. The scrollable container with max height is a good UX choice for potentially long lists.
197-216: Efficient completion tracking.This effect correctly updates entries when execution completes, with appropriate guards to skip already-completed entries and avoid unnecessary state updates.
218-244: LGTM!The transformation from internal to public format is clean and the status derivation logic correctly reflects the current processing state based on queue membership and completion status.
There was a problem hiding this comment.
2 issues found across 2 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/hooks/useBeforeUnload.ts">
<violation number="1" location="apps/web/hooks/useBeforeUnload.ts:12">
P2: Missing `e.returnValue` assignment for cross-browser compatibility. Some browsers (particularly Safari) require `e.returnValue` to be set to trigger the native "leave page?" dialog. Without it, the hook may silently fail.</violation>
</file>
<file name="apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx:74">
P2: Race condition: Button remains clickable after click until queue is populated. The old logic `isActive || queue.size > 0` hid the button immediately on START dispatch, but the new `queue.size > 0` leaves a window where the button is still visible/clickable. Consider keeping `isActive` in the condition or adding `isActive` to the button's disabled prop.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (1)
96-109: Race condition:abortRef.currentmay not be set when Stop is clicked.Line 97 correctly resumes the queue before starting (addressing a previous review concern). However, the race condition flagged in past reviews remains:
handleStopcan be invoked immediately after the user clicks "Process Emails," but before the asynconRun(...)on Line 99 returns and assigns the abort function toabortRef.current. In this scenario, Line 125'sabortRef.current?.()would be a no-op, leaving the background fetching unaborted.Suggested fix: Set abortRef immediately with a buffered abort
// Ensure queue is not paused from a previous run resumeAiQueue(); - abortRef.current = await onRun( + let pendingAbort = false; + abortRef.current = () => { + pendingAbort = true; + }; + + const abort = await onRun( emailAccountId, { startDate, endDate, includeRead }, (ids) => { dispatch({ type: "THREADS_QUEUED", ids }); }, (_completionStatus, count) => { dispatch({ type: "COMPLETE", count }); }, ); + + if (pendingAbort) { + abort(); + } else { + abortRef.current = abort; + }This ensures that if
handleStopis called early, the abort is buffered and executed onceonRunresolves.
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (1)
121-126: Consider resuming the queue inhandleStopfor defensive programming.While Line 97 in
handleStartensures the queue is resumed before each run, previous review feedback suggests also callingresumeAiQueue()inhandleStopto guarantee the queue isn't left in a paused state between runs. This makes the stop operation more self-contained and prevents subtle state bugs if the start flow changes.Proposed change
const handleStop = () => { dispatch({ type: "STOP", completedCount: completed }); clearAiQueue(); clearAiQueueAtom(); + resumeAiQueue(); abortRef.current?.(); };Based on learnings from previous reviews.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx(6 hunks)apps/web/hooks/useBeforeUnload.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (20)
**/*.{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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
apps/web/hooks/use*.ts
📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)
apps/web/hooks/use*.ts: Use SWR hooks for client-side data fetching, with hooks stored inapps/web/hooks/use*.tsthat return typed responses from GET API routes
Callmutate()on SWR hooks after successful mutations to refresh cached data
apps/web/hooks/use*.ts: Use theuseprefix for custom hook filenames (e.g.,useAccounts.ts)
For data fetching in custom hooks, prefer usinguseSWRand wrap it to handle API endpoint URL, returning data, loading state, error state, and potentially themutatefunction
Create dedicated hooks for specific data types (e.g.,useAccounts,useLabels) to wrapuseSWRfor individual API endpoints
Files:
apps/web/hooks/useBeforeUnload.ts
apps/web/hooks/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/hooks.mdc)
Place custom hooks in the
apps/web/hooks/directory
Files:
apps/web/hooks/useBeforeUnload.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/hooks/useBeforeUnload.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
apps/web/**/hooks/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Use SWR for client-side data fetching with type-safe response types
Files:
apps/web/hooks/useBeforeUnload.ts
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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
apps/web/**/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
🧠 Learnings (21)
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Use the `use` prefix for custom hook filenames (e.g., `useAccounts.ts`)
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:27.988Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:27.988Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : All feature flag hooks should be defined in `apps/web/hooks/useFeatureFlags.ts`
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:32.328Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:32.328Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : Feature flag hooks should be defined in `apps/web/hooks/useFeatureFlags.ts` with two patterns: boolean flags using `useFeatureFlagEnabled("key")` and variant flags using `useFeatureFlagVariantKey("key")` with type casting
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:32.328Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:32.328Z
Learning: Applies to **/*.{ts,tsx} : For early access feature flags, create hooks using the naming convention `use[FeatureName]Enabled` that return a boolean from `useFeatureFlagEnabled("flag-key")`
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : Custom hooks must use the `use` prefix in their filename (e.g., `useAccounts.ts`)
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) that wrap `useSWR`, handle the API endpoint URL, and return data, loading state, error state, and the `mutate` function
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) to wrap `useSWR` for individual API endpoints
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:27.988Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:27.988Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : For early access features, create boolean flag hooks using `useFeatureFlagEnabled` with the pattern `export function use[FeatureName]Enabled()`
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:27.988Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:27.988Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : Use `use[FeatureName]Enabled` naming convention for boolean feature flag hooks and `use[FeatureName]Variant` for A/B test variant hooks
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:32.328Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:32.328Z
Learning: Centralize all feature flag hooks in `apps/web/hooks/useFeatureFlags.ts` rather than scattering them across multiple files
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : If you need to use `onClick` in a component, that component is a client component and file must start with `use client`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/**/hooks/*.ts : Use SWR for client-side data fetching with type-safe response types
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 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/hooks/use*.ts : Use SWR hooks for client-side data fetching, with hooks stored in `apps/web/hooks/use*.ts` that return typed responses from GET API routes
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (5)
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.ts (3)
bulkRunReducer(26-96)initialBulkRunState(19-24)getProgressMessage(98-115)apps/web/hooks/useBeforeUnload.ts (1)
useBeforeUnload(7-20)apps/web/utils/queue/ai-queue.ts (3)
resumeAiQueue(9-9)pauseAiQueue(8-8)clearAiQueue(10-10)apps/web/store/ai-queue.ts (1)
clearAiQueueAtom(29-31)apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (1)
BulkProcessActivityLog(117-245)
⏰ 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: test
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Review for correctness
🔇 Additional comments (4)
apps/web/hooks/useBeforeUnload.ts (1)
1-20: LGTM! Well-implemented beforeunload protection hook.The hook correctly follows React patterns and beforeunload best practices. The implementation properly prevents page navigation when enabled, uses appropriate cleanup, and has correct dependencies.
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (3)
68-78: Well-structured derived state and navigation protection.The derived state calculations cleanly separate concerns, and Line 74 correctly derives
isProcessingfromqueue.size > 0rather than relying on status, which addresses the concern from previous reviews. TheuseBeforeUnloadhook appropriately prevents accidental navigation during active operations.
111-119: LGTM! Clean pause/resume logic.The handler correctly synchronizes the AI queue state with the reducer state, ensuring both pause and resume operations update the queue and dispatch the appropriate action.
141-247: Excellent state-driven UI updates.The UI correctly reflects the processing state throughout:
- Date inputs and toggles are appropriately disabled during active processing (Lines 167, 176, 186)
- The activity log is conditionally shown when there's processing state to display (Lines 202-212)
- Button visibility and content dynamically adapt to whether processing is active (Lines 214-247)
- Pause/Resume toggle provides clear visual feedback with icons (Lines 226-236)
The refactor successfully coordinates reducer state with UI presentation.
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (4)
73-73: Race condition: Button remains clickable between START and queue population.The
isProcessingflag only checksqueue.size > 0, which means there's a window between dispatchingSTART(line 80) and threads being added to the queue (line 102) where the "Process Emails" button remains visible and clickable. This allows users to trigger multiple concurrent runs.🔎 Proposed fix
Include
state.statusin the check to hide the button immediately after START is dispatched:- const isProcessing = queue.size > 0; + const isProcessing = state.status === "processing" || queue.size > 0;
98-107: Race condition: handleStop may be ineffective if called early.The
abortRef.currentis assigned after theawait onRun(...)call completes. If a user clicks Stop beforeonRunreturns the abort function, theabortRef.current?.()call inhandleStop(line 124) won't abort the ongoing fetch loop. This leaves the background fetch process running even though the UI shows "stopped".Consider one of these approaches:
- Return the abort function synchronously from
onRun(changerun()on line 364 to start the async loop in the background)- Buffer the stop request and invoke abort immediately once
abortRef.currentis set- Add a separate abort signal that
onRunchecks before starting each iteration
120-125: Missing queue resume on stop could block subsequent runs.If the user stops processing while the queue is paused,
pauseAiQueue()state persists. The next time they click "Process Emails", new tasks will be enqueued into a paused queue and won't execute until manually resumed. Always callresumeAiQueue()inhandleStopto reset the queue to a clean state.🔎 Proposed fix
const handleStop = () => { dispatch({ type: "STOP", completedCount: completed }); + resumeAiQueue(); clearAiQueue(); clearAiQueueAtom(); abortRef.current?.(); };
215-223: Button visibility subject to same race condition as line 73.The button is only hidden when
!isProcessing, which doesn't account forstate.status. This is the same race condition flagged at line 73 — the button remains clickable between START dispatch and queue population.See the proposed fix at line 73.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx(6 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
apps/web/**/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
🧠 Learnings (10)
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 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 : Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using `withRetry`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : If you need to use `onClick` in a component, that component is a client component and file must start with `use client`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/**/hooks/*.ts : Use SWR for client-side data fetching with type-safe response types
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 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/hooks/use*.ts : Use SWR hooks for client-side data fetching, with hooks stored in `apps/web/hooks/use*.ts` that return typed responses from GET API routes
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
⏰ 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
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (1)
236-257: Missingtypeattribute on buttons.Per coding guidelines, all button elements should include a
typeattribute. The Pause/Resume and Stop buttons are missing this attribute.🔎 Proposed fix
- <Button size="sm" onClick={handlePauseResume}> + <Button type="button" size="sm" onClick={handlePauseResume}> {isPaused ? ( <> <PlayIcon className="mr-1.5 h-3.5 w-3.5" /> Resume </> ) : ( <> <PauseIcon className="mr-1.5 h-3.5 w-3.5" /> Pause </> )} </Button> <Button variant="outline" size="sm" + type="button" onClick={handleStop} >apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (2)
134-139: Refine the clearing condition to prevent mid-run clears.The current implementation clears the log whenever
loadingbecomestrue, but ifloadingtoggles during a run, this might unexpectedly clear the log. Per the previous review comment, consider clearing only when starting a fresh run.🔎 More precise clearing condition
useEffect(() => { - if (loading) { + if (loading && processedThreadIds.size === 0) { setActivityLog([]); } - }, [loading]); + }, [loading, processedThreadIds]);
239-242: Consider memoizing the processing count.The
processingCountis recalculated on every render. While the performance impact is likely minimal, memoizing it would follow React best practices.🔎 Memoized version
+ import { useEffect, useState, useMemo } from "react"; // ... rest of component - const processingCount = activityLog.filter( - (entry) => aiQueue.has(entry.threadId) && entry.status !== "completed", - ).length; + const processingCount = useMemo( + () => + activityLog.filter( + (entry) => aiQueue.has(entry.threadId) && entry.status !== "completed", + ).length, + [activityLog, aiQueue], + );
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx(6 hunks)apps/web/hooks/useBeforeUnload.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (20)
**/*.{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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
apps/web/hooks/use*.ts
📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)
apps/web/hooks/use*.ts: Use SWR hooks for client-side data fetching, with hooks stored inapps/web/hooks/use*.tsthat return typed responses from GET API routes
Callmutate()on SWR hooks after successful mutations to refresh cached data
apps/web/hooks/use*.ts: Use theuseprefix for custom hook filenames (e.g.,useAccounts.ts)
For data fetching in custom hooks, prefer usinguseSWRand wrap it to handle API endpoint URL, returning data, loading state, error state, and potentially themutatefunction
Create dedicated hooks for specific data types (e.g.,useAccounts,useLabels) to wrapuseSWRfor individual API endpoints
Files:
apps/web/hooks/useBeforeUnload.ts
apps/web/hooks/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/hooks.mdc)
Place custom hooks in the
apps/web/hooks/directory
Files:
apps/web/hooks/useBeforeUnload.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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/hooks/useBeforeUnload.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
apps/web/**/hooks/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Use SWR for client-side data fetching with type-safe response types
Files:
apps/web/hooks/useBeforeUnload.ts
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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
apps/web/**/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
🧠 Learnings (22)
📚 Learning: 2025-11-25T14:38:27.988Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:27.988Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : For early access features, create boolean flag hooks using `useFeatureFlagEnabled` with the pattern `export function use[FeatureName]Enabled()`
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:32.328Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:32.328Z
Learning: Applies to **/*.{ts,tsx} : For early access feature flags, create hooks using the naming convention `use[FeatureName]Enabled` that return a boolean from `useFeatureFlagEnabled("flag-key")`
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:32.328Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:32.328Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : Feature flag hooks should be defined in `apps/web/hooks/useFeatureFlags.ts` with two patterns: boolean flags using `useFeatureFlagEnabled("key")` and variant flags using `useFeatureFlagVariantKey("key")` with type casting
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Use the `use` prefix for custom hook filenames (e.g., `useAccounts.ts`)
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) to wrap `useSWR` for individual API endpoints
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) that wrap `useSWR`, handle the API endpoint URL, and return data, loading state, error state, and the `mutate` function
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:27.988Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:27.988Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : All feature flag hooks should be defined in `apps/web/hooks/useFeatureFlags.ts`
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : Custom hooks must use the `use` prefix in their filename (e.g., `useAccounts.ts`)
Applied to files:
apps/web/hooks/useBeforeUnload.ts
📚 Learning: 2025-11-25T14:38:27.988Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:27.988Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : Use `use[FeatureName]Enabled` naming convention for boolean feature flag hooks and `use[FeatureName]Variant` for A/B test variant hooks
Applied to files:
apps/web/hooks/useBeforeUnload.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/hooks/use*.ts : Use SWR hooks for client-side data fetching, with hooks stored in `apps/web/hooks/use*.ts` that return typed responses from GET API routes
Applied to files:
apps/web/hooks/useBeforeUnload.tsapps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsxapps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
📚 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 : Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using `withRetry`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : If you need to use `onClick` in a component, that component is a client component and file must start with `use client`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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/**/hooks/*.ts : Use SWR for client-side data fetching with type-safe response types
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 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 : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.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 LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (5)
apps/web/app/(app)/[emailAccountId]/assistant/bulk-run-rules-reducer.ts (3)
bulkRunReducer(26-96)initialBulkRunState(19-24)getProgressMessage(98-115)apps/web/hooks/useBeforeUnload.ts (1)
useBeforeUnload(7-21)apps/web/utils/queue/ai-queue.ts (3)
resumeAiQueue(9-9)pauseAiQueue(8-8)clearAiQueue(10-10)apps/web/store/ai-queue.ts (1)
clearAiQueueAtom(29-31)apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (1)
BulkProcessActivityLog(117-252)
⏰ 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: test
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Review for correctness
🔇 Additional comments (10)
apps/web/hooks/useBeforeUnload.ts (1)
7-21: LGTM!The hook implementation is clean and follows best practices:
- Proper cleanup of event listener on unmount or when
enabledchanges- Cross-browser compatibility addressed with both
e.preventDefault()ande.returnValue = ""(fixing the Safari issue flagged in past reviews)- Follows hook naming conventions and placement guidelines
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (4)
68-78: Well-structured derived state addressing past concerns.The introduction of
isBusy = isProcessing || state.status === "processing"is a good improvement. This ensuresuseBeforeUnloadprotects both the initial fetch phase (whenstate.status === "processing"but queue is empty) and the active processing phase (whenqueue.size > 0).
80-118: Good error handling and validation.The
handleStartfunction properly:
- Validates inputs before proceeding
- Resumes the queue to prevent stuck state from previous runs
- Has try/catch with user-friendly error toast
- Dispatches RESET on failures to restore idle state
This addresses the past review concern about missing error handling.
225-233: Race condition from past reviews addressed.The button visibility now checks
state.status === "idle" && !isProcessing, which hides the button immediately when START is dispatched (sincestate.statusbecomes"processing"). This properly prevents double-clicks during the async gap before the queue is populated.
282-377: Solid batch processing implementation.The
onRunfunction is well-structured:
- Returns abort function immediately while processing runs in background
- Comprehensive error handling with user feedback
- Rate limiting via
sleep()to avoid Gmail API limits- Proper callbacks for state updates (
onThreadsQueued,onComplete)apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx (5)
1-16: LGTM!Clean imports and type definitions. Proper use of
"use client"directive andtypekeyword for type imports.
18-58: LGTM!Well-structured presentation component with proper conditional rendering and accessibility.
60-101: LGTM!Clean row component with appropriate status indicators and text truncation.
165-223: LGTM!The effects properly manage activity log state with functional updates and appropriate dependencies. The
threadsdependency may trigger frequent updates, but this is necessary for real-time log accuracy.
225-252: LGTM!Clean transformation of internal state to presentation props with proper status derivation.
| // Get message IDs from processed threads | ||
| const messageIds = Array.from(processedThreadIds) | ||
| .map((threadId) => { | ||
| const thread = threads.find((t) => t.id === threadId); | ||
| return thread?.messages?.[thread.messages.length - 1]?.id; | ||
| }) | ||
| .filter((id): id is string => !!id) | ||
| .slice(-20); // Keep last 20 |
There was a problem hiding this comment.
Address the incomplete log issue from older threads.
As noted in the previous review, threads.find() returns undefined when bulk-processing threads not in the current inbox snapshot (lines 143-144, 174-175). This causes those entries to be skipped, resulting in an incomplete activity log.
Consider one of these approaches:
- Pass a complete thread map: Have the parent component provide a Map<threadId, thread> that includes all processed threads, not just the current inbox snapshot
- Fetch missing threads: When a threadId in
processedThreadIdsisn't found inthreads, fetch it by ID - Document the limitation: If this is intentional, add a comment explaining that the log only shows currently visible threads
🔎 Verification script to check impact
#!/bin/bash
# Description: Check how BulkProcessActivityLog is used and whether threads might be incomplete
# Find usages of BulkProcessActivityLog
rg -n "BulkProcessActivityLog" --type ts --type tsx -C 3
# Check if threads are filtered or limited before being passed
ast-grep --pattern $'<BulkProcessActivityLog
threads={$_}
$$$
/>'Also applies to: 173-175
🤖 Prompt for AI Agents
In apps/web/app/(app)/[emailAccountId]/assistant/BulkProcessActivityLog.tsx
around lines 141-148 and 173-175, thread lookups using threads.find(...) can
return undefined for processedThreadIds that are not in the current inbox
snapshot, causing skipped log entries; fix by changing the component API to
accept a complete thread map (e.g., threadMap: Map<string, Thread>) from the
parent and use threadMap.get(threadId) as the primary lookup (falling back to
threads.find(...) only if the map is not provided), update call sites to supply
the full map (or document the limitation with a clear comment and prop name if
you choose not to), and add a brief comment in the file explaining the behavior.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (1)
307-374: Consider notifying user when hitting the iteration limit.The loop is hard-capped at 100 iterations (line 308), which limits processing to ~2500 threads. If a user's date range contains more threads, processing will silently stop without notification. While this is a reasonable safeguard, users might be confused if not all emails are processed.
🔎 Suggested improvement
for (let i = 0; i < 100; i++) { // ... existing logic ... } + if (nextPageToken) { + // Reached iteration limit with more pages remaining + console.warn("Bulk processing reached iteration limit"); + } + onComplete("success", totalProcessed); }Alternatively, you could pass a status flag to
onCompleteto display a message like "Processed 2500 emails. Run again to continue."
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx(8 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
apps/web/**/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
🧠 Learnings (9)
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.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)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : If you need to use `onClick` in a component, that component is a client component and file must start with `use client`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 Learning: 2025-12-17T11:18:06.830Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.830Z
Learning: Applies to apps/web/**/hooks/*.ts : Use SWR for client-side data fetching with type-safe response types
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
📚 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/hooks/use*.ts : Use SWR hooks for client-side data fetching, with hooks stored in `apps/web/hooks/use*.ts` that return typed responses from GET API routes
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
⏰ 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 (6)
apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx (6)
1-43: LGTM!The imports are well-organized, following project conventions. The
"use client"directive is correctly placed for a component with event handlers. UsinguseThreadshook for data fetching aligns with the SWR pattern required by coding guidelines.
68-78: LGTM!The derived state logic correctly addresses previous review concerns:
isBusycombines queue activity with processing status, covering the initial fetch phaseuseBeforeUnload(isBusy)now protects the entire processing lifecycle including thread fetching- The separation of
isProcessing(queue-based) andisBusy(includes status) provides appropriate granularity for different UI behaviors
80-118: LGTM!The
handleStartfunction properly addresses previous review concerns:
- Input validation with user-friendly error toasts
resumeAiQueue()called beforeonRunto ensure queue isn't stale-paused- Try/catch with toast error and
RESETdispatch for recovery- The
onRunfunction returns the abort callback synchronously (before the asyncrun()loop completes), soabortRef.currentis available immediately
120-135: LGTM!The pause/resume and stop handlers are well-implemented:
handlePauseResumecorrectly toggles queue state and dispatches corresponding actionshandleStopproperly cleans up by clearing both the queue and atom state, then invoking the abort callback with optional chaining for safety
225-260: LGTM!The button visibility logic correctly addresses previous review concerns:
- "Process Emails" button shows for both
idleandstoppedstates, allowing users to restart after stopping- Control buttons (Pause/Resume, Stop) are shown when
isBusy, which covers both active processing and initial fetch- All buttons include the required
type="button"attribute per coding guidelines
376-379: LGTM!The abort mechanism is correctly implemented. By calling
run()withoutawaitand returningabortimmediately, the caller receives the abort handle synchronously while the async processing continues in the background. This addresses the previously flagged race condition concern.
Summary by CodeRabbit
New Features
Improvements
Tests
✏️ Tip: You can customize this high-level summary in your review settings.