Skip to content

Allow renaming system fields#832

Merged
elie222 merged 17 commits intomainfrom
feat/rename-system-labels
Oct 5, 2025
Merged

Allow renaming system fields#832
elie222 merged 17 commits intomainfrom
feat/rename-system-labels

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Oct 5, 2025

Summary by CodeRabbit

  • New Features

    • System Labels settings UI to configure Needs Reply, Awaiting Reply, and Cold Email labels (dialog, comboboxes, create-label flow, toasts).
    • Reusable LabelCombobox for selecting/creating labels.
  • Refactor

    • Unified labeling to use stable system label IDs across providers, rules, actions, and UI; rule payloads and action displays now prefer labelId.
    • Centralized label utilities and reply-tracker helpers; lazy migration and label-resolution flows added.
  • Database

    • Migration adds nullable label ID fields to account and action tables.
  • Tests

    • Updated tests to validate ID-based labeling.
  • Chores

    • Version bumped to v2.14.0; removed legacy Labels and Groups UI.

@vercel
Copy link

vercel bot commented Oct 5, 2025

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

Project Deployment Preview Updated (UTC)
inbox-zero Ready Ready Preview Oct 5, 2025 8:34pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 5, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

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

Walkthrough

Adds 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

Cohort / File(s) Summary
Settings UI
apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx, apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
Add and render SystemLabelsSetting component to configure needsReply/awaitingReply/coldEmail label IDs (dialog + form) and persist via new action.
DB Schema & Migration
apps/web/prisma/schema.prisma, apps/web/prisma/migrations/.../migration.sql
Add nullable needsReplyLabelId, awaitingReplyLabelId, coldEmailLabelId to EmailAccount; add labelId TEXT columns to Action, ExecutedAction, ScheduledAction in migration.
Settings Action & Validation
apps/web/utils/actions/settings.ts, apps/web/utils/actions/settings.validation.ts
New updateSystemLabelsAction and Zod schema updateSystemLabelsBody to update email account label IDs and synchronize affected LABEL actions.
Label Config & Sync
apps/web/utils/label-config.ts
New centralized helpers: getOrCreateSystemLabelId, getSystemLabelId, updateSystemLabelId, updateAffectedRules to resolve/create labels via provider and persist/sync rule actions.
Email Provider API & Implementations
apps/web/utils/email/types.ts, apps/web/utils/email/google.ts, apps/web/utils/email/microsoft.ts
Add getLabelByName; change labelMessage to accept { messageId, labelId }; provider implementations updated; legacy reply-label helper methods removed.
Label Combobox Component
apps/web/components/LabelCombobox.tsx
New LabelCombobox: searchable selector for user labels, supports creating labels via createLabelAction with toast feedback and post-create mutate.
Rule Mapping & Persistence
apps/web/utils/rule/rule.ts, apps/web/utils/actions/rule.ts, apps/web/utils/actions/rule.validation.ts
Make mapping async, inject EmailProvider, resolve label name↔id (resolveLabelNameAndId), persist labelId alongside label name in create/update flows; validation switched to labelId.
Label Resolution Utility
apps/web/utils/label/resolve-label.ts
New resolveLabelNameAndId helper to normalize label name/id using provider lookups.
AI Actions & Assistant
apps/web/utils/ai/actions.ts, apps/web/utils/ai/assistant/chat.ts
LABEL action accepts optional labelId and lazily migrates from name via provider lookup; assistant now includes emailAccountId when updating rule actions.
Rule Form / Rules UI
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx, apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx, apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsx
Replace internal label UI with shared LabelCombobox, switch action label fields to labelId, pass userLabels/labels to action displays, and add labelId: null to generated cold-email actions.
Action Display & Contracts
apps/web/utils/action-display.tsx, apps/web/utils/action-item.ts, apps/web/app/api/user/rules/[id]/route.ts, apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
Move label surface to labelId with name fallback; adapt sanitization, API payload shaping, and display helpers to prefer labelId and accept a labels array.
Reply-Tracker & Cold-Email
apps/web/utils/reply-tracker/*.ts, apps/web/utils/cold-email/is-cold-email.ts, apps/web/utils/cold-email/is-cold-email.test.ts
Use getOrCreateSystemLabelId and new reply-tracker label-helpers for applying/removing system labels; tests updated to mock getOrCreateSystemLabelId.
Provider Mocks & Call-sites
apps/web/utils/__mocks__/email-provider.ts, apps/web/utils/assistant/process-assistant-email.ts, apps/web/utils/reply-tracker/*
Update mock surface (getLabelByName, getSignatures added; legacy helpers removed); update call sites to accept { messageId, labelId } and use new helper functions.
Removed / Replaced UI
apps/web/app/(app)/[emailAccountId]/settings/LabelsSection.tsx, apps/web/app/(app)/[emailAccountId]/assistant/group/Groups.tsx
Remove legacy LabelsSection and Groups UI modules; label management moved to new flows/components.
Prop & Signature Adjustments
apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx, apps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx, apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsx, apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx, apps/web/app/(landing)/components/page.tsx, apps/web/utils/action-display.tsx
Remove some emailAccountId prop threading, add labels prop in usages, adjust component signatures and example usages; bump version.txt v2.13.9 → v2.14.0.

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 }
Loading
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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • edulelis

Poem

"I hop through code with whiskers bright,
I stitch new IDs by moonlit night.
Labels now nest where names once lay,
Rules hum softly — carrots for the day. 🥕🐇"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title refers to enabling renaming of system fields, which partially reflects the introduction of a SystemLabelsSetting feature for renaming system labels but uses “fields” instead of “labels” and is somewhat broad; nonetheless, it relates to the main change of allowing customization of these system values, so it meets the criteria for a pass.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9d902c and 618da80.

📒 Files selected for processing (1)
  • apps/web/utils/cold-email/is-cold-email.test.ts (9 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
apps/web/utils/email/microsoft.ts (1)

130-133: LGTM!

The getLabelByName helper 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 getLabelByName helper 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.

labelMessageAsAwaitingReply logs an error when the label ID is unavailable (line 21), but removeAwaitingReplyLabelFromThread and removeNeedsReplyLabelFromThread silently 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

📥 Commits

Reviewing files that changed from the base of the PR and between aab5139 and f06a79f.

📒 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • apps/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.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/prisma/migrations/20251005093547_label_id/migration.sql
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/prisma/schema.prisma
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
apps/web/app/**/*.tsx

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

Components with onClick must be client components with use client directive

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/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 use elements 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • 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/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/prisma/migrations/20251005093547_label_id/migration.sql
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/prisma/schema.prisma
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • apps/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.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.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-action provides centralized error handling
Use Zod schemas for validation on both client and server
Use revalidatePath in server actions for cache invalidation

apps/web/utils/actions/**/*.ts: Use server actions (with next-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
Use revalidatePath in 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 Zod

Files:

  • apps/web/utils/actions/settings.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • apps/web/utils/label-config.ts
apps/web/utils/actions/*.ts

📄 CodeRabbit inference engine (.cursor/rules/server-actions.mdc)

apps/web/utils/actions/*.ts: Implement all server actions using the next-safe-action library for type safety, input validation, context management, and error handling. Refer to apps/web/utils/actions/safe-action.ts for client definitions (actionClient, actionClientUser, adminActionClient).
Use actionClientUser when only authenticated user context (userId) is needed.
Use actionClient when both authenticated user context and a specific emailAccountId are needed. The emailAccountId must be bound when calling the action from the client.
Use adminActionClient for actions restricted to admin users.
Access necessary context (like userId, emailAccountId, etc.) provided by the safe action client via the ctx object 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.
Use SafeError for expected/handled errors within actions if needed. next-safe-action provides centralized error handling.
Use the .metadata({ name: "actionName" }) method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied via withServerActionInstrumentation within the safe action clients.
If an action modifies data displayed elsewhere, use revalidatePath or revalidateTag from next/cache within the action handler as needed.

Server action files must start with use server

Files:

  • apps/web/utils/actions/settings.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.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • 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/actions/settings.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/cold-email/is-cold-email.test.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/ai/actions.ts
  • apps/web/utils/reply-tracker/label-helpers.ts
  • apps/web/utils/email/types.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/email/microsoft.ts
  • apps/web/utils/rule/rule.ts
  • apps/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 the server-only module with vi.mock("server-only", () => ({}));
When testing code that uses Prisma, mock it with vi.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() in beforeEach)
Avoid testing implementation details; focus on observable behavior
Do not mock the Logger

Files:

  • apps/web/utils/cold-email/is-cold-email.test.ts
apps/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 features

Files:

  • apps/web/utils/ai/actions.ts
  • apps/web/utils/ai/assistant/chat.ts
apps/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.ts
  • apps/web/utils/ai/assistant/chat.ts
apps/web/prisma/schema.prisma

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

The Prisma schema file must be located at apps/web/prisma/schema.prisma

Files:

  • 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 helpers

Applied 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 emailAccountId to the updateRuleActions call 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 labelId fields 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 labelMessage signature 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 SystemLabelsSetting is 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 labelMessage implementation 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:

  • getLabelByName enables label lookup by name for ID resolution
  • labelMessage now accepts labelId instead of labelName, ensuring consistent ID-based labeling across providers

Both 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 emailProvider throughout the rule creation and update flow is correct:

  • createEmailProvider is called with the appropriate parameters
  • mapActionFields is properly awaited since it's now async
  • emailAccountId is correctly added to updateRuleActions signature and used to create the provider

Also 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 null labelId by early returns, so logging a warning and continuing with labelId: null is safe. No unguarded use of a null labelId was found. The current error handling is sufficient; no changes required.

No changes needed; downstream logic already skips null labelId gracefully.

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.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/web/utils/label-config.ts (1)

13-13: Consider exporting SystemLabelType for type safety.

The SystemLabelType is used in public function signatures but isn't exported. Exporting it would allow consuming code to strongly type the type parameter 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

📥 Commits

Reviewing files that changed from the base of the PR and between f06a79f and a626770.

📒 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}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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 use elements 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/web/components/LabelCombobox.tsx (1)

48-62: Consider using toastError/toastSuccess for consistency.

While toast.promise from sonner works correctly, the project's coding guidelines recommend using the toastError and toastSuccess wrappers 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 emailAccountData exists before rendering the form, the fallback to an empty string (?? "") could theoretically pass an invalid value to createLabelAction. 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

📥 Commits

Reviewing files that changed from the base of the PR and between a626770 and cc8acc0.

📒 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.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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-action provides centralized error handling
Use Zod schemas for validation on both client and server
Use revalidatePath in server actions for cache invalidation

apps/web/utils/actions/**/*.ts: Use server actions (with next-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
Use revalidatePath in 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.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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.ts file. These schemas are used by next-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}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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 the next-safe-action library for type safety, input validation, context management, and error handling. Refer to apps/web/utils/actions/safe-action.ts for client definitions (actionClient, actionClientUser, adminActionClient).
Use actionClientUser when only authenticated user context (userId) is needed.
Use actionClient when both authenticated user context and a specific emailAccountId are needed. The emailAccountId must be bound when calling the action from the client.
Use adminActionClient for actions restricted to admin users.
Access necessary context (like userId, emailAccountId, etc.) provided by the safe action client via the ctx object 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.
Use SafeError for expected/handled errors within actions if needed. next-safe-action provides centralized error handling.
Use the .metadata({ name: "actionName" }) method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied via withServerActionInstrumentation within the safe action clients.
If an action modifies data displayed elsewhere, use revalidatePath or revalidateTag from next/cache within 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 use elements 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.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
apps/web/app/**/*.tsx

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

Components with onClick must be client components with use client directive

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SettingsTab.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/components/LabelCombobox.tsx
apps/web/components/**/*.tsx

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

Use React Hook Form with Zod validation for form handling

Use the LoadingContent component 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 handling

Applied 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 validation

Applied 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 id and name fields, 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.ts file 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, using toastError/toastSuccess, and properly refreshing data with mutate() 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: null is appropriate for non-label actions.

For ARCHIVE (line 157) and DIGEST (line 177) actions, setting labelId: null is 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: labelId isn’t used for display.

getActionDisplay relies on the label string (not labelId), so setting labelId: null on this synthetic, display-only rule has no impact.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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.error violates the coding guidelines. Use createScopedLogger for 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

📥 Commits

Reviewing files that changed from the base of the PR and between cc8acc0 and 412fef1.

📒 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.tsx
  • apps/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.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**/*.tsx

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

Components with onClick must be client components with use client directive

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/SystemLabelsSetting.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,jsx,ts,tsx}

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

**/*.{js,jsx,ts,tsx}: Don't use elements 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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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 handling

Applied 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 validation

Applied 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 LabelCombobox from 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 external LabelCombobox component always receives a non-null array, preventing potential runtime errors.


1020-1020: No need to verify mutate signature: mutateLabels is never invoked in RuleForm.tsx.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (2)
apps/web/utils/label-config.ts (2)

102-108: Wrap database updates in a transaction.

The emailAccount update (lines 102-105) and updateAffectedRules call (line 107) are executed separately. If updateAffectedRules fails 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 updateAffectedRules to 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

📥 Commits

Reviewing files that changed from the base of the PR and between be7d376 and e341b97.

📒 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.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • 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/email/microsoft.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • 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/email/microsoft.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/label-config.ts
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • 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/email/microsoft.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • 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/email/microsoft.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/label-config.ts
**/*.{js,jsx,ts,tsx}

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

**/*.{js,jsx,ts,tsx}: Don't use elements 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.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • 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/email/microsoft.ts
  • apps/web/utils/email/google.ts
  • apps/web/utils/actions/settings.ts
  • apps/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-action provides centralized error handling
Use Zod schemas for validation on both client and server
Use revalidatePath in server actions for cache invalidation

apps/web/utils/actions/**/*.ts: Use server actions (with next-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
Use revalidatePath in 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 the next-safe-action library for type safety, input validation, context management, and error handling. Refer to apps/web/utils/actions/safe-action.ts for client definitions (actionClient, actionClientUser, adminActionClient).
Use actionClientUser when only authenticated user context (userId) is needed.
Use actionClient when both authenticated user context and a specific emailAccountId are needed. The emailAccountId must be bound when calling the action from the client.
Use adminActionClient for actions restricted to admin users.
Access necessary context (like userId, emailAccountId, etc.) provided by the safe action client via the ctx object 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.
Use SafeError for expected/handled errors within actions if needed. next-safe-action provides centralized error handling.
Use the .metadata({ name: "actionName" }) method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied via withServerActionInstrumentation within the safe action clients.
If an action modifies data displayed elsewhere, use revalidatePath or revalidateTag from next/cache within 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 getLabelByName method correctly delegates to the internal getLabel helper and transforms the result to the EmailLabel interface. The null-check and early return are appropriate.


260-272: LGTM!

The updated labelMessage signature now accepts an object with messageId and labelId, which aligns with the broader refactor to use stable label IDs. The implementation correctly passes the labelId to the underlying labelMessage helper.

apps/web/utils/email/microsoft.ts (2)

125-133: LGTM!

The getLabelByName method correctly delegates to the internal getLabel helper and transforms the result to the EmailLabel interface. The implementation mirrors the Google provider and is consistent.


305-321: LGTM!

The updated labelMessage signature now accepts an object with messageId and labelId. 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/utils/actions/rule.ts (1)

144-188: Make label resolution best-effort inside server actions
createRuleAction, updateRuleAction, and resolveActionLabels now always call createEmailProvider, even when the submitted actions contain zero LABELs. 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 lazy shouldResolveLabels/try-catch pattern from rule.ts, and let resolveActionLabels accept 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.update runs before action.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 same prisma.$transaction and use the scoped tx client 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 allow userLabels to be undefined.

useLabels() can yield undefined, and the render path guards with userLabels || [], so the prop type should allow undefined instead of forcing a non-null array. Please adjust the prop to EmailLabel[] | 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.

setValue defaults to shouldValidate: false, so any existing error for labelId will 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

📥 Commits

Reviewing files that changed from the base of the PR and between e341b97 and d8cd5b2.

📒 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.tsx
  • apps/web/utils/label/resolve-label.ts
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/utils/rule/rule.ts
  • apps/web/app/api/user/rules/[id]/route.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/action-display.tsx
  • apps/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.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/app/api/user/rules/[id]/route.ts
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/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.tsx
  • apps/web/utils/label/resolve-label.ts
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/utils/rule/rule.ts
  • apps/web/app/api/user/rules/[id]/route.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/action-display.tsx
  • apps/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.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/action-display.tsx
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/web/utils/label/resolve-label.ts
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/utils/rule/rule.ts
  • apps/web/app/api/user/rules/[id]/route.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/action-display.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**/*.tsx

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

Components with onClick must be client components with use client directive

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/CreatedRulesModal.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,jsx,ts,tsx}

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

**/*.{js,jsx,ts,tsx}: Don't use elements 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.tsx
  • apps/web/utils/label/resolve-label.ts
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/utils/rule/rule.ts
  • apps/web/app/api/user/rules/[id]/route.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/action-display.tsx
  • apps/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.tsx
  • apps/web/utils/label/resolve-label.ts
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/utils/rule/rule.ts
  • apps/web/app/api/user/rules/[id]/route.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/action-display.tsx
  • apps/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.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/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.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/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 Zod

Files:

  • apps/web/utils/label/resolve-label.ts
  • apps/web/utils/rule/rule.ts
  • apps/web/app/api/user/rules/[id]/route.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/actions/rule.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/label/resolve-label.ts
  • apps/web/utils/rule/rule.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/action-display.tsx
  • apps/web/utils/actions/rule.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/label/resolve-label.ts
  • apps/web/utils/rule/rule.ts
  • apps/web/utils/actions/rule.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/reply-tracker/enable.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/actions/rule.validation.ts
apps/web/app/api/**/route.ts

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

apps/web/app/api/**/route.ts: Use withAuth for user-level operations
Use withEmailAccount for 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 with withAuth or withEmailAccount middleware 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).
Use withEmailAccount middleware for API routes that operate on a specific email account (i.e., use or require emailAccountId).
Use withAuth middleware for API routes that operate at the user level (i.e., use or require only userId).
Use withError middleware (with proper validation) for public endpoints, custom authentication, or cron endpoints.
Cron endpoints MUST use withError middleware and validate the cron secret using hasCronSecret(request) or hasPostCronSecret(request).
Cron endpoints MUST capture unauthorized attempts with captureException and 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.
All findUnique and findFirst Prisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
All findMany Prisma 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.ts
apps/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.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-action provides centralized error handling
Use Zod schemas for validation on both client and server
Use revalidatePath in server actions for cache invalidation

apps/web/utils/actions/**/*.ts: Use server actions (with next-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
Use revalidatePath in server actions to invalidate cache after mutations.

Files:

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

📄 CodeRabbit inference engine (.cursor/rules/server-actions.mdc)

apps/web/utils/actions/*.ts: Implement all server actions using the next-safe-action library for type safety, input validation, context management, and error handling. Refer to apps/web/utils/actions/safe-action.ts for client definitions (actionClient, actionClientUser, adminActionClient).
Use actionClientUser when only authenticated user context (userId) is needed.
Use actionClient when both authenticated user context and a specific emailAccountId are needed. The emailAccountId must be bound when calling the action from the client.
Use adminActionClient for actions restricted to admin users.
Access necessary context (like userId, emailAccountId, etc.) provided by the safe action client via the ctx object 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.
Use SafeError for expected/handled errors within actions if needed. next-safe-action provides centralized error handling.
Use the .metadata({ name: "actionName" }) method to provide a meaningful name for monitoring. Sentry instrumentation is automatically applied via withServerActionInstrumentation within the safe action clients.
If an action modifies data displayed elsewhere, use revalidatePath or revalidateTag from next/cache within the action handler as needed.

Server action files must start with use server

Files:

  • apps/web/utils/actions/rule.ts
  • apps/web/utils/actions/settings.ts
  • apps/web/utils/actions/rule.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.ts file. These schemas are used by next-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 handling

Applied 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 validation

Applied 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 server

Applied 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)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a21ecf3 and e3325e3.

📒 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
apps/web/app/**/*.tsx

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

Components with onClick must be client components with use client directive

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/FixWithChat.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessRules.tsx
**/*.{js,jsx,ts,tsx}

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

**/*.{js,jsx,ts,tsx}: Don't use elements 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/TestCustomEmailForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ProcessResultDisplay.tsx
  • apps/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 emailAccountId prop aligns with the refactored ProcessResultDisplay component signature, which now only requires result and an optional prefix.


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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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 use labelId: { 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 use labelId

  • 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[] | undefined

As 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

📥 Commits

Reviewing files that changed from the base of the PR and between e3325e3 and c6e09ce.

📒 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/components/GroupedTable.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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 LoadingContent component 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.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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 use elements 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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/components/LabelCombobox.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/create/examples.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/ActionSummaryCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/create/examples.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/ActionSummaryCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/create/examples.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/ActionSummaryCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/create/examples.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/ActionSummaryCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/create/examples.tsx
apps/web/app/**/*.tsx

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

Components with onClick must be client components with use client directive

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/rule/[ruleId]/examples/page.tsx
  • apps/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 handling

Applied 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 validation

Applied 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. The target="_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 labels prop 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: resolveLabelNameAndId is an async email‐provider lookup, whereas this UI code uses a synchronous in-memory labels array—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 deprecated label: { 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.

@elie222 elie222 merged commit df73660 into main Oct 5, 2025
4 of 5 checks passed
@elie222 elie222 deleted the feat/rename-system-labels branch October 5, 2025 20:29
@coderabbitai coderabbitai bot mentioned this pull request Dec 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments