Skip to content

Rules improvements - #1087

Merged
elie222 merged 74 commits into
elie222:mainfrom
jshwrnr:feat/rules-improvements
Dec 16, 2025
Merged

elie222 merged 74 commits into
elie222:mainfrom
jshwrnr:feat/rules-improvements

Conversation

@jshwrnr

@jshwrnr jshwrnr commented Dec 10, 2025 •

Copy link
Copy Markdown
Collaborator

Revamp rules UI to use step-based condition/action editors, iconized condition indicators, and redirect rule flows to /automation?tab=rules

Refactors the rules experience to step-based editors for conditions and actions, replaces the table’s inline condition text with tooltiped icons, adds reusable rule step/card components, updates validation to allow one AI condition plus distinct per-field static conditions, and changes post-create/delete navigation to /automation?tab=rules.

📍Where to Start

Start with the Rules table changes and condition icon logic in Rules.tsx, then review the new step editors in RuleForm.tsx, ConditionSteps.tsx, and ActionSteps.tsx.


Macroscope summarized c1c2e2c.

Summary by CodeRabbit

  • New Features

    • Redesigned rule editor with step-based condition and per-action editors, card-style sections, delay controls, AI-variable helpers, action icons, advanced settings, and a new stats card grid.
  • Improvements

    • Streamlined rules list and action badges, refined condition handling/validation to avoid duplicates and mix AI/static rules, updated post-submit navigation to the automation rules tab, improved API error parsing, and clarified webhook URL label.
  • Style

    • Minor input/error text styling tweak.

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


Note

Cursor Bugbot is generating a summary for commit 6067f44. Configure here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx (1)

100-137: Add explicit React import for type references.

The component uses React.ReactNode (lines 100, 104, 112, 136, 137) without importing the React namespace. While the JSX transform handles createElement, the React namespace reference for types requires an explicit import.

 import { Button } from "@/components/ui/button";
 import {
   TrashIcon,
   MoreHorizontalIcon,
   ClockIcon,
   SparklesIcon,
   PenLineIcon,
 } from "lucide-react";
+import type { ReactNode } from "react";
 import { cn } from "@/utils";

Then update the type references to use ReactNode directly instead of React.ReactNode.

apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1)

150-160: First-condition enforcement overwrites user data when removing conditions.

This useEffect forces conditions[0] to be a "prompt" type, which causes data loss when:

  1. User has [prompt, from-filter]
  2. User removes the first condition
  3. useFieldArray.remove(0) shifts from-filter to index 0
  4. This effect then overwrites the from-filter with an empty prompt condition

Consider one of these fixes:

  • Prevent removing the first condition entirely (always keep prompt row)
  • Prepend a new prompt condition instead of overwriting index 0
  • Check if the shifted condition should be preserved before overwriting
🧹 Nitpick comments (6)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1)

351-358: Consider using the Input component with autosizeTextarea for consistency.

The coding guidelines recommend using the Input component with autosizeTextarea prop for text areas. This provides consistent styling and error handling integration.

-<TextareaAutosize
-  className="block w-full flex-1 whitespace-pre-wrap rounded-md border border-border bg-background shadow-sm focus:border-black focus:ring-black sm:text-sm"
-  minRows={3}
-  rows={3}
-  {...register(`conditions.${index}.instructions`)}
-  placeholder="e.g. Newsletters, regular content from publications, blogs, or services I've subscribed to"
-/>
+<Input
+  type="text"
+  autosizeTextarea
+  rows={3}
+  name={`conditions.${index}.instructions`}
+  registerProps={register(`conditions.${index}.instructions`)}
+  placeholder="e.g. Newsletters, regular content from publications, blogs, or services I've subscribed to"
+/>
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)

529-531: Consider using a proper confirmation dialog instead of confirm().

The native confirm() is blocking and doesn't match the app's UI style. Since this is inside a Dialog component already, consider using a nested AlertDialog from shadcn/ui for consistent UX.


614-619: Duplicate function: allowMultipleConditions exists in both files.

This function is also defined in ConditionSteps.tsx (lines 55-60). Consider extracting it to a shared utility to avoid duplication.

// In a shared file like apps/web/utils/rule/consts.ts or a new helper:
+export function allowMultipleConditions(systemType: SystemType | null | undefined) {
+  return (
+    systemType !== SystemType.COLD_EMAIL &&
+    !isConversationStatusType(systemType)
+  );
+}

Then import it in both RuleForm.tsx and ConditionSteps.tsx.

apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (3)

727-735: Singular/plural labels could be simplified.

The current logic checks raw delayInMinutes values (1, 60, 1440) to determine singular/plural, which works but is indirect. Consider using the computed displayValue instead for clarity:

 <SelectItem value="minutes">
-  {delayInMinutes === 1 ? "Minute" : "Minutes"}
+  {displayValue === "1" && unit === "minutes" ? "Minute" : "Minutes"}
 </SelectItem>
 <SelectItem value="hours">
-  {delayInMinutes === 60 ? "Hour" : "Hours"}
+  {displayValue === "1" && unit === "hours" ? "Hour" : "Hours"}
 </SelectItem>
 <SelectItem value="days">
-  {delayInMinutes === 1440 ? "Day" : "Days"}
+  {displayValue === "1" && unit === "days" ? "Day" : "Days"}
 </SelectItem>

269-471: Consider extracting renderField into a separate component.

The renderField function is ~200 lines and handles complex conditional rendering. While the closure access to form state is convenient, extracting it into a <FieldRenderer> component could improve readability and testability.

This is a larger refactor that could be deferred, but would help with:

  • Easier unit testing of individual field types
  • Better code organization
  • Reduced cognitive load when reading ActionCard

127-130: Use imported types consistently.

ActionCard uses ReturnType<typeof useForm<CreateRuleBody>>["register"] while the imported types (UseFormRegister<CreateRuleBody>) would be cleaner and match the parent component's signature.

-register: ReturnType<typeof useForm<CreateRuleBody>>["register"];
-watch: ReturnType<typeof useForm<CreateRuleBody>>["watch"];
-setValue: ReturnType<typeof useForm<CreateRuleBody>>["setValue"];
-control: ReturnType<typeof useForm<CreateRuleBody>>["control"];
+register: UseFormRegister<CreateRuleBody>;
+watch: UseFormWatch<CreateRuleBody>;
+setValue: UseFormSetValue<CreateRuleBody>;
+control: Control<CreateRuleBody>;
📜 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 81b98f0 and 5a0ebfc.

📒 Files selected for processing (4)
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (7 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.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
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
apps/web/**/*.tsx

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

apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
apps/web/app/(app)/**/*.{ts,tsx}

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

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

Files:

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
**/*.{tsx,ts}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
**/*.{tsx,ts,css}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
**/*.tsx

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
**/*.{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
**/*Form.{ts,tsx}

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

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧠 Learnings (30)
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use semantic elements instead of role attributes in JSX

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Make sure all dependencies are correctly specified in React hooks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Don't define React components inside other components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text areas in forms, use the `Input` component with `type='text'`, `autosizeTextarea` prop, `rows`, `name`, `placeholder`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Use `<>...</>` instead of `<Fragment>...</Fragment>`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Use Shadcn UI and Tailwind for components and styling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Always include a `type` attribute for button elements

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : Use Shadcn UI and Tailwind for components and styling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields in the UI

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must follow a standard structure: accept options with `inputData` and `emailAccount` parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use `createGenerateObject` to execute the LLM call

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission using React Hook Form and Zod resolver

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Use React Hook Form with Zod validation (`zodResolver`) for form handling, with form components using `register`, `handleSubmit`, and error handling from the hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for form validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for validation in form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Handle form submission results using `result?.serverError` to show error toasts and `toastSuccess` to show success messages after server action completion

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in form submissions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For text inputs, use the `Input` component with `registerProps` for form integration and error handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.tsx : For text areas, use the `Input` component with `type='text'`, `autosizeTextarea` prop set to true, and `registerProps` for form integration

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Create corresponding server action implementation files using the naming convention `apps/web/utils/actions/NAME.ts` with 'use server' directive

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Add metadata with a meaningful action name using `.metadata({ name: "actionName" })` for Sentry instrumentation and monitoring

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
🧬 Code graph analysis (2)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (5)
apps/web/utils/actions/rule.validation.ts (2)
  • ZodCondition (62-62)
  • CreateRuleBody (194-194)
apps/web/utils/reply-tracker/conversation-status-config.ts (1)
  • isConversationStatusType (16-22)
apps/web/app/(app)/[emailAccountId]/assistant/RuleSteps.tsx (1)
  • RuleSteps (7-40)
apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx (1)
  • RuleStep (120-172)
apps/web/utils/rule/consts.ts (1)
  • getRuleConfig (112-116)
apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (7)
apps/web/utils/outlook/folders.ts (1)
  • OutlookFolder (12-17)
apps/web/app/(app)/[emailAccountId]/assistant/RuleSteps.tsx (1)
  • RuleSteps (7-40)
apps/web/utils/action-item.ts (1)
  • actionInputs (4-152)
apps/web/utils/delayed-actions.ts (1)
  • canActionBeDelayed (14-16)
apps/web/components/FolderSelector.tsx (1)
  • FolderSelector (90-287)
apps/web/utils/template.ts (2)
  • hasVariables (5-6)
  • TEMPLATE_VARIABLE_PATTERN (2-2)
apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx (1)
  • RuleStep (120-172)
⏰ 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: test
🔇 Additional comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1)

47-52: Verify body-to-subject mapping behavior.

The body field maps to "subject" UI type (line 50), but when the user modifies this condition, getConditionFromUIType("subject") creates a condition with subject: "" and body: null. This will silently lose any existing body data.

Is this intentional? If rules can have body conditions from elsewhere (e.g., API, migrations), they'll appear as "subject" in the UI and lose the body value on any edit.

apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

386-425: Well-structured modular form layout.

The refactor to RuleSectionCard with ConditionSteps and ActionSteps components creates a clean, maintainable structure. The separation of concerns and consistent card-based UI align well with the step-based editing goals.

apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1)

46-107: Clean composition with RuleSteps container.

The ActionSteps component provides a well-structured wrapper that maps action fields to ActionCard instances. The integration with RuleSteps for the add button and consistent prop passing is well-organized.

Comment thread apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
Comment on lines +528 to +567
onClick={async () => {
const yes = confirm(
"Are you sure you want to delete this rule?",
);
if (yes) {
try {
setIsDeleting(true);
const result = await deleteRuleAction(
emailAccountId,
{
id: rule.id!,
},
);
if (result?.serverError) {
toastError({
description: result.serverError,
});
} else {
toastSuccess({
description: "The rule has been deleted.",
});

if (isDialog && onSuccess) {
onSuccess();
}

router.push(
prefixPath(
emailAccountId,
"/automation?tab=rules",
),
);
}
} catch {
toastError({ description: "Failed to delete rule." });
} finally {
setIsDeleting(false);
}
}
}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Empty catch block loses error context.

The catch block at line 561 catches the error but doesn't log it, making debugging difficult if the delete operation fails for unexpected reasons.

-} catch {
+} catch (error) {
+  console.error("Failed to delete rule:", error);
   toastError({ description: "Failed to delete rule." });
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx around lines 528
to 567, the catch block for delete action swallows the thrown error; update the
catch to accept the error (e.g., catch (err)) and log the error (console.error
or a project logger) and include the error message in the toastError description
or log so you retain error context for debugging, then keep the existing finally
block that resets setIsDeleting(false).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1)

165-176: Previous concern about data loss has been addressed.

The useEffect now checks if uiType === undefined before setting a default prompt condition. This prevents overwriting existing static conditions when they shift to index 0 after removal of the first condition. The fix correctly addresses the data-loss issue flagged in previous reviews.

apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1)

74-74: Add missing ElementType import.

The code references React.ElementType without importing the React namespace or ElementType type. This will cause a TypeScript error.

Apply this diff:

-import { useCallback, useMemo, useState } from "react";
+import { useCallback, useMemo, useState, type ElementType } from "react";

Then update lines 74 and 137 to use ElementType directly:

-  typeOptions: { label: string; value: ActionType; icon: React.ElementType }[];
+  typeOptions: { label: string; value: ActionType; icon: ElementType }[];
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

561-565: Log error in catch block for debugging.

The catch block doesn't capture the error, losing valuable debugging information when deletion fails.

Apply this diff:

-                        } catch {
+                        } catch (error) {
+                          console.error("Failed to delete rule:", error);
                           toastError({ description: "Failed to delete rule." });
🧹 Nitpick comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (2)

70-73: Remove redundant | never from return type.

The | never union in the return type is unnecessary. A function that can throw (line 126) or return ZodCondition doesn't need | never in its signature.

Apply this diff:

-function getConditionFromUIType(
-  uiType: UIConditionType | undefined,
-): ZodCondition | never {
+function getConditionFromUIType(
+  uiType: UIConditionType | undefined,
+): ZodCondition {

277-296: Consider simplifying the prompt reordering logic.

The loop that reorders conditions when a prompt is selected at a non-first position could be more readable using array methods.

Consider this refactor:

-                      // If AI Prompt is selected at a non-first position,
-                      // insert it at position 0 and shift other conditions
                       if (value === "prompt" && index !== 0) {
                         const currentConditionAtIndex = conditions[index];
                         const currentConditionType = getUIConditionType(
                           currentConditionAtIndex,
                         );

-                        // Build new conditions array with AI Prompt at position 0
-                        const newConditions = [newCondition];
-
-                        // Add all existing conditions except the one being changed
-                        for (let i = 0; i < conditions.length; i++) {
-                          if (i !== index) {
-                            newConditions.push(conditions[i]);
-                          } else if (currentConditionType !== undefined) {
-                            // If the condition being changed had data, keep it
-                            newConditions.push(currentConditionAtIndex);
-                          }
-                          // If it was empty (undefined type), just skip it
-                        }
+                        // Build new conditions array with AI Prompt at position 0
+                        const otherConditions = conditions.filter((_, i) => i !== index);
+                        const newConditions = [newCondition];
+                        
+                        // If the condition being changed had data, keep it
+                        if (currentConditionType !== undefined) {
+                          newConditions.push(currentConditionAtIndex);
+                        }
+                        newConditions.push(...otherConditions);

                         setValue("conditions", newConditions);
📜 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 5a0ebfc and 10208dd.

📒 Files selected for processing (4)
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (7 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.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
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
apps/web/**/*.tsx

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

apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
apps/web/app/(app)/**/*.{ts,tsx}

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

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

Files:

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
**/*.{tsx,ts}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
**/*.{tsx,ts,css}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
**/*.tsx

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
**/*.{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
**/*Form.{ts,tsx}

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

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧠 Learnings (37)
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Create corresponding server action implementation files using the naming convention `apps/web/utils/actions/NAME.ts` with 'use server' directive

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in `apps/web/utils/actions/*.validation.ts`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use semantic elements instead of role attributes in JSX

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Always include a `type` attribute for button elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use valid, non-abstract ARIA roles for elements with ARIA roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Make sure all dependencies are correctly specified in React hooks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text areas in forms, use the `Input` component with `type='text'`, `autosizeTextarea` prop, `rows`, `name`, `placeholder`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{ts,tsx} : Use `import type` for types

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure ARIA properties are valid for the element's supported roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make static elements with click handlers use a valid role attribute

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Watch out for possible "wrong" semicolons inside JSX elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use proper error handling with try/catch blocks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `SafeError` for error responses to prevent information disclosure - provide generic messages (e.g., 'Rule not found' not 'Rule {id} does not exist for user {userId}') without revealing internal IDs or ownership details

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't reassign exceptions in catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in form submissions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission using React Hook Form and Zod resolver

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Use React Hook Form with Zod validation (`zodResolver`) for form handling, with form components using `register`, `handleSubmit`, and error handling from the hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for form validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for validation in form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields in the UI

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Handle form submission results using `result?.serverError` to show error toasts and `toastSuccess` to show success messages after server action completion

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For text inputs, use the `Input` component with `registerProps` for form integration and error handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.tsx : For text areas, use the `Input` component with `type='text'`, `autosizeTextarea` prop set to true, and `registerProps` for form integration

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (8)
apps/web/utils/action-display.tsx (1)
  • getActionIcon (86-115)
apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx (1)
  • RuleSectionCard (5-58)
apps/web/utils/reply-tracker/conversation-status-config.ts (1)
  • isConversationStatusType (16-22)
apps/web/utils/rule/consts.ts (1)
  • getRuleConfig (112-116)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1)
  • ConditionSteps (129-544)
apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1)
  • ActionSteps (46-107)
apps/web/components/Toggle.tsx (1)
  • Toggle (18-50)
apps/web/app/(app)/[emailAccountId]/assistant/group/LearnedPatterns.tsx (1)
  • LearnedPatternsDialog (21-96)
⏰ 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: test
🔇 Additional comments (4)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1)

129-544: Well-structured condition management component.

The component follows best practices:

  • Proper form integration with react-hook-form via register, setValue, and watch
  • Error handling with inline ErrorMessage display
  • Accessibility through labeled inputs and tooltips
  • Modular design with clear separation of UI condition types and backend conditions
apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1)

46-615: Well-structured action management with good UX patterns.

The component demonstrates several strengths:

  • Proper form integration with react-hook-form
  • Good use of useCallback and useMemo for performance
  • Nice UX features like variable highlighting and expandable fields
  • Correct usage of Input component with registerProps per coding guidelines
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)

386-466: Excellent refactoring to modular components.

The refactoring successfully:

  • Separates concerns with RuleSectionCard, ConditionSteps, and ActionSteps
  • Maintains proper form integration throughout
  • Provides clear visual hierarchy with icons and colors
  • Preserves error handling and validation

468-598: Well-executed Advanced Settings dialog.

Moving advanced settings to a dialog improves the UX by:

  • Reducing visual clutter in the main form
  • Grouping related settings logically
  • Maintaining accessibility with proper dialog structure
  • Preserving all functionality including delete action

Comment thread apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx (1)

1-3: Add missing ComponentType import.

The component uses React.ComponentType on line 12 without importing it. Add a type-only import and update the reference.

Apply this diff:

 import { Card } from "@/components/ui/card";
 import { TypographyH3 } from "@/components/Typography";
 import { cn } from "@/utils";
+import type { ComponentType, ReactNode } from "react";

Then update line 12:

-  icon: React.ComponentType<{ className?: string }>;
+  icon: ComponentType<{ className?: string }>;

As per coding guidelines: Use import type for types.

Also applies to: 12-12

apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)

3-3: Add missing ElementType import.

The code uses React.ElementType on line 277 without importing it. Add a type-only import and update the reference.

Apply this diff:

-import { useCallback, useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useState, type ElementType } from "react";

Then update line 277:

-      icon: React.ElementType;
+      icon: ElementType;

As per coding guidelines: Use import type for types.

Also applies to: 273-278


555-556: Empty catch block loses error context.

The catch block doesn't capture or log the error, making debugging difficult if deletion fails unexpectedly.

Apply this diff:

-                        } catch {
+                        } catch (error) {
+                          console.error("Failed to delete rule:", error);
                           toastError({ description: "Failed to delete rule." });

As per coding guidelines: Use proper error handling with try/catch blocks.

🧹 Nitpick comments (2)
apps/web/providers/SWRProvider.tsx (1)

38-51: Consider using captureException for production logging consistency.

The try/catch approach for handling non-JSON responses is solid. However, using console.error in production (line 45) doesn't align with the project's structured error logging pattern via captureException.

Apply this diff to use structured error reporting:

     } catch {
       // Response wasn't JSON - common during dev HMR, unexpected in production
       if (process.env.NODE_ENV !== "development") {
-        console.error("Failed to parse error response as JSON", {
+        captureException(new Error("Failed to parse error response as JSON"), {
+          extra: {
-          url,
-          status: res.status,
-          statusText: res.statusText,
+            url,
+            status: res.status,
+            statusText: res.statusText,
+          },
         });
       }
     }
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

608-613: Consider extracting duplicated utility function.

The allowMultipleConditions function is duplicated in ConditionSteps.tsx (lines 63-68). Consider extracting it to a shared utility file like @/utils/rule/helpers.ts to avoid code duplication and ensure consistency.

📜 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 10208dd and e30a17f.

📒 Files selected for processing (4)
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (7 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx (1 hunks)
  • apps/web/providers/SWRProvider.tsx (2 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
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.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 for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
apps/web/app/(app)/**/*.{ts,tsx}

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

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

Files:

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*.{tsx,ts}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*.{tsx,ts,css}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*.tsx

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*.{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*.{js,ts,jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/providers/SWRProvider.tsx
**/*Form.{ts,tsx}

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

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/components/**/*.tsx : Use PascalCase for component file names (e.g., `components/Button.tsx`)

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{ts,tsx} : Use `import type` for types

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use semantic elements instead of role attributes in JSX

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text areas in forms, use the `Input` component with `type='text'`, `autosizeTextarea` prop, `rows`, `name`, `placeholder`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Always include a `type` attribute for button elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Make sure all dependencies are correctly specified in React hooks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Don't define React components inside other components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks over class components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use proper error handling with try/catch blocks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `SafeError` for error responses to prevent information disclosure - provide generic messages (e.g., 'Rule not found' not 'Rule {id} does not exist for user {userId}') without revealing internal IDs or ownership details

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't reassign exceptions in catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in form submissions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use valid, non-abstract ARIA roles for elements with ARIA roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make static elements with click handlers use a valid role attribute

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure label elements have text content and are associated with an input

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure ARIA properties are valid for the element's supported roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Watch out for possible "wrong" semicolons inside JSX elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission using React Hook Form and Zod resolver

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Use React Hook Form with Zod validation (`zodResolver`) for form handling, with form components using `register`, `handleSubmit`, and error handling from the hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for form validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for validation in form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields in the UI

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Handle form submission results using `result?.serverError` to show error toasts and `toastSuccess` to show success messages after server action completion

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For text inputs, use the `Input` component with `registerProps` for form integration and error handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.tsx : For text areas, use the `Input` component with `type='text'`, `autosizeTextarea` prop set to true, and `registerProps` for form integration

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/hooks/use*.ts : Use SWR for client-side data fetching with typed responses from GET API routes

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : For API GET requests to server, use the `swr` package

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : If we're in a deeply nested component we will use `swr` to fetch via API

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:39:08.150Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:08.150Z
Learning: Applies to apps/web/app/api/**/*.{ts,tsx} : Use generic error messages instead of revealing internal details; throw `SafeError` instead of exposing user IDs, resource IDs, or system information

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For API GET requests to server, use the `swr` package with hooks like `useSWR` to fetch data

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Maintain consistent error response format across all API routes to avoid information disclosure while providing meaningful error feedback

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If nested deeply in components, use `swr` to fetch via API instead of loading data directly

Applied to files:

  • apps/web/providers/SWRProvider.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/hooks/use*.ts : Use SWR hooks for client-side data fetching, with hooks stored in `apps/web/hooks/use*.ts` that return typed responses from GET API routes

Applied to files:

  • apps/web/providers/SWRProvider.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx (2)
apps/web/components/new-landing/common/Card.tsx (1)
  • Card (67-105)
apps/web/components/Typography.tsx (1)
  • TypographyH3 (125-125)
⏰ 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: test
🔇 Additional comments (7)
apps/web/providers/SWRProvider.tsx (1)

81-84: LGTM! Improved error typing.

The change from any to Record<string, unknown> with explicit type casting provides better type safety while maintaining the existing error handling flow.

apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (3)

165-176: LGTM! The first-condition enforcement now preserves existing data.

The fix correctly checks if the first condition is empty (uiType === undefined) before initializing it as a prompt. This prevents overwriting existing static conditions when loading a rule, addressing the data-loss issue flagged in previous reviews.


254-301: Complex but correct reordering logic for AI Prompt.

The logic properly handles moving an AI Prompt to position 0 when selected at a later index, preserving configured conditions and skipping empty ones. The duplicate checking and user feedback are well-implemented.


449-533: Well-structured form inputs with proper error handling.

The condition inputs follow the project's form patterns, using the Input component with registerProps for integration and displaying inline errors. The tooltips enhance usability.

apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx (1)

5-37: Clean and well-structured card component.

The component provides a consistent layout for rule sections with proper conditional rendering and styling. The use of the cn utility for dynamic classes is appropriate.

apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)

386-460: Excellent modular refactoring of the rule form.

The refactor into RuleSectionCard, ConditionSteps, and ActionSteps components significantly improves code organization and reusability. The consistent use of section cards with icons and proper error handling enhances both maintainability and user experience.


463-568: Well-implemented Advanced Settings dialog.

The dialog consolidates advanced options in a clean, accessible way. The use of toggles, tooltips, and proper button states provides a good user experience.

@vercel

vercel Bot commented Dec 15, 2025 •

Copy link
Copy Markdown

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

Project Deployment Review Updated (UTC)
inbox-zero Ready Ready Preview Dec 16, 2025 1:36am

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (3)
apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx (1)

7-7: LGTM! UI alignment change looks good.

The addition of justify-end appropriately aligns the AddRuleDialog button to the right, consistent with the PR's UI refactoring goals.

Optionally verify the mobile UX—the button will remain right-aligned on smaller screens. If centering or full-width alignment is preferred on mobile, consider adding responsive classes like justify-center sm:justify-end or similar.

apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx (2)

96-101: Prefer the wrapper Tooltip component for better mobile support.

The code uses raw shadcn Tooltip components directly. The project has a wrapper component at @/components/Tooltip.tsx that adds mobile click-to-toggle functionality, improving UX on touch devices.

Apply this diff to use the wrapper component:

 import { Card } from "@/components/ui/card";
-import {
-  Tooltip,
-  TooltipContent,
-  TooltipTrigger,
-} from "@/components/ui/tooltip";
+import { Tooltip } from "@/components/Tooltip";
 import { formatStat } from "@/utils/stats";

 // ... in the render:
                 {item.tooltip && (
-                  <Tooltip>
-                    <TooltipTrigger asChild>
-                      <InfoIcon className="h-4 w-4 cursor-pointer text-gray-400 hover:text-gray-500" />
-                    </TooltipTrigger>
-                    <TooltipContent>{item.tooltip}</TooltipContent>
-                  </Tooltip>
+                  <Tooltip content={item.tooltip}>
+                    <InfoIcon className="h-4 w-4 cursor-pointer text-gray-400 hover:text-gray-500" />
+                  </Tooltip>
                 )}

86-86: Consider using a stable key instead of array index.

While using index as a key works for static arrays, using a stable identifier like item.title would be more maintainable if the items array becomes dynamic in the future.

-            <div key={index} className="flex-1 p-6">
+            <div key={item.title} className="flex-1 p-6">
📜 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 e30a17f and 9543c3d.

📒 Files selected for processing (5)
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx (1 hunks)
  • apps/web/components/Combobox.tsx (0 hunks)
  • apps/web/components/SideNav.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/components/Combobox.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/web/components/SideNav.tsx
🧰 Additional context used
📓 Path-based instructions (13)
apps/web/**/*.{ts,tsx}

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
apps/web/**/*.tsx

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

apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
apps/web/app/(app)/**/*.{ts,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.{ts,tsx,js,jsx}

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.{tsx,ts}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.{tsx,ts,css}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.tsx

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
**/*.{js,ts,jsx,tsx}

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

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

Files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx (2)
apps/web/components/new-landing/common/Card.tsx (1)
  • Card (67-105)
apps/web/components/Tooltip.tsx (1)
  • Tooltip (18-41)
⏰ 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: test
🔇 Additional comments (1)
apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx (1)

13-50: LGTM! Well-structured type definitions.

The variants object and type definitions are clean, with good dark mode support and flexible design that allows either predefined variants or custom colors.

Comment thread apps/web/app/(app)/[emailAccountId]/setup/StatsCardGrid.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)

279-284: Missing ElementType import causes potential runtime issues

The code uses React.ElementType at line 283, but ElementType is not imported from React. While this works because React is implicitly available through JSX transform, it's inconsistent with the project's import patterns and could fail in strict ESM environments.

Apply this diff:

-import { useCallback, useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useState, type ElementType } from "react";

Then update the type:

-      icon: React.ElementType;
+      icon: ElementType;

561-565: Empty catch block loses error context for debugging

The catch block swallows the error without logging, making it difficult to debug failed delete operations.

-} catch {
+} catch (error) {
+  console.error("Failed to delete rule:", error);
   toastError({ description: "Failed to delete rule." });
 }
🧹 Nitpick comments (7)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (3)

419-427: Consider using the Input component with autosizeTextarea prop

Per coding guidelines, text areas should use the Input component with autosizeTextarea prop for consistency and form integration. The current TextareaAutosize usage bypasses the project's standard form input patterns.

-<TextareaAutosize
-  className="block w-full flex-1 whitespace-pre-wrap rounded-md border border-border bg-background shadow-sm focus:border-black focus:ring-black sm:text-sm"
-  minRows={3}
-  rows={3}
-  {...register(`conditions.${index}.instructions`)}
-  placeholder="e.g. Newsletters, regular content from publications, blogs, or services I've subscribed to"
-/>
+<Input
+  type="text"
+  autosizeTextarea
+  rows={3}
+  name={`conditions.${index}.instructions`}
+  registerProps={register(`conditions.${index}.instructions`)}
+  placeholder="e.g. Newsletters, regular content from publications, blogs, or services I've subscribed to"
+/>

253-271: Duplicate type validation could be extracted into a reusable helper

The duplicate checking logic is inline and moderately complex. Consider extracting it for testability and reuse:

function hasDuplicateUITypes(
  conditions: ZodCondition[],
  index: number,
  newValue: UIConditionType
): boolean {
  const prospectiveUITypes = conditions.map((c, idx) =>
    idx === index ? newValue : getUIConditionType(c)
  );
  const configuredTypes = prospectiveUITypes.filter(
    (type): type is UIConditionType => type !== undefined
  );
  return new Set(configuredTypes).size !== configuredTypes.length;
}

277-300: Complex array reordering when selecting "prompt" at non-first position

The logic to move an AI Prompt to position 0 when selected elsewhere is intricate. While functionally correct, consider:

  1. Adding a comment explaining why AI Prompt must be first
  2. The condition at line 290-293 may keep an empty condition in the array when currentConditionType !== undefined

The current behavior appears intentional but could be clearer.

apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)

528-567: Delete confirmation uses native confirm() dialog

The delete flow uses window.confirm() which is functional but inconsistent with the rest of the UI that uses shadcn/ui Dialog components. For a more polished UX, consider using a confirmation Dialog component.


440-442: Use stable keys instead of array index for error list items

Using array index as key (action-${index}) can cause rendering issues if errors are reordered. Since error messages should be unique, consider using the message itself:

-{actionErrors.map((error, index) => (
-  <li key={`action-${index}`}>{error}</li>
+{actionErrors.map((error) => (
+  <li key={error}>{error}</li>
))}
apps/web/utils/condition.ts (2)

117-139: Shape consistency improved between getConditions and getEmptyCondition

The getEmptyCondition for STATIC now includes instructions: null (line 132), matching the shape produced by getConditions. This addresses the shape inconsistency noted in previous reviews.

However, the AI case at lines 120-123 still omits the from, to, subject, body fields while getConditions includes them as null. Consider adding explicit null fields for full consistency:

     case ConditionType.AI:
       return {
         type: ConditionType.AI,
         instructions: "",
+        from: null,
+        to: null,
+        subject: null,
+        body: null,
       };

149-171: flattenConditions silently overwrites duplicate field values

When multiple STATIC conditions have the same field populated (e.g., two conditions with from values), only the last one is kept. With the new UI design where each STATIC condition has exactly one field, this shouldn't happen in practice—but the function doesn't guard against it.

Consider adding validation or a warning:

 case ConditionType.STATIC:
-  acc.to = condition.to;
-  acc.from = condition.from;
-  acc.subject = condition.subject;
-  acc.body = condition.body;
+  if (condition.to) {
+    if (acc.to) logger.warn("Overwriting existing 'to' condition");
+    acc.to = condition.to;
+  }
+  if (condition.from) {
+    if (acc.from) logger.warn("Overwriting existing 'from' condition");
+    acc.from = condition.from;
+  }
+  if (condition.subject) {
+    if (acc.subject) logger.warn("Overwriting existing 'subject' condition");
+    acc.subject = condition.subject;
+  }
+  if (condition.body) {
+    if (acc.body) logger.warn("Overwriting existing 'body' condition");
+    acc.body = condition.body;
+  }
   break;
📜 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 9543c3d and 39d3dc9.

📒 Files selected for processing (6)
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (6 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx (1 hunks)
  • apps/web/components/Input.tsx (1 hunks)
  • apps/web/utils/actions/rule.validation.ts (1 hunks)
  • apps/web/utils/condition.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleStep.tsx
🧰 Additional context used
📓 Path-based instructions (18)
apps/web/**/*.{ts,tsx}

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.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 for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/components/**/*.tsx

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

apps/web/components/**/*.tsx: Use React Hook Form with Zod validation for form components
Use result?.serverError with toastError and toastSuccess for error handling in form submissions

Use LoadingContent component to consistently handle loading and error states, passing loading, error, and children props

Use PascalCase for component file names (e.g., components/Button.tsx)

Files:

  • apps/web/components/Input.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/{pages,routes,components}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/gmail-api.mdc)

Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder

Files:

  • apps/web/components/Input.tsx
**/*.{ts,tsx,js,jsx}

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

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

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{tsx,ts}

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

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{tsx,ts,css}

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

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.tsx

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

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

Files:

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{jsx,tsx}

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

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,ts,jsx,tsx}

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

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

Files:

  • apps/web/components/Input.tsx
  • apps/web/utils/condition.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/{server,api,actions,utils}/**/*.ts

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

**/{server,api,actions,utils}/**/*.ts: Use createScopedLogger from "@/utils/logger" for logging in backend code
Add the createScopedLogger instantiation at the top of the file with an appropriate scope name
Use .with() method to attach context variables only within specific functions, not on global loggers
For large functions with reused variables, use createScopedLogger().with() to attach context once and reuse the logger without passing variables repeatedly

Files:

  • apps/web/utils/condition.ts
**/*.ts

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

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

Files:

  • apps/web/utils/condition.ts
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/**/*.{ts,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*Form.{ts,tsx}

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

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧠 Learnings (37)
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For text inputs, use the `Input` component with `registerProps` for form integration and error handling

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text areas in forms, use the `Input` component with `type='text'`, `autosizeTextarea` prop, `rows`, `name`, `placeholder`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.tsx : For text areas, use the `Input` component with `type='text'`, `autosizeTextarea` prop set to true, and `registerProps` for form integration

Applied to files:

  • apps/web/components/Input.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields in the UI

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure label elements have text content and are associated with an input

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in form submissions

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use semantic elements instead of role attributes in JSX

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Handle form submission results using `result?.serverError` to show error toasts and `toastSuccess` to show success messages after server action completion

Applied to files:

  • apps/web/components/Input.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use constant expressions in conditions

Applied to files:

  • apps/web/utils/condition.ts
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use duplicate conditions in if-else-if chains

Applied to files:

  • apps/web/utils/condition.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must follow a standard structure: accept options with `inputData` and `emailAccount` parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use `createGenerateObject` to execute the LLM call

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use proper error handling with try/catch blocks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `SafeError` for error responses to prevent information disclosure - provide generic messages (e.g., 'Rule not found' not 'Rule {id} does not exist for user {userId}') without revealing internal IDs or ownership details

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't reassign exceptions in catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Always include a `type` attribute for button elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use valid, non-abstract ARIA roles for elements with ARIA roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Make sure all dependencies are correctly specified in React hooks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make static elements with click handlers use a valid role attribute

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure ARIA properties are valid for the element's supported roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Watch out for possible "wrong" semicolons inside JSX elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission using React Hook Form and Zod resolver

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Use React Hook Form with Zod validation (`zodResolver`) for form handling, with form components using `register`, `handleSubmit`, and error handling from the hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for form validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for validation in form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-09T19:50:05.292Z
Learnt from: ppranay20
Repo: elie222/inbox-zero PR: 935
File: apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx:367-369
Timestamp: 2025-11-09T19:50:05.292Z
Learning: In React Hook Form, when using `useMemo` or `useEffect` with form errors, always use `formState` as the dependency rather than `errors` or `formState.errors`. This is because React Hook Form uses a Proxy pattern where the errors object is mutable and won't trigger dependency arrays correctly. The formState dependency ensures proper reactivity when form validation state changes.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧬 Code graph analysis (1)
apps/web/utils/condition.ts (1)
apps/web/utils/config.ts (2)
  • ConditionType (14-19)
  • ConditionType (21-21)
⏰ 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: test
🔇 Additional comments (8)
apps/web/components/Input.tsx (1)

143-143: LGTM – Styling simplified for consistency.

The removal of font-semibold and leading-snug streamlines the error message styling while preserving visibility through the red color. This aligns with the PR's goal of consistent typography across the new card-based UI components.

apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (2)

165-176: useEffect still has edge-case data loss potential

The current implementation only sets a prompt condition when uiType === undefined, which is an improvement from the earlier version. However, there's still a subtle issue: if a rule is loaded with conditions where conditions[0] exists but has all fields null (which getConditionFromUIType(undefined) produces), this will get replaced with a prompt condition, potentially not matching user intent.

Consider adding a more explicit check or documenting this behavior:

   useEffect(() => {
     if (conditions.length > 0) {
       const firstCondition = conditions[0];
       const uiType = getUIConditionType(firstCondition);
       // Only set to prompt if the condition is empty (undefined type)
       // Don't replace existing static conditions (from/to/subject)
-      if (uiType === undefined) {
+      // Also check if this is a freshly added empty condition vs loaded data
+      if (uiType === undefined && firstCondition.type !== ConditionType.AI) {
         const promptCondition = getConditionFromUIType("prompt");
         setValue("conditions.0", promptCondition);
       }
     }
   }, [conditions, setValue]);

546-547: Tooltip text function is well-structured

The getFilterTooltipText helper provides consistent, informative tooltip content for filter types.

apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (3)

392-428: Well-structured conditional rendering for rule sections

The RuleSectionCard wrapper with conditional content based on isConversationStatusType provides clear separation of concerns. The error display integration is clean.


253-256: React Hook Form dependency on conditions in useEffect

The useEffect that triggers validation has a suppressed exhaustive-deps warning. Per learnings, when using form state in effects, prefer using formState as the dependency rather than derived values like conditions. However, since this is triggering validation (not reading errors), the current approach is acceptable.


273-277: Error handling is properly separated between form-level and field-specific errors

The current implementation is correct and intentional. formErrors captures only top-level errors with a direct message property (like validation on the name field). Array-level errors for conditions and actions are handled separately and explicitly:

  • conditions array errors display via errors.conditions?.root?.message (line 397)
  • actions array errors extract via actionErrors which accesses errors?.actions?.[index]?.{url,labelId,to}?.root?.message (lines 258-268)

This is proper separation of concerns. No changes needed.

apps/web/utils/condition.ts (2)

57-99: Well-structured STATIC condition splitting

The new approach of creating separate STATIC conditions for each populated field aligns well with the UI design where each condition row handles a single field. The explicit null values for unused fields maintain type consistency.


46-55: AI condition now includes explicit null fields

Good improvement—the AI condition object now includes explicit from: null, to: null, subject: null, body: null fields, ensuring consistent shape with STATIC conditions and preventing potential undefined property access.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)

279-284: Add missing ElementType import.

This is still using React.ElementType without importing it. As flagged in the previous review, you need to import ElementType from React.

Apply this diff:

-import { useCallback, useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useState, type ElementType } from "react";

And update the type definition:

   const typeOptions = useMemo(() => {
     const options: {
       label: string;
       value: ActionType;
-      icon: React.ElementType;
+      icon: ElementType;
     }[] = [

528-567: Empty catch block loses error context.

The catch block at line 561 swallows the error without logging it, making debugging difficult if the delete operation fails for unexpected reasons. This was flagged in the previous review.

Apply this diff:

-                        } catch {
+                        } catch (error) {
+                          console.error("Failed to delete rule:", error);
                           toastError({ description: "Failed to delete rule." });
📜 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 39d3dc9 and 6b10a0d.

📒 Files selected for processing (3)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (7 hunks)
  • apps/web/utils/ai/assistant/process-user-request.ts (1 hunks)
  • version.txt (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • version.txt
🧰 Additional context used
📓 Path-based instructions (18)
apps/web/**/*.{ts,tsx}

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts

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

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
apps/web/utils/ai/**/*.ts

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

apps/web/utils/ai/**/*.ts: LLM feature functions must import from zod for schema validation, use createScopedLogger from @/utils/logger, chatCompletionObject and createGenerateObject from @/utils/llms, and import EmailAccountWithAI type from @/utils/llms/types
LLM feature functions must follow a standard structure: accept options with inputData and emailAccount parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use createGenerateObject to execute the LLM call
System prompts must define the LLM's role and task specifications
User prompts must contain the actual data and context, and should be kept separate from system prompts
Always define a Zod schema for LLM response validation and make schemas as specific as possible to guide the LLM output
Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using withRetry
Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions
Use TypeScript types for all LLM function parameters and return values, and define clear interfaces for complex input/output structures
Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
**/{server,api,actions,utils}/**/*.ts

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

**/{server,api,actions,utils}/**/*.ts: Use createScopedLogger from "@/utils/logger" for logging in backend code
Add the createScopedLogger instantiation at the top of the file with an appropriate scope name
Use .with() method to attach context variables only within specific functions, not on global loggers
For large functions with reused variables, use createScopedLogger().with() to attach context once and reuse the logger without passing variables repeatedly

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
**/*.{ts,tsx,js,jsx}

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

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

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.ts

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

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
**/*.{tsx,ts}

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

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{tsx,ts,css}

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

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

Files:

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,ts,jsx,tsx}

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

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

Files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • 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 for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*Form.{ts,tsx}

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

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.tsx

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧠 Learnings (37)
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : System prompts must define the LLM's role and task specifications

Applied to files:

  • apps/web/utils/ai/assistant/process-user-request.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

  • apps/web/utils/ai/assistant/process-user-request.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Applied to files:

  • apps/web/utils/ai/assistant/process-user-request.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must follow a standard structure: accept options with `inputData` and `emailAccount` parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use `createGenerateObject` to execute the LLM call

Applied to files:

  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Handle form submission results using `result?.serverError` to show error toasts and `toastSuccess` to show success messages after server action completion

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use proper error handling with try/catch blocks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `SafeError` for error responses to prevent information disclosure - provide generic messages (e.g., 'Rule not found' not 'Rule {id} does not exist for user {userId}') without revealing internal IDs or ownership details

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't reassign exceptions in catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in form submissions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use semantic elements instead of role attributes in JSX

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Always include a `type` attribute for button elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use valid, non-abstract ARIA roles for elements with ARIA roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make static elements with click handlers use a valid role attribute

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Make sure all dependencies are correctly specified in React hooks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure label elements have text content and are associated with an input

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text areas in forms, use the `Input` component with `type='text'`, `autosizeTextarea` prop, `rows`, `name`, `placeholder`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure ARIA properties are valid for the element's supported roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Watch out for possible "wrong" semicolons inside JSX elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission using React Hook Form and Zod resolver

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Use React Hook Form with Zod validation (`zodResolver`) for form handling, with form components using `register`, `handleSubmit`, and error handling from the hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for form validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for validation in form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields in the UI

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-09T19:50:05.292Z
Learnt from: ppranay20
Repo: elie222/inbox-zero PR: 935
File: apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx:367-369
Timestamp: 2025-11-09T19:50:05.292Z
Learning: In React Hook Form, when using `useMemo` or `useEffect` with form errors, always use `formState` as the dependency rather than `errors` or `formState.errors`. This is because React Hook Form uses a Proxy pattern where the errors object is mutable and won't trigger dependency arrays correctly. The formState dependency ensures proper reactivity when form validation state changes.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For text inputs, use the `Input` component with `registerProps` for form integration and error handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (5)
apps/web/utils/action-display.tsx (1)
  • getActionIcon (86-115)
apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx (1)
  • RuleSectionCard (5-37)
apps/web/utils/reply-tracker/conversation-status-config.ts (1)
  • isConversationStatusType (16-22)
apps/web/utils/rule/consts.ts (1)
  • getRuleConfig (112-116)
apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1)
  • ActionSteps (46-107)
⏰ 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: test
🔇 Additional comments (1)
apps/web/utils/ai/assistant/process-user-request.ts (1)

90-90: LGTM! URL updated to reflect the new rules UI location.

The URL path change from /assistant?tab=rules to /automation?tab=rules aligns with the rules UI refactoring described in the PR objectives.

Comment thread apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (1)

319-361: Remove redundant mutate() calls in delete handler.

The delete handler calls mutate() three times:

  1. Via the onSettled callback of the useAction hook (line 89)
  2. On line 343 after successful deletion
  3. In the finally block on line 351

Since onSettled already handles revalidation for all outcomes, the mutate() calls on lines 343 and 351 are redundant. While SWR deduplicates requests, removing these unnecessary calls improves clarity.

Apply this diff:

                                          toast.promise(
                                            async () => {
                                              const res = await deleteRule({
                                                id: rule.id,
                                              });

                                              if (
                                                res?.serverError ||
                                                res?.validationErrors
                                              ) {
                                                throw new Error(
                                                  res?.serverError ||
                                                    "There was an error deleting your rule",
                                                );
                                              }
-
-                                             mutate();
                                            },
                                            {
                                              loading: "Deleting rule...",
                                              success: "Rule deleted",
                                              error: (error) =>
                                                `Error deleting rule. ${error.message}`,
-                                             finally: () => {
-                                               mutate();
-                                             },
                                            },
                                          );
📜 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 6b10a0d and 7357a21.

📒 Files selected for processing (2)
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (6 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(app)/[emailAccountId]/assistant/RulesTabNew.tsx
🧰 Additional context used
📓 Path-based instructions (13)
apps/web/**/*.{ts,tsx}

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • 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 for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
apps/web/app/(app)/**/*.{ts,tsx}

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

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

Files:

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
**/*.{tsx,ts}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
**/*.{tsx,ts,css}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
**/*.tsx

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
**/*.{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
🧠 Learnings (19)
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:36:33.376Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/cursor-rules.mdc:0-0
Timestamp: 2025-11-25T14:36:33.376Z
Learning: Applies to .cursor/rules/**/*.mdc : Make cursor rule filenames descriptive of the rule's purpose

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Use the `LoadingContent` component to handle loading states

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use LoadingContent component for async data with loading and error states

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*.tsx : Use `LoadingContent` component to consistently handle loading and error states, passing `loading`, `error`, and `children` props

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) that wrap `useSWR`, handle the API endpoint URL, and return data, loading state, error state, and the `mutate` function

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) to wrap `useSWR` for individual API endpoints

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use `next-safe-action` with `actionClient` for server actions with Zod schema validation

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Use the `use` prefix for custom hook filenames (e.g., `useAccounts.ts`)

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in `apps/web/utils/actions/*.validation.ts`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (4)
apps/web/utils/rule/rule.ts (1)
  • deleteRule (244-260)
apps/web/app/api/user/rules/route.ts (1)
  • RulesResponse (5-5)
apps/web/components/Tooltip.tsx (1)
  • Tooltip (18-41)
apps/web/utils/condition.ts (1)
  • conditionsToString (200-217)
⏰ 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: test
🔇 Additional comments (4)
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (4)

13-13: LGTM! Import and header changes align with refactoring objectives.

The new imports (FilterIcon, Tooltip, conditionsToString) are properly used in the StaticConditionsIcon component, and the table header restructure correctly replaces the Conditions column with an Action column as described in the PR objectives.

Also applies to: 53-54, 147-150


411-411: LGTM! ActionBadges alignment change.

The justify-start alignment correctly positions the action badges to the left as specified in the PR objectives.


240-318: LGTM! Action menu restructure is well-implemented.

The new dropdown menu structure provides clear actions:

  • Edit manually opens the rule dialog in edit mode
  • Edit via AI pre-fills the chat with rule context (properly gated for system rules)
  • Duplicate opens the dialog with a rule copy
  • History navigates correctly based on rule type

The conditional rendering logic and event handling are appropriate.


454-466: LGTM! Helper functions are well-structured.

The hasStaticConditions helper correctly identifies rules with static conditions, and StaticConditionsIcon provides a clean UI indicator with tooltip showing the condition details via conditionsToString.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

523-573: Empty catch block loses error context.

The catch block at line 563 doesn't capture the error parameter, making debugging difficult if the delete operation fails for unexpected reasons. This was noted in a previous review.

Apply this diff:

-                        } catch {
+                        } catch (error) {
+                          console.error("Failed to delete rule:", error);
                           toastError({ description: "Failed to delete rule." });
                         } finally {
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

281-286: Consider importing ElementType separately.

While React.ElementType works, TypeScript best practice is to import ElementType as a type directly from React. This was noted in a previous review comment.

Apply this diff:

-import { useCallback, useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useState, type ElementType } from "react";

Then update line 285:

-      icon: React.ElementType;
+      icon: ElementType;
📜 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 7357a21 and c1c2e2c.

📒 Files selected for processing (2)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (8 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (6 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
Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type files

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**/*.{ts,tsx}

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

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.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 for class sorting
Prefer functional components with hooks over class components
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Use LoadingContent component for async data with loading and error states

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/**/*.{ts,tsx}

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

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

Files:

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

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{tsx,ts}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{tsx,ts,css}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.tsx

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

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

Files:

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{jsx,tsx}

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
!(pages/_document).{jsx,tsx}

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

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

Files:

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

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

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

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*Form.{ts,tsx}

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

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧠 Learnings (45)
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) that wrap `useSWR`, handle the API endpoint URL, and return data, loading state, error state, and the `mutate` function

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`) to wrap `useSWR` for individual API endpoints

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use `next-safe-action` with `actionClient` for server actions with Zod schema validation

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:35.343Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:35.343Z
Learning: Applies to apps/web/hooks/use*.ts : Use the `use` prefix for custom hook filenames (e.g., `useAccounts.ts`)

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in `apps/web/utils/actions/*.validation.ts`

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Handle form submission results using `result?.serverError` to show error toasts and `toastSuccess` to show success messages after server action completion

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must follow a standard structure: accept options with `inputData` and `emailAccount` parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use `createGenerateObject` to execute the LLM call

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use proper error handling with try/catch blocks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `SafeError` for error responses to prevent information disclosure - provide generic messages (e.g., 'Rule not found' not 'Rule {id} does not exist for user {userId}') without revealing internal IDs or ownership details

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't reassign exceptions in catch clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in form submissions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use semantic elements instead of role attributes in JSX

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Always include a `type` attribute for button elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use valid, non-abstract ARIA roles for elements with ARIA roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make static elements with click handlers use a valid role attribute

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Make sure all dependencies are correctly specified in React hooks

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure label elements have text content and are associated with an input

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text areas in forms, use the `Input` component with `type='text'`, `autosizeTextarea` prop, `rows`, `name`, `placeholder`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure ARIA properties are valid for the element's supported roles

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Watch out for possible "wrong" semicolons inside JSX elements

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-09T19:50:05.292Z
Learnt from: ppranay20
Repo: elie222/inbox-zero PR: 935
File: apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx:367-369
Timestamp: 2025-11-09T19:50:05.292Z
Learning: In React Hook Form, when using `useMemo` or `useEffect` with form errors, always use `formState` as the dependency rather than `errors` or `formState.errors`. This is because React Hook Form uses a Proxy pattern where the errors object is mutable and won't trigger dependency arrays correctly. The formState dependency ensures proper reactivity when form validation state changes.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Use React Hook Form with Zod validation (`zodResolver`) for form handling, with form components using `register`, `handleSubmit`, and error handling from the hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission using React Hook Form and Zod resolver

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for form validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for validation in form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields in the UI

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Show validation errors inline next to form fields

Applied to files:

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

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For text inputs, use the `Input` component with `registerProps` for form integration and error handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
🧬 Code graph analysis (2)
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (4)
apps/web/utils/rule/rule.ts (1)
  • deleteRule (244-260)
apps/web/app/api/user/rules/route.ts (1)
  • RulesResponse (5-5)
apps/web/components/Tooltip.tsx (1)
  • Tooltip (18-41)
apps/web/utils/condition.ts (1)
  • conditionsToString (200-217)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (8)
apps/web/utils/action-display.tsx (1)
  • getActionIcon (86-115)
apps/web/app/(app)/[emailAccountId]/assistant/RuleSectionCard.tsx (1)
  • RuleSectionCard (5-37)
apps/web/utils/reply-tracker/conversation-status-config.ts (1)
  • isConversationStatusType (16-22)
apps/web/utils/rule/consts.ts (1)
  • getRuleConfig (112-116)
apps/web/app/(app)/[emailAccountId]/assistant/ConditionSteps.tsx (1)
  • ConditionSteps (129-544)
apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1)
  • ActionSteps (46-107)
apps/web/app/(app)/[emailAccountId]/assistant/group/LearnedPatterns.tsx (1)
  • LearnedPatternsDialog (21-96)
apps/web/utils/actions/rule.ts (1)
  • deleteRuleAction (237-261)
⏰ 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: test
🔇 Additional comments (11)
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (5)

13-14: LGTM!

The new imports for icons and tooltip functionality are correctly placed and used by the StaticConditionsIcon component.

Also applies to: 54-55


148-151: LGTM!

The table header changes properly reflect the new UI structure, replacing the Condition column with an Action column and adjusting the sizing for the action menu.


234-240: LGTM!

The ActionBadges rendering is correctly aligned to the left, matching the column header, and receives all necessary props.


412-428: LGTM!

The justify-start alignment in the flex container correctly positions the action badges to the left, matching the column header alignment.


455-476: LGTM!

The helper functions correctly identify AI and static conditions, and the StaticConditionsIcon component properly displays icons with a tooltip showing the formatted condition string.

apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (6)

128-128: LGTM!

The form state destructuring correctly extracts formState and uses it for errors and submission state. The useFieldArray setup for actions follows the standard React Hook Form pattern.

Also applies to: 132-132, 142-146


260-270: LGTM!

The actionErrors memoization correctly uses formState as a dependency and properly extracts error messages from action validation errors.


275-279: LGTM!

The formErrors memoization correctly uses formState as a dependency (addressing the previous review comment) and properly extracts error messages with type-safe filtering.


357-468: LGTM!

The form structure refactoring with RuleSectionCard components creates a clean, modular UI. The sections are well-organized with proper error handling, and the conditional rendering for conversation status rules is correctly implemented.


578-603: LGTM!

The action buttons layout is clean and properly handles the conditional rendering of Cancel, Save, and Create buttons with appropriate loading and disabled states.


5-5: No action needed on this import change. The Input component import path change from @/components/ui/input to @/components/Input is correct. The custom Input component at @/components/Input provides proper form integration with registerProps, error handling via FieldError, and textarea support with autosizeTextarea—all required for form components per the coding guidelines.

Comment on lines +320 to +362
{!isColdEmailBlocker &&
!isConversationStatus && (
<DropdownMenuItem
onClick={async () => {
const yes = confirm(
`Are you sure you want to delete the rule "${rule.name}"?`,
);
if (yes) {
toast.promise(
async () => {
const res = await deleteRule({
id: rule.id,
});

if (
res?.serverError ||
res?.validationErrors
) {
throw new Error(
res?.serverError ||
"There was an error deleting your rule",
);
}

mutate();
},
{
loading: "Deleting rule...",
success: "Rule deleted",
error: (error) =>
`Error deleting rule. ${error.message}`,
finally: () => {
mutate();
},
},
);
}
}}
>
<Trash2Icon className="mr-2 size-4" />
Delete
</DropdownMenuItem>
)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check deleteRule action implementation and error handling patterns
rg -nP --type=ts -A 20 'export const deleteRule' apps/web/utils/actions/rule.ts

Repository: elie222/inbox-zero

Length of output: 854


🏁 Script executed:

#!/bin/bash
# Get more context of the deleteRuleAction, especially the catch block
rg -nP --type=ts -A 35 'export const deleteRuleAction' apps/web/utils/actions/rule.ts | head -50

Repository: elie222/inbox-zero

Length of output: 1422


🏁 Script executed:

#!/bin/bash
# Check the validation schema for deleteRuleAction
rg -nP --type=ts -B5 'deleteRuleBody' apps/web/utils/actions/rule.ts | head -20

Repository: elie222/inbox-zero

Length of output: 368


🏁 Script executed:

#!/bin/bash
# Check the validation schema file for deleteRuleBody
rg -nP --type=ts 'deleteRuleBody' apps/web/utils/actions/rule.validation.ts

Repository: elie222/inbox-zero

Length of output: 125


🏁 Script executed:

#!/bin/bash
# Check the SafeError implementation and how next-safe-action handles errors
rg -nP --type=ts 'class SafeError' . --max-count=5

Repository: elie222/inbox-zero

Length of output: 129


🏁 Script executed:

#!/bin/bash
# Check the SafeError implementation
rg -nP --type=ts -A 10 'export class SafeError' apps/web/utils/error.ts

Repository: elie222/inbox-zero

Length of output: 369


🏁 Script executed:

#!/bin/bash
# Check how toastError/toastSuccess are used elsewhere in the codebase
rg -nP --type=tsx 'toastError|toastSuccess' apps/web/app/\(app\)/\[emailAccountId\]/assistant/ -A 2 | head -30

Repository: elie222/inbox-zero

Length of output: 89


🏁 Script executed:

#!/bin/bash
# Check how errors are handled in other parts of the codebase with server actions
rg -nP --type=ts 'toast\.(promise|error|success)' apps/web/app -A 3 | head -40

Repository: elie222/inbox-zero

Length of output: 3750


🏁 Script executed:

#!/bin/bash
# Check how next-safe-action returns errors vs validation errors
rg -nP --type=ts 'validationErrors' apps/web/utils/actions/rule.ts -B 3 -A 3

Repository: elie222/inbox-zero

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Check how next-safe-action errors are handled at the client
rg -nP --type=ts 'serverError|validationErrors' apps/web/app/\(app\)/\[emailAccountId\]/assistant/Rules.tsx -B 2 -A 2

Repository: elie222/inbox-zero

Length of output: 1062


🏁 Script executed:

#!/bin/bash
# Check if there are similar delete/action patterns with better error handling
rg -nP --type=ts 'serverError' apps/web/app/\(app\)/\[emailAccountId\]/assistant/Rules.tsx -B 3 -A 3 | head -50

Repository: elie222/inbox-zero

Length of output: 1216


Remove unnecessary validationErrors check and use toastError for consistency.

The validationErrors check is unnecessary since deleteRuleBody only validates a simple string ID that won't produce meaningful validation errors. Additionally, the error handling pattern here should match the pattern used elsewhere in the same file (line 218-223): use toastError directly with result?.serverError instead of throwing within toast.promise, as indicated by the data-fetching guidelines.

🤖 Prompt for AI Agents
In apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx around lines 320 to
362, remove the unnecessary check for result?.validationErrors inside the delete
flow and replace the current throw-based error handling in toast.promise with
the consistent pattern used elsewhere: call toastError(result?.serverError) when
the deleteRule response has a serverError, avoid throwing from within the
toast.promise callback, and keep mutate() in the promise's finally handler so
the UI refreshes whether the call succeeded or failed.

@elie222
elie222 merged commit fc6b703 into elie222:main Dec 16, 2025
18 checks passed

This branch was successfully deployed

1 active deployment
Preview — c1c2e2cd Deployed Dec 16, 2025 by vercel[bot]
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.

2 participants