Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. 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 stable system-label IDs end-to-end: DB migration and schema fields, provider API changes (labelId), label-config utilities, UI components (LabelCombobox, SystemLabelsSetting), rule/action mapping to labelId, and updates to reply-tracker, cold-email, and related UI/props. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as Settings UI
participant Action as updateSystemLabelsAction
participant DB as Prisma
participant Sync as updateAffectedRules
UI->>Action: Submit {needsReplyLabelId?, awaitingReplyLabelId?, coldEmailLabelId?}
Action->>DB: Update EmailAccount label ID fields
alt needsReplyLabelId changed
Action->>Sync: updateAffectedRules(emailAccountId, type=needsReply, labelId)
Sync->>DB: Fetch TO_REPLY rules & LABEL actions
Sync->>DB: Update LABEL actions with new labelId
end
Action-->>UI: { success: true }
sequenceDiagram
autonumber
participant Cold as Cold-email flow
participant LC as label-config
participant Prov as EmailProvider
participant Mail as Provider.labelMessage
Cold->>LC: getOrCreateSystemLabelId({emailAccountId,type=coldEmail,provider})
alt stored ID
LC-->>Cold: labelId
else not stored
LC->>Prov: getLabelByName(name)
alt found
LC->>DB: updateSystemLabelId(...)
LC-->>Cold: labelId
else not found
LC->>Prov: createLabel(name)
LC->>DB: updateSystemLabelId(...)
LC-->>Cold: labelId
end
end
alt labelId present
Cold->>Mail: labelMessage({messageId, labelId})
end
sequenceDiagram
autonumber
participant RuleAPI as Rule API
participant Prov as EmailProvider
participant DB as Prisma
RuleAPI->>Prov: createEmailProvider(emailAccount)
loop each action
alt action.type == LABEL && missing labelId
RuleAPI->>Prov: getLabelByName(action.label)
alt found
Prov-->>RuleAPI: { id, name }
RuleAPI->>DB: create/update Action with labelId=id and label=name
else not found
RuleAPI->>DB: create/update Action with label fallback (label name only)
end
else
RuleAPI->>DB: create/update Action (unchanged)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on November 30
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
apps/web/utils/email/microsoft.ts (1)
130-133: LGTM!The
getLabelByNamehelper correctly fetches labels and returns the matching one by name. The implementation is consistent with the Gmail provider.For improved performance with large label lists, consider caching the label lookup or implementing a provider-level method that fetches a single label by name if the API supports it.
apps/web/utils/email/google.ts (1)
150-153: LGTM!The
getLabelByNamehelper correctly implements label lookup by name, maintaining consistency with the Microsoft provider implementation.For improved performance with large label lists, consider caching the label lookup if this method is called frequently.
apps/web/utils/reply-tracker/label-helpers.ts (1)
28-46: Consider consistent error logging across all helper functions.
labelMessageAsAwaitingReplylogs an error when the label ID is unavailable (line 21), butremoveAwaitingReplyLabelFromThreadandremoveNeedsReplyLabelFromThreadsilently return without logging (lines 41-42, 61-62). For better observability and debugging, consider logging at least a warning when label IDs cannot be resolved, especially since this might indicate a configuration issue.Apply this diff to add consistent logging:
export async function removeAwaitingReplyLabelFromThread(options: { emailAccountId: string; threadId: string; provider: EmailProvider; }): Promise<void> { const { emailAccountId, threadId, provider } = options; const labelId = await getOrCreateSystemLabelId({ emailAccountId, type: "awaitingReply", provider, }); if (!labelId) { + logger.warn("Failed to get awaiting reply label for removal"); return; } await provider.removeThreadLabel(threadId, labelId); } export async function removeNeedsReplyLabelFromThread(options: { emailAccountId: string; threadId: string; provider: EmailProvider; }): Promise<void> { const { emailAccountId, threadId, provider } = options; const labelId = await getOrCreateSystemLabelId({ emailAccountId, type: "needsReply", provider, }); if (!labelId) { + logger.warn("Failed to get needs reply label for removal"); return; } await provider.removeThreadLabel(threadId, labelId); }Also applies to: 48-66
apps/web/utils/label-config.ts (1)
172-179: Consider batch update for better performance.The current implementation updates each action individually in a loop. For rules with multiple LABEL actions, this results in multiple database round-trips.
Apply this diff to use a batch update:
for (const rule of rules) { - for (const action of rule.actions) { - await prisma.action.update({ - where: { id: action.id }, - data: { labelId }, - }); - } + if (rule.actions.length > 0) { + await prisma.action.updateMany({ + where: { id: { in: rule.actions.map((a) => a.id) } }, + data: { labelId }, + }); + } }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx(1 hunks)apps/web/prisma/migrations/20251005093547_label_id/migration.sql(1 hunks)apps/web/prisma/schema.prisma(4 hunks)apps/web/utils/actions/settings.ts(1 hunks)apps/web/utils/ai/actions.ts(1 hunks)apps/web/utils/ai/assistant/chat.ts(1 hunks)apps/web/utils/cold-email/is-cold-email.test.ts(9 hunks)apps/web/utils/cold-email/is-cold-email.ts(3 hunks)apps/web/utils/email/google.ts(2 hunks)apps/web/utils/email/microsoft.ts(2 hunks)apps/web/utils/email/types.ts(2 hunks)apps/web/utils/label-config.ts(1 hunks)apps/web/utils/reply-tracker/label-helpers.ts(1 hunks)apps/web/utils/rule/rule.ts(6 hunks)
🧰 Additional context used
📓 Path-based instructions (25)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.ts
apps/web/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
apps/web/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/prisma/migrations/20251005093547_label_id/migration.sqlapps/web/utils/ai/assistant/chat.tsapps/web/prisma/schema.prismaapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.ts
apps/web/app/(app)/*/**
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
apps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
apps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
apps/web/app/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirective
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.ts
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/prisma/migrations/20251005093547_label_id/migration.sqlapps/web/utils/ai/assistant/chat.tsapps/web/prisma/schema.prismaapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
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 use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
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 ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/utils/actions/**/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/utils/actions/**/*.ts: Use server actions for all mutations (create/update/delete operations)
next-safe-actionprovides centralized error handling
Use Zod schemas for validation on both client and server
UserevalidatePathin server actions for cache invalidation
apps/web/utils/actions/**/*.ts: Use server actions (withnext-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
UserevalidatePathin server actions to invalidate cache after mutations.Files:
apps/web/utils/actions/settings.ts**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.ts: The same validation should be done in the server action too
Define validation schemas using ZodFiles:
apps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.tsapps/web/utils/actions/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server-actions.mdc)
apps/web/utils/actions/*.ts: Implement all server actions using thenext-safe-actionlibrary for type safety, input validation, context management, and error handling. Refer toapps/web/utils/actions/safe-action.tsfor client definitions (actionClient,actionClientUser,adminActionClient).
UseactionClientUserwhen only authenticated user context (userId) is needed.
UseactionClientwhen both authenticated user context and a specificemailAccountIdare needed. TheemailAccountIdmust be bound when calling the action from the client.
UseadminActionClientfor actions restricted to admin users.
Access necessary context (likeuserId,emailAccountId, etc.) provided by the safe action client via thectxobject in the.action()handler.
Server Actions are strictly for mutations (operations that change data, e.g., creating, updating, deleting). Do NOT use Server Actions for data fetching (GET operations). For data fetching, use dedicated GET API Routes combined with SWR Hooks.
UseSafeErrorfor expected/handled errors within actions if needed.next-safe-actionprovides centralized error handling.
Use the.metadata({ name: "actionName" })method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied viawithServerActionInstrumentationwithin the safe action clients.
If an action modifies data displayed elsewhere, userevalidatePathorrevalidateTagfromnext/cachewithin the action handler as needed.Server action files must start with
use serverFiles:
apps/web/utils/actions/settings.tsapps/web/utils/**
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Create utility functions in
utils/folder for reusable logicFiles:
apps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.tsapps/web/utils/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle sizeFiles:
apps/web/utils/actions/settings.tsapps/web/utils/cold-email/is-cold-email.tsapps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/email/google.tsapps/web/utils/ai/actions.tsapps/web/utils/reply-tracker/label-helpers.tsapps/web/utils/email/types.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/email/microsoft.tsapps/web/utils/rule/rule.tsapps/web/utils/label-config.ts**/*.test.{ts,js}
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
Include security tests in your test suites to verify authentication, authorization, and error handling.
Files:
apps/web/utils/cold-email/is-cold-email.test.ts**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Don't use export or module.exports in test files.
Don't use focused tests.
Don't use disabled tests.
Make sure the assertion function, like expect, is placed inside an it() function call.
Don't nest describe() blocks too deeply in test files.
Don't use focused tests.
Don't use disabled tests.
Don't use export or module.exports in test files.Files:
apps/web/utils/cold-email/is-cold-email.test.ts**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
**/*.test.{ts,tsx}: Use Vitest (vitest) as the testing framework
Colocate tests next to the file under test (e.g., dir/format.ts with dir/format.test.ts)
In tests, mock theserver-onlymodule withvi.mock("server-only", () => ({}));
When testing code that uses Prisma, mock it withvi.mock("@/utils/prisma")and use the mock from@/utils/__mocks__/prisma
Use provided helpers for mocks: import{ getEmail, getEmailAccount, getRule }from@/__tests__/helpers
Each test should be independent
Use descriptive test names
Mock external dependencies in tests
Clean up mocks between tests (e.g.,vi.clearAllMocks()inbeforeEach)
Avoid testing implementation details; focus on observable behavior
Do not mock the LoggerFiles:
apps/web/utils/cold-email/is-cold-email.test.tsapps/web/utils/ai/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)
apps/web/utils/ai/**/*.{ts,tsx}: Place main LLM feature implementations under apps/web/utils/ai/
LLM feature functions should follow the provided TypeScript pattern (separate system/user prompts, use createGenerateObject, Zod schema validation, early validation, return result.object)
Keep system prompts and user prompts separate
System prompt should define the LLM's role and task specifications
User prompt should contain the actual data and context
Always define a Zod schema for response validation
Make Zod schemas as specific as possible to guide LLM output
Use descriptive scoped loggers for each feature
Log inputs and outputs with appropriate log levels and include relevant context
Implement early returns for invalid inputs
Use proper error types and logging for failures
Implement fallbacks for AI failures
Add retry logic for transient failures using withRetry
Use XML-like tags to structure data in prompts
Remove excessive whitespace and truncate long inputs in prompts
Format prompt data consistently across similar functions
Use TypeScript types for all parameters and return values in LLM features
Define clear interfaces for complex input/output structures in LLM featuresFiles:
apps/web/utils/ai/actions.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/{ai,llms}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)
Keep related AI functions co-located and extract common patterns into utilities; document complex AI logic with clear comments
Files:
apps/web/utils/ai/actions.tsapps/web/utils/ai/assistant/chat.tsapps/web/prisma/schema.prisma
📄 CodeRabbit inference engine (.cursor/rules/prisma.mdc)
The Prisma schema file must be located at
apps/web/prisma/schema.prismaFiles:
apps/web/prisma/schema.prisma🧠 Learnings (2)
📚 Learning: 2025-10-02T23:23:48.053Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/llm-test.mdc:0-0 Timestamp: 2025-10-02T23:23:48.053Z Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer existing helpers from @/__tests__/helpers.ts (getEmailAccount, getEmail, getRule, getMockMessage, getMockExecutedRule) over custom helpersApplied to files:
apps/web/utils/cold-email/is-cold-email.test.ts📚 Learning: 2025-09-20T18:24:34.280Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/testing.mdc:0-0 Timestamp: 2025-09-20T18:24:34.280Z Learning: Applies to **/*.test.{ts,tsx} : Use provided helpers for mocks: import `{ getEmail, getEmailAccount, getRule }` from `@/__tests__/helpers`Applied to files:
apps/web/utils/cold-email/is-cold-email.test.ts🧬 Code graph analysis (11)
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx (1)
SystemLabelsSetting(19-178)apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx (7)
apps/web/hooks/useLabels.ts (1)
useLabels(62-88)apps/web/utils/actions/settings.ts (1)
updateSystemLabelsAction(213-243)apps/web/components/SettingCard.tsx (1)
SettingCard(3-26)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-27)apps/web/components/Input.tsx (1)
Label(116-132)apps/web/components/Select.tsx (1)
Select(16-48)apps/web/utils/label.ts (1)
inboxZeroLabels(32-68)apps/web/utils/actions/settings.ts (1)
apps/web/utils/actions/safe-action.ts (1)
actionClient(62-113)apps/web/utils/cold-email/is-cold-email.ts (1)
apps/web/utils/label-config.ts (1)
getOrCreateSystemLabelId(16-96)apps/web/utils/cold-email/is-cold-email.test.ts (1)
apps/web/utils/label-config.ts (1)
getOrCreateSystemLabelId(16-96)apps/web/utils/email/google.ts (3)
apps/web/utils/email/types.ts (1)
EmailLabel(12-23)apps/web/utils/email/microsoft.ts (1)
labelMessage(305-315)apps/web/utils/gmail/label.ts (1)
labelMessage(133-149)apps/web/utils/ai/actions.ts (1)
apps/web/app/api/outlook/webhook/logger.ts (1)
logger(3-3)apps/web/utils/reply-tracker/label-helpers.ts (3)
apps/web/utils/logger.ts (1)
createScopedLogger(17-80)apps/web/utils/email/types.ts (1)
EmailProvider(43-229)apps/web/utils/label-config.ts (1)
getOrCreateSystemLabelId(16-96)apps/web/utils/email/microsoft.ts (2)
apps/web/utils/email/types.ts (1)
EmailLabel(12-23)apps/web/utils/outlook/label.ts (1)
labelMessage(191-203)apps/web/utils/rule/rule.ts (3)
apps/web/utils/email/provider.ts (1)
createEmailProvider(13-29)apps/web/utils/email/types.ts (1)
EmailProvider(43-229)apps/web/utils/email/provider-types.ts (1)
isMicrosoftProvider(5-7)apps/web/utils/label-config.ts (3)
apps/web/utils/logger.ts (1)
createScopedLogger(17-80)apps/web/utils/email/types.ts (1)
EmailProvider(43-229)apps/web/utils/label.ts (1)
inboxZeroLabels(32-68)⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
🔇 Additional comments (15)
apps/web/utils/ai/assistant/chat.ts (1)
466-466: LGTM!The addition of
emailAccountIdto theupdateRuleActionscall correctly propagates the account context needed for label ID resolution in the updated rule management flow.apps/web/prisma/schema.prisma (2)
132-135: LGTM!The schema additions correctly introduce configurable system label fields to store stable, provider-agnostic label IDs. The inline comments clearly document that these store Gmail Label IDs or Outlook Category IDs.
432-432: LGTM!The addition of
labelIdfields to Action, ExecutedAction, and ScheduledAction models enables stable label ID storage across the action lifecycle, aligning with the provider-agnostic labeling architecture introduced in this PR.Also applies to: 510-510, 542-542
apps/web/utils/email/microsoft.ts (1)
305-314: LGTM!The updated
labelMessagesignature correctly shifts to ID-based labeling. The error handling when a category is not found is appropriate, and the implementation correctly uses the category name for the Outlook API call.apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx (1)
9-9: LGTM!The integration of
SystemLabelsSettingis straightforward and correctly positioned in the settings flow. The component self-manages its state without requiring props.Also applies to: 16-16
apps/web/utils/email/google.ts (1)
258-264: LGTM!The simplified
labelMessageimplementation correctly shifts to ID-based labeling. The removal of label creation/lookup logic is appropriate since label ID resolution now happens upstream in the rule creation flow.apps/web/utils/email/types.ts (1)
49-49: LGTM!The interface changes correctly formalize the shift to ID-based labeling:
getLabelByNameenables label lookup by name for ID resolutionlabelMessagenow acceptslabelIdinstead oflabelName, ensuring consistent ID-based labeling across providersBoth Gmail and Microsoft providers implement these updated signatures correctly.
Also applies to: 90-90
apps/web/utils/rule/rule.ts (2)
169-174: LGTM!The integration of
emailProviderthroughout the rule creation and update flow is correct:
createEmailProvideris called with the appropriate parametersmapActionFieldsis properly awaited since it's now asyncemailAccountIdis correctly added toupdateRuleActionssignature and used to create the providerAlso applies to: 232-232, 242-244, 273-273, 278-280, 286-288
379-419: I've verified that downstream helpers (e.g., reply-tracker, AI actions) guard against nulllabelIdby early returns, so logging a warning and continuing withlabelId: nullis safe. No unguarded use of a nulllabelIdwas found. The current error handling is sufficient; no changes required.No changes needed; downstream logic already skips null
labelIdgracefully.apps/web/prisma/migrations/20251005093547_label_id/migration.sql (1)
1-13: LGTM!The migration correctly adds the necessary TEXT columns to support stable label ID storage across Action, EmailAccount, ExecutedAction, and ScheduledAction models. The nullable columns with no defaults are appropriate for this additive schema change.
apps/web/utils/reply-tracker/label-helpers.ts (2)
1-5: LGTM! Proper logger initialization.The imports are correct and the logger is properly initialized at the top level using
createScopedLogger, which follows the coding guidelines.
7-26: LGTM! Proper error handling for label creation failure.The function correctly handles the case where the awaiting reply label cannot be retrieved or created by logging an error and returning early.
apps/web/utils/label-config.ts (3)
1-12: LGTM! Proper imports and logger initialization.The imports follow the coding guidelines (using path aliases with
@/, importing Prisma correctly) and the logger is properly initialized at the top level.
16-96: Well-structured label discovery with backward compatibility.The function properly handles the migration path: checks for existing ID → new numbered label → legacy label → creates new label. The error handling is appropriate with logging and returning null on failure.
182-195: LGTM! Proper error handling in getLabelDisplayName.The function correctly handles errors by logging and returning null, allowing graceful degradation when label names cannot be retrieved.
There was a problem hiding this comment.
5 issues found across 15 files
Prompt for AI agents (all 5 issues)
Understand the root cause of the following 5 issues and fix them.
<file name="apps/web/utils/actions/settings.ts">
<violation number="1" location="apps/web/utils/actions/settings.ts:229">
doneLabelId is accepted by this action but never persisted, so attempts to rename the Done system label will silently fail. Please include doneLabelId in the parsed input and update payload.</violation>
</file>
<file name="apps/web/utils/email/types.ts">
<violation number="1" location="apps/web/utils/email/types.ts:90">
Switching labelMessage to require a labelId breaks existing callers like the Microsoft provider, which still passes the label name; this will now throw when labelAwaitingReply runs. Please update the callers to supply an ID (or keep the interface accepting names).</violation>
</file>
<file name="apps/web/utils/email/google.ts">
<violation number="1" location="apps/web/utils/email/google.ts:151">
getLabelByName relies on getLabels(), which filters out hidden Gmail labels. When legacy actions only have a label name and that label is hidden, this lookup now returns null and the action exits without labeling the message—previously getOrCreateLabel still found hidden labels, so this is a functional regression.</violation>
</file>
<file name="apps/web/utils/reply-tracker/label-helpers.ts">
<violation number="1" location="apps/web/utils/reply-tracker/label-helpers.ts:114">
`markThreadAsDone` calls `provider.labelMessage` with a thread ID, but `labelMessage` expects a message ID. This will fail to apply the Done label because the provider implementation uses the value as a message identifier.</violation>
</file>
<file name="apps/web/utils/label-config.ts">
<violation number="1" location="apps/web/utils/label-config.ts:40">
Avoid referencing inboxZeroLabels.cold_email.nameLegacy if it’s not defined; pass a valid legacy name or fall back to the current name to prevent undefined lookups.</violation>
</file>
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
apps/web/utils/label-config.ts (1)
13-13: Consider exporting SystemLabelType for type safety.The
SystemLabelTypeis used in public function signatures but isn't exported. Exporting it would allow consuming code to strongly type thetypeparameter when calling these functions.Apply this diff to export the type:
-type SystemLabelType = "needsReply" | "awaitingReply" | "coldEmail"; +export type SystemLabelType = "needsReply" | "awaitingReply" | "coldEmail";
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/utils/actions/settings.ts(1 hunks)apps/web/utils/label-config.ts(1 hunks)apps/web/utils/reply-tracker/label-helpers.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/utils/actions/settings.ts
- apps/web/utils/reply-tracker/label-helpers.ts
🧰 Additional context used
📓 Path-based instructions (8)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/utils/label-config.ts
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/utils/label-config.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.ts: The same validation should be done in the server action too
Define validation schemas using Zod
Files:
apps/web/utils/label-config.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/utils/label-config.ts
apps/web/utils/**
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Create utility functions in
utils/folder for reusable logic
Files:
apps/web/utils/label-config.ts
apps/web/utils/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size
Files:
apps/web/utils/label-config.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/utils/label-config.ts
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/utils/label-config.ts
🧬 Code graph analysis (1)
apps/web/utils/label-config.ts (3)
apps/web/utils/logger.ts (1)
createScopedLogger(17-80)apps/web/utils/email/types.ts (1)
EmailProvider(43-229)apps/web/utils/label.ts (1)
inboxZeroLabels(32-68)
🔇 Additional comments (3)
apps/web/utils/label-config.ts (3)
1-11: LGTM!Imports and logger initialization follow the coding guidelines correctly. The scoped logger is properly initialized at the top of the file.
56-80: LGTM!The function correctly retrieves the system label ID from the database with appropriate null handling.
137-150: LGTM!The function correctly retrieves the label display name with appropriate error handling and null safety.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/components/LabelCombobox.tsx (1)
48-62: Consider using toastError/toastSuccess for consistency.While
toast.promisefrom sonner works correctly, the project's coding guidelines recommend using thetoastErrorandtoastSuccesswrappers for consistency with other parts of the codebase.Consider refactoring to:
- toast.promise( - async () => { - const res = await createLabelAction(emailAccountId, { - name: search, - }); - mutate(); - if (res?.serverError) throw new Error(res.serverError); - }, - { - loading: `Creating label "${search}"...`, - success: `Created label "${search}"`, - error: (errorMessage) => - `Error creating label "${search}": ${errorMessage}`, - }, - ); + const res = await createLabelAction(emailAccountId, { + name: search, + }); + if (res?.serverError) { + toastError({ description: res.serverError }); + } else { + toastSuccess({ description: `Created label "${search}"` }); + mutate(); + }As per coding guidelines
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx (1)
148-148: Consider more defensive handling of emailAccountId.While the LoadingContent wrapper ensures
emailAccountDataexists before rendering the form, the fallback to an empty string (?? "") could theoretically pass an invalid value tocreateLabelAction. Consider disabling the form or using a non-empty fallback.However, since the form is only rendered when data is loaded and no error occurred, the current implementation is functionally correct. This is a minor defensive programming consideration.
Also applies to: 166-166, 184-184
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx(3 hunks)apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx(1 hunks)apps/web/components/LabelCombobox.tsx(1 hunks)apps/web/utils/actions/settings.ts(2 hunks)apps/web/utils/actions/settings.validation.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/utils/actions/settings.ts
🧰 Additional context used
📓 Path-based instructions (21)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/utils/actions/settings.validation.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
apps/web/utils/actions/**/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/utils/actions/**/*.ts: Use server actions for all mutations (create/update/delete operations)
next-safe-actionprovides centralized error handling
Use Zod schemas for validation on both client and server
UserevalidatePathin server actions for cache invalidation
apps/web/utils/actions/**/*.ts: Use server actions (withnext-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
UserevalidatePathin server actions to invalidate cache after mutations.
Files:
apps/web/utils/actions/settings.validation.ts
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/utils/actions/settings.validation.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.ts: The same validation should be done in the server action too
Define validation schemas using Zod
Files:
apps/web/utils/actions/settings.validation.ts
apps/web/utils/actions/*.validation.ts
📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)
Define Zod schemas for validation in dedicated files and use them for both client and server validation.
Define input validation schemas using Zod in the corresponding
.validation.tsfile. These schemas are used bynext-safe-action(.schema()) and can also be reused on the client for form validation.
Files:
apps/web/utils/actions/settings.validation.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/utils/actions/settings.validation.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
apps/web/utils/actions/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server-actions.mdc)
apps/web/utils/actions/*.ts: Implement all server actions using thenext-safe-actionlibrary for type safety, input validation, context management, and error handling. Refer toapps/web/utils/actions/safe-action.tsfor client definitions (actionClient,actionClientUser,adminActionClient).
UseactionClientUserwhen only authenticated user context (userId) is needed.
UseactionClientwhen both authenticated user context and a specificemailAccountIdare needed. TheemailAccountIdmust be bound when calling the action from the client.
UseadminActionClientfor actions restricted to admin users.
Access necessary context (likeuserId,emailAccountId, etc.) provided by the safe action client via thectxobject in the.action()handler.
Server Actions are strictly for mutations (operations that change data, e.g., creating, updating, deleting). Do NOT use Server Actions for data fetching (GET operations). For data fetching, use dedicated GET API Routes combined with SWR Hooks.
UseSafeErrorfor expected/handled errors within actions if needed.next-safe-actionprovides centralized error handling.
Use the.metadata({ name: "actionName" })method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied viawithServerActionInstrumentationwithin the safe action clients.
If an action modifies data displayed elsewhere, userevalidatePathorrevalidateTagfromnext/cachewithin the action handler as needed.Server action files must start with
use server
Files:
apps/web/utils/actions/settings.validation.ts
apps/web/utils/**
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Create utility functions in
utils/folder for reusable logic
Files:
apps/web/utils/actions/settings.validation.ts
apps/web/utils/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size
Files:
apps/web/utils/actions/settings.validation.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/utils/actions/settings.validation.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/utils/actions/settings.validation.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
apps/web/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
apps/web/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
apps/web/app/(app)/*/**
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
apps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
apps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
apps/web/app/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirective
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
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 use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
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 ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsxapps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/Rules.tsxapps/web/components/LabelCombobox.tsxapps/web/components/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Use React Hook Form with Zod validation for form handling
Use the
LoadingContentcomponent to handle loading and error states consistently in data-fetching components.Use PascalCase for components (e.g.
components/Button.tsx)Files:
apps/web/components/LabelCombobox.tsx🧠 Learnings (4)
📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/utils/actions/*.validation.ts : Define Zod schemas for validation in dedicated files and use them for both client and server validation.Applied to files:
apps/web/utils/actions/settings.validation.ts📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/components/**/*Form.tsx : Use React Hook Form with Zod resolver for form handling and validation.Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:30.467Z
Learnt from: CR PR: elie222/inbox-zero#0 File: apps/web/CLAUDE.md:0-0 Timestamp: 2025-07-18T15:04:30.467Z Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form handlingApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:57.115Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/form-handling.mdc:0-0 Timestamp: 2025-07-18T15:04:57.115Z Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validationApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx🧬 Code graph analysis (3)
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx (1)
SystemLabelsSetting(33-55)apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx (8)
apps/web/components/SettingCard.tsx (1)
SettingCard(3-26)apps/web/hooks/useLabels.ts (1)
useLabels(62-88)apps/web/utils/actions/settings.validation.ts (2)
UpdateSystemLabelsBody(62-62)updateSystemLabelsBody(57-61)apps/web/utils/label.ts (1)
inboxZeroLabels(32-68)apps/web/utils/actions/settings.ts (1)
updateSystemLabelsAction(214-237)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-27)apps/web/components/Input.tsx (1)
Label(116-132)apps/web/components/LabelCombobox.tsx (1)
LabelCombobox(10-73)apps/web/components/LabelCombobox.tsx (2)
apps/web/components/Combobox.tsx (1)
Combobox(23-95)apps/web/utils/actions/mail.ts (1)
createLabelAction(138-153)🔇 Additional comments (15)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)
98-98: LGTM! Centralized LabelCombobox import.The import follows project conventions using the
@/path alias and enables code reuse across the application.
1150-1150: LGTM! Safe null handling for userLabels.The defensive programming pattern
userLabels || []ensures the LabelCombobox always receives a defined array, preventing potential runtime errors when userLabels is undefined during loading states.apps/web/components/LabelCombobox.tsx (3)
10-24: LGTM! Well-structured component props.The component follows React best practices with clear prop types and proper TypeScript integration using the EmailLabel type from the email provider.
27-27: LGTM! Correct label selection logic.The ID-based lookup correctly finds the selected label for display purposes.
31-34: LGTM! Safe options mapping.The mapping includes fallback empty strings for potentially undefined
idandnamefields, preventing runtime errors when label data is incomplete.apps/web/utils/actions/settings.validation.ts (1)
57-62: LGTM! Proper validation schema.The Zod schema follows project conventions by defining validation in a dedicated
.validation.tsfile with optional fields for the update operation. The type export enables type-safe usage in form components.Based on learnings
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx (1)
9-9: LGTM! Clean integration of new setting.The SystemLabelsSetting is properly imported and rendered following the same pattern as other settings in this tab.
Also applies to: 21-21
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx (6)
33-55: LGTM! Well-structured settings component.The component follows React best practices with clean state management and conditional rendering of the dialog content only when needed (performance optimization).
70-83: LGTM! Correct form setup with Zod validation.The react-hook-form setup with zodResolver follows project conventions and aligns with the coding guidelines for form handling.
Based on learnings
85-108: LGTM! Smart default value initialization.The useEffect correctly prioritizes saved label IDs from the email account data, falling back to finding labels by name. This provides a smooth user experience when labels exist but IDs haven't been saved yet.
110-123: LGTM! Proper error handling and success flow.The submit handler follows coding guidelines by checking
serverError, usingtoastError/toastSuccess, and properly refreshing data withmutate()on success.As per coding guidelines
130-133: LGTM! Proper loading state handling.The LoadingContent component is correctly used to handle loading and error states, following the project's coding guidelines.
As per coding guidelines
189-196: LGTM! Proper form submission controls.The submit button is correctly disabled when there are no changes (
!isDirty) or during submission, preventing unnecessary API calls and multiple submissions.apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (2)
150-171: LGTM:labelId: nullis appropriate for non-label actions.For ARCHIVE (line 157) and DIGEST (line 177) actions, setting
labelId: nullis correct since these action types don't involve label operations. The action object structure supports multiple action types with shared fields, so unused fields being null is expected.Also applies to: 172-191
130-148: No changes required:labelIdisn’t used for display.
getActionDisplayrelies on thelabelstring (notlabelId), so settinglabelId: nullon this synthetic, display-only rule has no impact.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
255-256: Replace console.error with scoped logger.Using
console.errorviolates the coding guidelines. UsecreateScopedLoggerfor consistent logging.As per coding guidelines, apply this pattern at the top of the file:
+"use client"; + +import { createScopedLogger } from "@/utils/logger"; + +const logger = createScopedLogger("RuleForm");Then replace console.error calls:
- console.error(res); + logger.error("Update rule failed", res);- console.error(res); + logger.error("Create rule failed", res);Also applies to: 286-287
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(3 hunks)apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx(1 hunks)apps/web/components/LabelCombobox.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/components/LabelCombobox.tsx
🧰 Additional context used
📓 Path-based instructions (14)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirective
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
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 use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
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 ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx🧠 Learnings (3)
📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/components/**/*Form.tsx : Use React Hook Form with Zod resolver for form handling and validation.Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:30.467Z
Learnt from: CR PR: elie222/inbox-zero#0 File: apps/web/CLAUDE.md:0-0 Timestamp: 2025-07-18T15:04:30.467Z Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form handlingApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:57.115Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/form-handling.mdc:0-0 Timestamp: 2025-07-18T15:04:57.115Z Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validationApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx (8)
apps/web/components/SettingCard.tsx (1)
SettingCard(3-26)apps/web/hooks/useLabels.ts (1)
useLabels(62-88)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-27)apps/web/utils/label.ts (1)
inboxZeroLabels(32-68)apps/web/utils/actions/settings.validation.ts (2)
UpdateSystemLabelsBody(62-62)updateSystemLabelsBody(57-61)apps/web/utils/actions/settings.ts (1)
updateSystemLabelsAction(214-237)apps/web/components/Input.tsx (1)
Label(116-132)apps/web/components/LabelCombobox.tsx (1)
LabelCombobox(10-85)🔇 Additional comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (3)
98-98: LGTM: External component import.The import of
LabelComboboxfrom an external component aligns with the PR's goal of supporting stable system label IDs.
1148-1162: LGTM: Defensive null check.Passing
userLabels || []ensures the externalLabelComboboxcomponent always receives a non-null array, preventing potential runtime errors.
1020-1020: No need to verifymutatesignature:mutateLabelsis never invoked in RuleForm.tsx.Likely an incorrect or invalid review comment.
apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
apps/web/utils/label-config.ts (2)
102-108: Wrap database updates in a transaction.The
emailAccountupdate (lines 102-105) andupdateAffectedRulescall (line 107) are executed separately. IfupdateAffectedRulesfails after the email account is updated, the system will be left in an inconsistent state.Apply this diff to wrap both operations in a transaction:
- await prisma.emailAccount.update({ - where: { id: emailAccountId }, - data: { [field]: labelId }, - }); - - await updateAffectedRules({ emailAccountId, type, labelId }); + await prisma.$transaction(async (tx) => { + await tx.emailAccount.update({ + where: { id: emailAccountId }, + data: { [field]: labelId }, + }); + + await updateAffectedRulesInTx({ tx, emailAccountId, type, labelId }); + });Then refactor
updateAffectedRulesto accept a transaction parameter.
132-139: Use batch update for better performance and atomicity.The nested loops update actions one-by-one, which is inefficient and can leave the system in a partially updated state if one update fails.
Apply this diff to use a single batch update:
- for (const rule of rules) { - for (const action of rule.actions) { - await prisma.action.update({ - where: { id: action.id }, - data: { labelId }, - }); - } - } + const allActionIds = rules.flatMap((rule) => + rule.actions.map((action) => action.id) + ); + + if (allActionIds.length > 0) { + await prisma.action.updateMany({ + where: { id: { in: allActionIds } }, + data: { labelId }, + }); + }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/web/utils/actions/settings.ts(2 hunks)apps/web/utils/ai/actions.ts(1 hunks)apps/web/utils/email/google.ts(5 hunks)apps/web/utils/email/microsoft.ts(3 hunks)apps/web/utils/gmail/label.ts(0 hunks)apps/web/utils/label-config.ts(1 hunks)
💤 Files with no reviewable changes (1)
- apps/web/utils/gmail/label.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/utils/ai/actions.ts
🧰 Additional context used
📓 Path-based instructions (10)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.ts: The same validation should be done in the server action too
Define validation schemas using Zod
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
apps/web/utils/**
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Create utility functions in
utils/folder for reusable logic
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
apps/web/utils/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/email/google.tsapps/web/utils/actions/settings.tsapps/web/utils/label-config.ts
apps/web/utils/actions/**/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/utils/actions/**/*.ts: Use server actions for all mutations (create/update/delete operations)
next-safe-actionprovides centralized error handling
Use Zod schemas for validation on both client and server
UserevalidatePathin server actions for cache invalidation
apps/web/utils/actions/**/*.ts: Use server actions (withnext-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
UserevalidatePathin server actions to invalidate cache after mutations.
Files:
apps/web/utils/actions/settings.ts
apps/web/utils/actions/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server-actions.mdc)
apps/web/utils/actions/*.ts: Implement all server actions using thenext-safe-actionlibrary for type safety, input validation, context management, and error handling. Refer toapps/web/utils/actions/safe-action.tsfor client definitions (actionClient,actionClientUser,adminActionClient).
UseactionClientUserwhen only authenticated user context (userId) is needed.
UseactionClientwhen both authenticated user context and a specificemailAccountIdare needed. TheemailAccountIdmust be bound when calling the action from the client.
UseadminActionClientfor actions restricted to admin users.
Access necessary context (likeuserId,emailAccountId, etc.) provided by the safe action client via thectxobject in the.action()handler.
Server Actions are strictly for mutations (operations that change data, e.g., creating, updating, deleting). Do NOT use Server Actions for data fetching (GET operations). For data fetching, use dedicated GET API Routes combined with SWR Hooks.
UseSafeErrorfor expected/handled errors within actions if needed.next-safe-actionprovides centralized error handling.
Use the.metadata({ name: "actionName" })method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied viawithServerActionInstrumentationwithin the safe action clients.
If an action modifies data displayed elsewhere, userevalidatePathorrevalidateTagfromnext/cachewithin the action handler as needed.Server action files must start with
use server
Files:
apps/web/utils/actions/settings.ts
🧠 Learnings (1)
📚 Learning: 2025-07-18T15:05:34.899Z
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.899Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')
Applied to files:
apps/web/utils/email/google.ts
🧬 Code graph analysis (4)
apps/web/utils/email/microsoft.ts (3)
apps/web/utils/email/types.ts (1)
EmailLabel(12-23)apps/web/utils/outlook/label.ts (2)
getLabel(127-140)labelMessage(191-203)apps/web/utils/email/google.ts (1)
labelMessage(260-272)
apps/web/utils/email/google.ts (3)
apps/web/utils/email/types.ts (1)
EmailLabel(12-23)apps/web/utils/gmail/label.ts (2)
getLabel(233-245)labelMessage(133-149)apps/web/utils/email/microsoft.ts (1)
labelMessage(305-321)
apps/web/utils/actions/settings.ts (2)
apps/web/utils/actions/safe-action.ts (1)
actionClient(62-113)apps/web/utils/actions/settings.validation.ts (1)
updateSystemLabelsBody(57-61)
apps/web/utils/label-config.ts (3)
apps/web/utils/logger.ts (1)
createScopedLogger(17-80)apps/web/utils/email/types.ts (1)
EmailProvider(43-224)apps/web/utils/label.ts (1)
inboxZeroLabels(32-68)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Secret Detection
🔇 Additional comments (4)
apps/web/utils/email/google.ts (2)
144-155: LGTM!The
getLabelByNamemethod correctly delegates to the internalgetLabelhelper and transforms the result to theEmailLabelinterface. The null-check and early return are appropriate.
260-272: LGTM!The updated
labelMessagesignature now accepts an object withmessageIdandlabelId, which aligns with the broader refactor to use stable label IDs. The implementation correctly passes thelabelIdto the underlyinglabelMessagehelper.apps/web/utils/email/microsoft.ts (2)
125-133: LGTM!The
getLabelByNamemethod correctly delegates to the internalgetLabelhelper and transforms the result to theEmailLabelinterface. The implementation mirrors the Google provider and is consistent.
305-321: LGTM!The updated
labelMessagesignature now accepts an object withmessageIdandlabelId. The implementation correctly looks up the label by ID first, throws an appropriate error if not found, and uses the label name for Outlook's category-based labeling. This aligns with the broader refactor to use stable label IDs.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/utils/actions/rule.ts (1)
144-188: Make label resolution best-effort inside server actions
createRuleAction,updateRuleAction, andresolveActionLabelsnow always callcreateEmailProvider, even when the submitted actions contain zeroLABELs. If that provider bootstrap fails (common with expired tokens or temporary API issues) we’ll reject an otherwise-valid rule mutation, which is a regression. Please only spin up the provider when at least one action needs label resolution, and treat failures as a warning so we fall back to storing the label name like before. You can reuse the lazyshouldResolveLabels/try-catch pattern fromrule.ts, and letresolveActionLabelsaccept a nullable provider so the mutation remains resilient.- const resolvedActions = await resolveActionLabels( - actions || [], - emailAccountId, - provider, - ); + const resolvedActions = await resolveActionLabels( + actions || [], + emailAccountId, + provider, + logger, + ); @@ - const resolvedActions = await resolveActionLabels( - actions, - emailAccountId, - provider, - ); + const resolvedActions = await resolveActionLabels( + actions, + emailAccountId, + provider, + logger, + ); @@ -async function resolveActionLabels< +async function resolveActionLabels< T extends { type: ActionType; labelId?: { name?: string | null; value?: string | null; ai?: boolean | null; } | null; }, ->(actions: T[], emailAccountId: string, provider: string) { - const emailProvider = await createEmailProvider({ - emailAccountId, - provider, - }); +>( + actions: T[], + emailAccountId: string, + provider: string, + logger: ReturnType<typeof createScopedLogger>, +) { + const shouldResolveLabels = actions.some( + (action) => action.type === ActionType.LABEL, + ); + const emailProvider = shouldResolveLabels + ? await createEmailProvider({ emailAccountId, provider }).catch((error) => { + logger.warn("Unable to resolve label IDs; keeping existing names", { + emailAccountId, + provider, + error, + }); + return null; + }) + : null; return Promise.all( actions.map(async (action) => { - if (action.type === ActionType.LABEL) { + if (action.type === ActionType.LABEL && emailProvider) { const { label: resolvedLabel, labelId: resolvedLabelId } = await resolveLabelNameAndId({ emailProvider, label: action.labelId?.name || null, labelId: action.labelId?.value || null, }); return { ...action, labelId: { value: resolvedLabelId, name: resolvedLabel, ai: action.labelId?.ai, }, }; } return action; }), ); }Also applies to: 248-347, 821-846
♻️ Duplicate comments (2)
apps/web/utils/actions/settings.ts (1)
244-271: Wrap the label updates in a single transaction.
emailAccount.updateruns beforeaction.updateMany. If the second call throws (e.g., transient DB error), the account will point at the new label ID while actions stay on the old ID, leaving Reply Tracker in an inconsistent configuration. Run both statements inside the sameprisma.$transactionand use the scopedtxclient so they either succeed together or roll back.- await prisma.emailAccount.update({ - where: { id: emailAccountId }, - data: { - needsReplyLabelId: needsReplyLabelId ?? null, - awaitingReplyLabelId: awaitingReplyLabelId ?? null, - coldEmailLabelId: coldEmailLabelId ?? null, - }, - }); - - // Update all LABEL actions that match the old needs reply label - if (needsReplyLabelId) { - await prisma.action.updateMany({ - where: { - rule: { emailAccountId }, - type: ActionType.LABEL, - OR: [ - ...(oldConfig?.needsReplyLabelId - ? [{ labelId: oldConfig.needsReplyLabelId }] - : []), - { label: NEEDS_REPLY_LABEL_NAME }, - ], - }, - data: { - labelId: needsReplyLabelId, - label: null, // Clear the label name since we're using labelId now - }, - }); - } + await prisma.$transaction(async (tx) => { + await tx.emailAccount.update({ + where: { id: emailAccountId }, + data: { + needsReplyLabelId: needsReplyLabelId ?? null, + awaitingReplyLabelId: awaitingReplyLabelId ?? null, + coldEmailLabelId: coldEmailLabelId ?? null, + }, + }); + + if (needsReplyLabelId) { + await tx.action.updateMany({ + where: { + rule: { emailAccountId }, + type: ActionType.LABEL, + OR: [ + ...(oldConfig?.needsReplyLabelId + ? [{ labelId: oldConfig.needsReplyLabelId }] + : []), + { label: NEEDS_REPLY_LABEL_NAME }, + ], + }, + data: { + labelId: needsReplyLabelId, + label: null, + }, + }); + } + });apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
993-1001: Still need to allowuserLabelsto be undefined.
useLabels()can yieldundefined, and the render path guards withuserLabels || [], so the prop type should allowundefinedinstead of forcing a non-null array. Please adjust the prop toEmailLabel[] | undefined(or make it optional) so the types reflect reality and we don’t have to rely on runtime fallbacks.
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
1124-1136: Re-run validation when the combobox changes.
setValuedefaults toshouldValidate: false, so any existing error forlabelIdwill linger after a user picks a label until the next submit. Pass{ shouldValidate: true, shouldDirty: true }so the UI clears errors immediately and keeps form state in sync.- onChangeValue={(newValue: string) => { - setValue( - `actions.${index}.${field.name}.value`, - newValue, - ); - }} + onChangeValue={(newValue: string) => { + setValue( + `actions.${index}.${field.name}.value`, + newValue, + { shouldValidate: true, shouldDirty: true }, + ); + }}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsx(3 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(9 hunks)apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx(8 hunks)apps/web/app/(app)/[emailAccountId]/settings/LabelsSection.tsx(0 hunks)apps/web/app/(landing)/components/page.tsx(1 hunks)apps/web/app/api/user/rules/[id]/route.ts(1 hunks)apps/web/prisma/schema.prisma(4 hunks)apps/web/utils/action-display.tsx(2 hunks)apps/web/utils/action-item.ts(5 hunks)apps/web/utils/actions/rule.ts(11 hunks)apps/web/utils/actions/rule.validation.ts(2 hunks)apps/web/utils/actions/settings.ts(3 hunks)apps/web/utils/label/resolve-label.ts(1 hunks)apps/web/utils/reply-tracker/enable.ts(5 hunks)apps/web/utils/rule/rule.ts(8 hunks)
💤 Files with no reviewable changes (1)
- apps/web/app/(app)/[emailAccountId]/settings/LabelsSection.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
- apps/web/prisma/schema.prisma
🧰 Additional context used
📓 Path-based instructions (23)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/utils/label/resolve-label.tsapps/web/app/(landing)/components/page.tsxapps/web/utils/rule/rule.tsapps/web/app/api/user/rules/[id]/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/action-display.tsxapps/web/utils/actions/rule.validation.ts
apps/web/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(landing)/components/page.tsxapps/web/app/api/user/rules/[id]/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/action-display.tsx
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/utils/label/resolve-label.tsapps/web/app/(landing)/components/page.tsxapps/web/utils/rule/rule.tsapps/web/app/api/user/rules/[id]/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/action-display.tsxapps/web/utils/actions/rule.validation.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/action-display.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/utils/label/resolve-label.tsapps/web/app/(landing)/components/page.tsxapps/web/utils/rule/rule.tsapps/web/app/api/user/rules/[id]/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/action-display.tsxapps/web/utils/actions/rule.validation.ts
apps/web/app/(app)/*/**
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirective
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/utils/label/resolve-label.tsapps/web/app/(landing)/components/page.tsxapps/web/utils/rule/rule.tsapps/web/app/api/user/rules/[id]/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/action-display.tsxapps/web/utils/actions/rule.validation.ts
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/utils/label/resolve-label.tsapps/web/app/(landing)/components/page.tsxapps/web/utils/rule/rule.tsapps/web/app/api/user/rules/[id]/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/action-display.tsxapps/web/utils/actions/rule.validation.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
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 use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/action-display.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
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 ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsxapps/web/app/(landing)/components/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/utils/action-display.tsx**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.ts: The same validation should be done in the server action too
Define validation schemas using ZodFiles:
apps/web/utils/label/resolve-label.tsapps/web/utils/rule/rule.tsapps/web/app/api/user/rules/[id]/route.tsapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/**
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Create utility functions in
utils/folder for reusable logicFiles:
apps/web/utils/label/resolve-label.tsapps/web/utils/rule/rule.tsapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/action-display.tsxapps/web/utils/actions/rule.validation.tsapps/web/utils/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle sizeFiles:
apps/web/utils/label/resolve-label.tsapps/web/utils/rule/rule.tsapps/web/utils/actions/rule.tsapps/web/utils/action-item.tsapps/web/utils/reply-tracker/enable.tsapps/web/utils/actions/settings.tsapps/web/utils/actions/rule.validation.tsapps/web/app/api/**/route.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/app/api/**/route.ts: UsewithAuthfor user-level operations
UsewithEmailAccountfor email-account-level operations
Do NOT use POST API routes for mutations - use server actions instead
No need for try/catch in GET routes when using middleware
Export response types from GET routes
apps/web/app/api/**/route.ts: Wrap all GET API route handlers withwithAuthorwithEmailAccountmiddleware for authentication and authorization.
Export response types from GET API routes for type-safe client usage.
Do not use try/catch in GET API routes when using authentication middleware; rely on centralized error handling.Files:
apps/web/app/api/user/rules/[id]/route.ts**/api/**/route.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/api/**/route.ts: ALL API routes that handle user data MUST use appropriate authentication and authorization middleware (withAuth or withEmailAccount).
ALL database queries in API routes MUST be scoped to the authenticated user/account (e.g., include userId or emailAccountId in query filters).
Always validate that resources belong to the authenticated user before performing operations (resource ownership validation).
UsewithEmailAccountmiddleware for API routes that operate on a specific email account (i.e., use or requireemailAccountId).
UsewithAuthmiddleware for API routes that operate at the user level (i.e., use or require onlyuserId).
UsewithErrormiddleware (with proper validation) for public endpoints, custom authentication, or cron endpoints.
Cron endpoints MUST usewithErrormiddleware and validate the cron secret usinghasCronSecret(request)orhasPostCronSecret(request).
Cron endpoints MUST capture unauthorized attempts withcaptureExceptionand return a 401 status for unauthorized requests.
All parameters in API routes MUST be validated for type, format, and length before use.
Request bodies in API routes MUST be validated using Zod schemas before use.
All Prisma queries in API routes MUST only return necessary fields and never expose sensitive data.
Error messages in API routes MUST not leak internal information or sensitive data; use generic error messages and SafeError where appropriate.
API routes MUST use a consistent error response format, returning JSON with an error message and status code.
AllfindUniqueandfindFirstPrisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
AllfindManyPrisma calls in API routes MUST be scoped to the authenticated user's data.
Never use direct object references in API routes without ownership checks (prevent IDOR vulnerabilities).
Prevent mass assignment vulnerabilities by only allowing explicitly whitelisted fields in update operations in AP...Files:
apps/web/app/api/user/rules/[id]/route.tsapps/web/app/api/**/*.{ts,js}
📄 CodeRabbit inference engine (.cursor/rules/security-audit.mdc)
apps/web/app/api/**/*.{ts,js}: All API route handlers in 'apps/web/app/api/' must use authentication middleware: withAuth, withEmailAccount, or withError (with custom authentication logic).
All Prisma queries in API routes must include user/account filtering (e.g., emailAccountId or userId in WHERE clauses) to prevent unauthorized data access.
All parameters used in API routes must be validated before use; do not use parameters from 'params' or request bodies directly in queries without validation.
Request bodies in API routes should use Zod schemas for validation.
API routes should only return necessary fields using Prisma's 'select' and must not include sensitive data in error messages.
Error messages in API routes must not reveal internal details; use generic errors and SafeError for user-facing errors.
All QStash endpoints (API routes called via publishToQstash or publishToQstashQueue) must use verifySignatureAppRouter to verify request authenticity.
All cron endpoints in API routes must use hasCronSecret or hasPostCronSecret for authentication.
Do not hardcode weak or plaintext secrets in API route files; secrets must not be directly assigned as string literals.
Review all new withError usage in API routes to ensure custom authentication is implemented where required.Files:
apps/web/app/api/user/rules/[id]/route.tsapps/web/utils/actions/**/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/utils/actions/**/*.ts: Use server actions for all mutations (create/update/delete operations)
next-safe-actionprovides centralized error handling
Use Zod schemas for validation on both client and server
UserevalidatePathin server actions for cache invalidation
apps/web/utils/actions/**/*.ts: Use server actions (withnext-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
UserevalidatePathin server actions to invalidate cache after mutations.Files:
apps/web/utils/actions/rule.tsapps/web/utils/actions/settings.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server-actions.mdc)
apps/web/utils/actions/*.ts: Implement all server actions using thenext-safe-actionlibrary for type safety, input validation, context management, and error handling. Refer toapps/web/utils/actions/safe-action.tsfor client definitions (actionClient,actionClientUser,adminActionClient).
UseactionClientUserwhen only authenticated user context (userId) is needed.
UseactionClientwhen both authenticated user context and a specificemailAccountIdare needed. TheemailAccountIdmust be bound when calling the action from the client.
UseadminActionClientfor actions restricted to admin users.
Access necessary context (likeuserId,emailAccountId, etc.) provided by the safe action client via thectxobject in the.action()handler.
Server Actions are strictly for mutations (operations that change data, e.g., creating, updating, deleting). Do NOT use Server Actions for data fetching (GET operations). For data fetching, use dedicated GET API Routes combined with SWR Hooks.
UseSafeErrorfor expected/handled errors within actions if needed.next-safe-actionprovides centralized error handling.
Use the.metadata({ name: "actionName" })method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied viawithServerActionInstrumentationwithin the safe action clients.
If an action modifies data displayed elsewhere, userevalidatePathorrevalidateTagfromnext/cachewithin the action handler as needed.Server action files must start with
use serverFiles:
apps/web/utils/actions/rule.tsapps/web/utils/actions/settings.tsapps/web/utils/actions/rule.validation.tsapps/web/utils/actions/*.validation.ts
📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)
Define Zod schemas for validation in dedicated files and use them for both client and server validation.
Define input validation schemas using Zod in the corresponding
.validation.tsfile. These schemas are used bynext-safe-action(.schema()) and can also be reused on the client for form validation.Files:
apps/web/utils/actions/rule.validation.ts🧠 Learnings (6)
📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/components/**/*Form.tsx : Use React Hook Form with Zod resolver for form handling and validation.Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:30.467Z
Learnt from: CR PR: elie222/inbox-zero#0 File: apps/web/CLAUDE.md:0-0 Timestamp: 2025-07-18T15:04:30.467Z Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form handlingApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:57.115Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/form-handling.mdc:0-0 Timestamp: 2025-07-18T15:04:57.115Z Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validationApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/utils/actions/*.validation.ts : Define Zod schemas for validation in dedicated files and use them for both client and server validation.Applied to files:
apps/web/utils/actions/rule.validation.ts📚 Learning: 2025-07-18T15:04:30.467Z
Learnt from: CR PR: elie222/inbox-zero#0 File: apps/web/CLAUDE.md:0-0 Timestamp: 2025-07-18T15:04:30.467Z Learning: Applies to apps/web/utils/actions/**/*.ts : Use Zod schemas for validation on both client and serverApplied to files:
apps/web/utils/actions/rule.validation.ts📚 Learning: 2025-07-18T17:27:58.249Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/server-actions.mdc:0-0 Timestamp: 2025-07-18T17:27:58.249Z Learning: Applies to apps/web/utils/actions/*.validation.ts : Define input validation schemas using Zod in the corresponding `.validation.ts` file. These schemas are used by `next-safe-action` (`.schema()`) and can also be reused on the client for form validation.Applied to files:
apps/web/utils/actions/rule.validation.ts🧬 Code graph analysis (7)
apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsx (2)
apps/web/hooks/useLabels.ts (1)
useLabels(62-88)apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (1)
ActionBadges(476-514)apps/web/utils/rule/rule.ts (5)
apps/web/utils/ai/rule/create-rule-schema.ts (1)
CreateOrUpdateRuleSchemaWithCategories(163-166)apps/web/utils/email/provider.ts (1)
createEmailProvider(13-29)apps/web/utils/email/types.ts (1)
EmailProvider(43-224)apps/web/utils/label/resolve-label.ts (1)
resolveLabelNameAndId(10-52)apps/web/utils/email/provider-types.ts (1)
isMicrosoftProvider(5-7)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
apps/web/components/LabelCombobox.tsx (1)
LabelCombobox(10-85)apps/web/utils/actions/rule.ts (2)
apps/web/utils/email/provider.ts (1)
createEmailProvider(13-29)apps/web/utils/label/resolve-label.ts (1)
resolveLabelNameAndId(10-52)apps/web/utils/reply-tracker/enable.ts (2)
apps/web/utils/email/provider.ts (1)
createEmailProvider(13-29)apps/web/utils/label/resolve-label.ts (1)
resolveLabelNameAndId(10-52)apps/web/utils/actions/settings.ts (2)
apps/web/utils/actions/safe-action.ts (1)
actionClient(62-113)apps/web/utils/actions/settings.validation.ts (1)
updateSystemLabelsBody(57-61)apps/web/utils/action-display.tsx (1)
apps/web/utils/string.ts (1)
truncate(1-3)
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx(3 hunks)apps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
apps/web/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
apps/web/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
apps/web/app/(app)/*/**
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
apps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
apps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
apps/web/app/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirective
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
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 use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
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 ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsxapps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsxapps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx🧬 Code graph analysis (4)
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsx (1)
apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx (1)
ProcessResultDisplay(13-60)apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx (1)
apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx (1)
ProcessResultDisplay(13-60)apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx (4)
apps/web/components/HoverCard.tsx (1)
HoverCard(7-20)apps/web/utils/ai/choose-rule/run-rules.ts (1)
RunRulesResult(35-41)apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx (1)
useRuleDialog(27-42)apps/web/utils/condition.ts (1)
isAIRule(33-37)apps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx (1)
apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx (1)
ProcessResultDisplay(13-60)🔇 Additional comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsx (2)
222-222: LGTM! ProcessResultDisplay call correctly updated.The removal of the
emailAccountIdprop aligns with the refactoredProcessResultDisplaycomponent signature, which now only requiresresultand an optionalprefix.
36-36: Ensure EmailAccountProvider wraps this route
useRules() → useSWRWithEmailAccount → useAccount() requires EmailAccountProvider to supply emailAccountId; confirm EmailAccountProvider encloses this component in your root or parent layout.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx (2)
134-137: Critical inconsistency: LABEL action not updated to new format.This LABEL action still uses the old format
content: { value: "Pitch" }while the other two LABEL actions in this file (lines 52 and 71) have been updated to uselabelId: { name: ... }. This inconsistency will likely cause runtime errors or incorrect behavior if the old format is no longer supported.Apply this diff to fix the inconsistency:
actions: [ { type: ActionType.LABEL, - content: { value: "Pitch" }, + labelId: { name: "Pitch" }, }, ],
1-142: Fix LABEL action definitions to uselabelId
- In
apps/web/app/(app)/[emailAccountId]/assistant/rule/create/page.tsx, replace
label: { value: searchParams.label }
with
labelId: { value: searchParams.label }.- In
apps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx, replace
content: { value: "Pitch" }
with
labelId: { value: "Pitch" }.
🧹 Nitpick comments (5)
apps/web/components/LabelCombobox.tsx (2)
36-41: Avoid empty-string option values; require stable id/name.Empty values can cause duplicate keys and selection glitches. Filter to labels with both id and name (IDs should now be stable).
Apply:
- options={userLabels.map((label) => ({ - value: label.id || "", - label: label.name || "", - }))} + options={userLabels + .filter((l) => !!l.id && !!l.name) + .map((label) => ({ + value: label.id!, + label: label.name!, + }))}
76-78: Safer error text in toast.promise.Ensure readable message for Error/unknown types.
Use:
- error: (errorMessage) => - `Error creating label "${searchValue}": ${errorMessage}`, + error: (e) => + `Error creating label "${searchValue}": ${ + (e && (e.message || e.toString?.())) || "Unknown error" + }`,apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (3)
846-846: Guard labels prop for summary to avoid undefined.If userLabels can be undefined during load, pass a safe default.
- provider={provider} - labels={userLabels} + provider={provider} + labels={userLabels || []}
991-999: Loosen userLabels prop type to reflect optional data.ActionCard accepts userLabels but later uses userLabels || []. Either ensure non-null at call sites or widen the type here.
- userLabels: EmailLabel[]; + userLabels?: EmailLabel[]; // or: EmailLabel[] | undefinedAs per coding guidelines (strict null checks).
239-241: Remove console.error in UI code.Console usage is disallowed; you already show toasts. Drop logs or capture via analytics if needed.
As per coding guidelines.
Also applies to: 270-272
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(10 hunks)apps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/group/Groups.tsx(0 hunks)apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx(1 hunks)apps/web/components/GroupedTable.tsx(1 hunks)apps/web/components/LabelCombobox.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/web/app/(app)/[emailAccountId]/assistant/group/Groups.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
🧰 Additional context used
📓 Path-based instructions (15)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
apps/web/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
apps/web/components/**/*.tsx
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Use React Hook Form with Zod validation for form handling
Use the
LoadingContentcomponent to handle loading and error states consistently in data-fetching components.Use PascalCase for components (e.g.
components/Button.tsx)
Files:
apps/web/components/GroupedTable.tsxapps/web/components/LabelCombobox.tsx
!{.cursor/rules/*.mdc}
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
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 use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
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 ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/components/GroupedTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/components/LabelCombobox.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsxapps/web/app/**
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsxapps/web/app/(app)/*/**
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsxapps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsxapps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsxapps/web/app/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirectiveFiles:
apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsxapps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsxapps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx🧠 Learnings (3)
📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/components/**/*Form.tsx : Use React Hook Form with Zod resolver for form handling and validation.Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:30.467Z
Learnt from: CR PR: elie222/inbox-zero#0 File: apps/web/CLAUDE.md:0-0 Timestamp: 2025-07-18T15:04:30.467Z Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form handlingApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx📚 Learning: 2025-07-18T15:04:57.115Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/form-handling.mdc:0-0 Timestamp: 2025-07-18T15:04:57.115Z Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validationApplied to files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx🧬 Code graph analysis (3)
apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx (1)
apps/web/utils/actions/rule.validation.ts (1)
CreateRuleBody(160-160)apps/web/components/LabelCombobox.tsx (2)
apps/web/components/Combobox.tsx (1)
Combobox(23-95)apps/web/utils/actions/mail.ts (1)
createLabelAction(138-153)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
apps/web/components/LabelCombobox.tsx (1)
LabelCombobox(10-90)⏰ 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: Static Code Analysis Js
- GitHub Check: Jit Security
🔇 Additional comments (9)
apps/web/components/GroupedTable.tsx (1)
437-437: LGTM! Routing refactor aligns with first file.The change from query-based to RESTful routing is correct and consistent with the update in
apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx. Thetarget="_blank"behavior is preserved.apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx (2)
11-11: LGTM! Prop addition follows best practices.The addition of the
labelsprop enables proper label ID-to-name resolution. The import and prop typing are correct and follow TypeScript conventions.Also applies to: 17-17, 22-22
43-54: Extraction to shared utility not applicable:resolveLabelNameAndIdis an async email‐provider lookup, whereas this UI code uses a synchronous in-memorylabelsarray—combining them would introduce unnecessary async behavior.Likely an incorrect or invalid review comment.
apps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx (2)
50-52: LGTM! Updated to use the new labelId format.The LABEL action now correctly uses
labelId: { name: "Newsletter" }instead of the deprecatedlabel: { value: "Newsletter" }format, aligning with the PR's goal of introducing stable system-label IDs.
71-71: LGTM! Correctly uses the new labelId format.This LABEL action properly uses
labelId: { name: "High Priority" }, consistent with the updated format introduced in this PR.apps/web/components/LabelCombobox.tsx (1)
55-63: Good fix: mutate only after success.Creation result is checked before mutate(); flow is correct and consistent.
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (3)
1028-1031: Correct: gate labelId variables behind AI toggle.Good constraint; prevents invalid templating for manual label selection.
Also applies to: 1059-1061
1121-1139: LabelCombobox integration looks correct.Passes stable id, preserves name for placeholder, updates only value on select, and refreshes via mutate.
995-995: Prop type for mutate updated to Promise-returning.Matches LabelCombobox usage; good.
Summary by CodeRabbit
New Features
Refactor
Database
Tests
Chores