Skip to content

feat(ui): Implements the requested "Regenerate Writing Style" feature (#1231).#1248

Closed
CODEAbhinav-art wants to merge 5 commits intoelie222:mainfrom
CODEAbhinav-art:main
Closed

feat(ui): Implements the requested "Regenerate Writing Style" feature (#1231).#1248
CODEAbhinav-art wants to merge 5 commits intoelie222:mainfrom
CODEAbhinav-art:main

Conversation

@CODEAbhinav-art
Copy link

@CODEAbhinav-art CODEAbhinav-art commented Jan 11, 2026

Implementation Details

Backend: Added regenerateWritingStyleAction to assess.ts. This reuses the existing aiAnalyzeWritingStyle logic but returns the string payload instead of saving to the DB.

Frontend: Updated WritingStyleSetting to include a "Regenerate" button using the variant="outline" style.

State Management: Implemented useAction hooks to handle the loading state (disabling the button) and onSuccess state (updating the form via setValue without persisting).

Test Plan

Build Verification: Verified the app compiles and starts locally (pnpm dev) with no type errors.

Code Analysis: Confirmed the import paths and function signatures match the existing assess.ts and user.ts patterns.

Runtime Note: I performed a static verification of the logic. I could not perform a full end-to-end execution of the generation flow because the local environment lacks the necessary GOOGLE_CLIENT_ID for login and OPENAI_API_KEY for the generation service.

The logic is a safe, direct transposition of the existing analyzeWritingStyleAction but adapted for a non-persisting return type.

Summary by CodeRabbit

  • New Features

    • Added a "Regenerate Style" button in Writing Style settings to recompute your style from recent sent emails (last ~20), with loading spinner, idle sparkles, success/error toasts, and disabled state while running or saving.
    • Preserved existing Save flow; buttons now appear side-by-side (Regenerate outline, Save primary), aligned right.
  • Style

    • Simplified editor placeholder styling, updated placeholder/copy, and enforced a max length on regenerated content.

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

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


CODEAbhinav-art seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

📝 Walkthrough

Walkthrough

Adds a regenerate flow for the Writing Style setting: UI button triggers a new server action that fetches the last 20 sent emails, reanalyzes writing style, returns a formatted string, and updates the form/editor while showing success or error toasts.

Changes

Cohort / File(s) Summary
UI — Writing Style Setting
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
Adds Regenerate Style (outline) button and isGenerating state; shows Loader2 while generating and Sparkles when idle; disables controls during generation/saving; uses setValue to update writingStyle and the Tiptap editor (truncates to WRITING_STYLE_MAX_LENGTH); preserves existing Save flow; updates placeholder/class.
Server Action — Writing Style Regeneration
apps/web/utils/actions/assess.ts
Adds exported regenerateWritingStyleAction that loads the email account (with extra fields), creates the email provider, fetches the last 20 sent messages, calls aiAnalyzeWritingStyle, formats a multi-line writingStyle (Typical Length, Formality, Common Greeting, Notable Traits, Examples), and returns { writingStyle } with error handling.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as WritingStyleSetting
    participant Server as regenerateWritingStyleAction
    participant Provider as EmailProvider
    participant AI as aiAnalyzeWritingStyle

    User->>UI: Click "Regenerate Style"
    UI->>UI: set isGenerating = true, disable buttons
    UI->>Server: invoke regenerateWritingStyleAction(emailAccountId)
    Server->>Provider: load account & create provider
    Provider->>Provider: fetch last 20 sent emails
    Server->>AI: analyze messages for writing style
    AI->>Server: return style characteristics
    Server->>Server: format multi-line writingStyle string
    Server->>UI: return { writingStyle }
    UI->>UI: setValue("writingStyle"), update editor content (truncate if needed)
    UI->>UI: show success toast, set isGenerating = false
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • elie222
  • baz-reviewer

Poem

🐰✨ I nibbled drafts beneath the moonlit file,
Clicked “Regenerate” and hopped a happy mile,
A spinner twirled, then sparkles filled the air,
New phrasing brewed with gentle rabbit care,
Hop—your voice refined in a fluffy style.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature addition: implementing a 'Regenerate Writing Style' functionality. It is specific, concise, and clearly summarizes the primary change across both backend and frontend components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

@vercel
Copy link

vercel bot commented Jan 11, 2026

Someone is attempting to deploy a commit to the Inbox Zero OSS Program Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

83-97: Align regenerate error handling with save (surface actionable message)

Save uses getActionErrorMessage(error.error) but regenerate currently drops error detail. Keeping them consistent will reduce “unknown error” reports.

Also applies to: 104-109

📜 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 46dceb0 and 8be264e.

📒 Files selected for processing (2)
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
  • apps/web/utils/actions/assess.ts
🧰 Additional context used
📓 Path-based instructions (22)
**/*.{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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
apps/web/utils/actions/**/*.ts

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

apps/web/utils/actions/**/*.ts: Server actions must be located in apps/web/utils/actions folder
Server action files must start with use server directive

Files:

  • apps/web/utils/actions/assess.ts
apps/web/**/*.{ts,tsx}

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

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas using z.infer<typeof schema> instead of duplicating as separate interfaces

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
apps/web/utils/actions/*.ts

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

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
Use 'use server' directive at the top of server action implementation files
Implement all server actions using the next-safe-action library with actionClient, actionClientUser, or adminActionClient for type safety and validation
Use actionClientUser when only authenticated user context (userId) is needed
Use actionClient when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client
Use adminActionClient for actions restricted to admin users
Add metadata with a meaningful action name using .metadata({ name: "actionName" }) for Sentry instrumentation and monitoring
Use .schema() method with Zod validation schemas from corresponding .validation.ts files in next-safe-action configuration
Access context (userId, emailAccountId, etc.) via the ctx object parameter in the .action() handler
Use revalidatePath or revalidateTag from 'next/cache' within server action handlers when mutations modify data displayed elsewhere

apps/web/utils/actions/*.ts: Use next-safe-action with proper Zod validation for server actions
Server actions should use actionClient.metadata({ name: 'actionName' }).schema(schema).action(...) pattern
Call revalidatePath in server actions after successful mutations
Use revalidatePath in server actions for cache invalidation

Files:

  • apps/web/utils/actions/assess.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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')

**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
**/{utils,helpers,lib}/**/*.{ts,tsx}

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

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/actions/assess.ts
apps/web/utils/actions/!(*.validation).ts

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

apps/web/utils/actions/!(*.validation).ts: Use next-safe-action for all server actions with actionClient, .metadata(), .inputSchema(), and .action() chain pattern
Add 'use server' directive at the top of all server action files

Files:

  • apps/web/utils/actions/assess.ts
apps/web/**/*.{ts,tsx,js,jsx}

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

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Use getActionErrorMessage(error.error) from @/utils/error to extract user-friendly error messages

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
apps/web/**/*.{ts,tsx,css}

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

Follow tailwindcss patterns with prettier-plugin-tailwindcss

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx,json}

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

Client-side environment variables must be prefixed with NEXT_PUBLIC_

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}

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

Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
apps/web/**/*.{tsx,jsx}

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

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks
Use shadcn/ui components when available
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use useAction hook from next-safe-action/hooks with onSuccess and onError callbacks for form submission
Use LoadingContent component to handle loading and error states consistently
Call mutate() after successful mutations to refresh SWR data

Files:

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

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

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧠 Learnings (15)
📚 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/utils/actions/assess.ts
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/utils/actions/!(*.validation).ts : Use `next-safe-action` for all server actions with `actionClient`, `.metadata()`, `.inputSchema()`, and `.action()` chain pattern

Applied to files:

  • apps/web/utils/actions/assess.ts
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use `actionClient.metadata({ name: 'actionName' }).schema(schema).action(...)` pattern

Applied to files:

  • apps/web/utils/actions/assess.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with `zodResolver` for form validation, combining it with `useAction` hook from `next-safe-action/hooks` for server action execution

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use `useAction` hook with `onSuccess` and `onError` callbacks for handling server action responses in forms

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `useAction` hook from `next-safe-action/hooks` with `onSuccess` and `onError` callbacks for form submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T17:27:19.225Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1234
File: apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:65-83
Timestamp: 2026-01-09T17:27:19.225Z
Learning: In the elie222/inbox-zero repo, for React components using next-safe-action, using optimistic updates with mutate on success/error is an accepted approach to address race conditions in toggle handlers. It is acceptable for components not to guard rapid toggles with isExecuting (disable) when the optimistic UI state is reconciled by mutate. Apply this guidance to similar TSX components in the web app where appropriate.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use React Hook Form with Zod validation for form handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (5)
apps/web/utils/actions/user.validation.ts (2)
  • SaveWritingStyleBody (14-14)
  • saveWritingStyleBody (11-13)
apps/web/utils/actions/assess.ts (1)
  • regenerateWritingStyleAction (101-151)
apps/web/components/Toast.tsx (2)
  • toastSuccess (3-12)
  • toastError (14-19)
apps/web/utils/actions/user.ts (1)
  • saveWritingStyleAction (40-50)
apps/web/utils/error.ts (1)
  • getActionErrorMessage (325-346)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer

Comment on lines +101 to +151
export const regenerateWritingStyleAction = actionClient
.metadata({ name: "regenerateWritingStyle" })
.action(async ({ ctx: { emailAccountId, provider, logger } }) => {
const emailAccount = await prisma.emailAccount.findUnique({
where: { id: emailAccountId },
select: {
id: true,
userId: true,
email: true,
about: true,
multiRuleSelectionEnabled: true,
timezone: true,
calendarBookingLink: true,
user: { select: { aiProvider: true, aiModel: true, aiApiKey: true } },
},
});

if (!emailAccount) throw new SafeError("Email account not found");

const emailProvider = await createEmailProvider({
emailAccountId,
provider,
logger,
});
const sentMessages = await emailProvider.getSentMessages(20);

const style = await aiAnalyzeWritingStyle({
emails: sentMessages.map((email) =>
getEmailForLLM(email, { extractReply: true }),
),
emailAccount: { ...emailAccount, account: { provider } },
});

if (!style) return { writingStyle: "" };

const writingStyle = [
style.typicalLength ? `Typical Length: ${style.typicalLength}` : null,
style.formality ? `Formality: ${style.formality}` : null,
style.commonGreeting ? `Common Greeting: ${style.commonGreeting}` : null,
style.notableTraits.length
? `Notable Traits: ${formatBulletList(style.notableTraits)}`
: null,
style.examples.length
? `Examples: ${formatBulletList(style.examples)}`
: null,
]
.filter(Boolean)
.join("\n");

return { writingStyle };
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== 1) Inspect actionClient and action binding patterns ==="
fd -t f "safe-action.ts" apps/web/utils -x head -220 {}

echo
echo "=== 2) Check regenerateWritingStyleAction file for context ==="
cat -n apps/web/utils/actions/assess.ts | head -160

echo
echo "=== 3) How is analyzeWritingStyleAction invoked? ==="
rg -n "analyzeWritingStyleAction" apps/web --type ts --type tsx -B2 -A2

echo
echo "=== 4) How is regenerateWritingStyleAction invoked? ==="
rg -n "regenerateWritingStyleAction" apps/web --type ts --type tsx -B2 -A2

echo
echo "=== 5) Check if saveWritingStyleAction exists for comparison ==="
rg -n "saveWritingStyleAction|saveWritingStyleBody" apps/web --type ts --type tsx -B1 -A5 | head -80

Repository: elie222/inbox-zero

Length of output: 11353


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check how actions are invoked from client ==="
rg -n "regenerateWritingStyleAction|analyzeWritingStyleAction" apps/web --type ts -A3 -B3

echo
echo "=== Look for .execute( or serverAction( patterns ==="
rg -n "\.execute|serverAction" apps/web --type ts -A2 | grep -A2 -B2 "Writing\|writing"

echo
echo "=== Check for style formatting - is it duplicated? ==="
echo "Formatting pattern in analyzeWritingStyleAction:"
sed -n '79,91p' apps/web/utils/actions/assess.ts

echo
echo "Formatting pattern in regenerateWritingStyleAction:"
sed -n '136,148p' apps/web/utils/actions/assess.ts

echo
echo "=== Look for saveWritingStyleAction and its schema ==="
rg -n "saveWritingStyleAction|writingStyle.*max|saveWritingStyleBody" apps/web --type ts -B3 -A10

echo
echo "=== Search for component calling regenerateWritingStyleAction ==="
find apps/web -name "*.tsx" -o -name "*.ts" | xargs grep -l "regenerateWritingStyleAction" 2>/dev/null | head -5

Repository: elie222/inbox-zero

Length of output: 4167


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Full WritingStyleSetting.tsx usage around line 80 ==="
sed -n '75,95p' apps/web/app/\(app\)/\[emailAccountId\]/assistant/settings/WritingStyleSetting.tsx

echo
echo "=== Compare with analyzeWritingStyleAction binding in assess.tsx ==="
sed -n '20,25p' apps/web/app/\(app\)/\[emailAccountId\]/assess.tsx

echo
echo "=== Check saveWritingStyleBody schema ==="
rg -n "saveWritingStyleBody" apps/web --type ts -B2 -A8 | head -30

echo
echo "=== Look for any .bind calls on regenerateWritingStyleAction ==="
rg -n "regenerateWritingStyleAction.bind" apps/web

Repository: elie222/inbox-zero

Length of output: 3217


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Verify the exact invocation in WritingStyleSetting.tsx around line 80-82 ==="
sed -n '75,100p' "apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx"

echo
echo "=== Check if useAction hook requires binding or can handle it internally ==="
rg -n "useAction" apps/web/utils --type ts -A15 | head -50

echo
echo "=== Get full context of the style formatting function in both actions ==="
echo "--- analyzeWritingStyleAction (lines 79-91) ---"
sed -n '79,91p' apps/web/utils/actions/assess.ts

echo
echo "--- regenerateWritingStyleAction (lines 136-148) ---"
sed -n '136,148p' apps/web/utils/actions/assess.ts

echo
echo "=== Check if there's a helper function for formatting style already ==="
rg -n "formatStyle|formatWriting" apps/web --type ts

Repository: elie222/inbox-zero

Length of output: 1005


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Find useAction definition and how it handles binding ==="
find apps/web -name "*.ts" -o -name "*.tsx" | xargs grep -l "export.*useAction\|function useAction" | head -3

echo
echo "=== Check the hook implementation ==="
rg -n "function useAction|export const useAction|export.*useAction" apps/web --type ts -A20 | head -60

echo
echo "=== Verify how actionClient.bind works ==="
echo "From safe-action.ts, actionClient bindArgsSchemas definition:"
sed -n '60,75p' apps/web/utils/actions/safe-action.ts

echo
echo "=== Check if regenerateWritingStyleAction actually receives emailAccountId ==="
echo "It reads from ctx: "
sed -n '101,103p' apps/web/utils/actions/assess.ts
echo "But how does ctx get emailAccountId if not bound? Check safe-action middleware..."
sed -n '60,120p' apps/web/utils/actions/safe-action.ts

Repository: elie222/inbox-zero

Length of output: 124


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Find useAction hook ==="
find apps/web -type f \( -name "*.ts" -o -name "*.tsx" \) -exec grep -l "useAction" {} \; | grep -v node_modules | head -5

echo
echo "=== Search for useAction definition ==="
rg "export.*useAction" apps/web -A10 --type ts --type tsx 2>/dev/null | head -40

echo
echo "=== Verify actionClient.bindArgsSchemas line 60-75 ==="
sed -n '60,75p' apps/web/utils/actions/safe-action.ts

echo
echo "=== Check how emailAccountId flows through actionClient middleware ==="
sed -n '95,130p' apps/web/utils/actions/safe-action.ts

Repository: elie222/inbox-zero

Length of output: 465


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for useAction import source ==="
grep -r "useAction" apps/web --include="*.ts" --include="*.tsx" | grep "import\|from" | head -3

echo
echo "=== Find the hooks file ==="
find apps/web -name "*hooks*" -o -name "*use-action*" | head -10

echo
echo "=== Check node_modules for next-safe-action hooks ==="
ls -la apps/web/node_modules/next-safe-action 2>/dev/null | head -20 || echo "Checking package info..."

echo
echo "=== Verify actionClient middleware once more - the critical part ==="
sed -n '90,135p' apps/web/utils/actions/safe-action.ts

echo
echo "=== Check how regenerateWritingStyleAction is being called without binding ==="
cat -n apps/web/app/\(app\)/\[emailAccountId\]/assistant/settings/WritingStyleSetting.tsx | sed -n '1,35p'

Repository: elie222/inbox-zero

Length of output: 3611


Fix binding: regenerateWritingStyleAction requires .bind(null, emailAccountId)

In WritingStyleSetting.tsx line 81, regenerateWritingStyleAction is called without binding but uses actionClient which requires it as a bound argument. This will cause the action to fail silently since emailAccountId will be undefined in the middleware. Add .bind(null, emailAccountId) to match analyzeWritingStyleAction.

Additionally:

  • Extract the duplicated style formatting block (lines 79-91 in analyzeWritingStyleAction / 136-148 in regenerateWritingStyleAction) into a shared helper function
  • Truncate the returned writingStyle to saveWritingStyleBody's max(2000) limit to prevent validation errors on save

Copy link
Contributor

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

Choose a reason for hiding this comment

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

2 issues found across 2 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx:87">
P2: Dialog form state is never reset; unsaved regenerated/edited style persists across close/reopen and can overwrite newer server state instead of reflecting currentWritingStyle</violation>

<violation number="2" location="apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx:162">
P1: Since `regenerateWritingStyleAction` has no `inputSchema` (only `bindArgsSchemas`), the action should be invoked as `generate()` without arguments. The `emailAccountId` should be passed via `.bind(null, emailAccountId)` on the action instead of as an argument to `execute`.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

variant="outline"
onClick={(e) => {
e.preventDefault();
generate({ emailAccountId });
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 11, 2026

Choose a reason for hiding this comment

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

P1: Since regenerateWritingStyleAction has no inputSchema (only bindArgsSchemas), the action should be invoked as generate() without arguments. The emailAccountId should be passed via .bind(null, emailAccountId) on the action instead of as an argument to execute.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx, line 162:

<comment>Since `regenerateWritingStyleAction` has no `inputSchema` (only `bindArgsSchemas`), the action should be invoked as `generate()` without arguments. The `emailAccountId` should be passed via `.bind(null, emailAccountId)` on the action instead of as an argument to `execute`.</comment>

<file context>
@@ -142,9 +152,29 @@ Notable Traits:
+              variant="outline"
+              onClick={(e) => {
+                e.preventDefault();
+                generate({ emailAccountId });
+              }}
+              disabled={isGenerating || isExecuting}
</file context>
Suggested change
generate({ emailAccountId });
generate();

✅ Addressed in 50ce27f

Copy link
Contributor

Choose a reason for hiding this comment

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

Commit 50ce27f addressed this comment. The code now correctly binds emailAccountId to the action using .bind(null, emailAccountId) at line 84, and invokes the action as generate() without arguments at line 171, exactly as requested in the comment.

const newStyle = data?.data?.writingStyle;

if (newStyle) {
setValue("writingStyle", newStyle);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 11, 2026

Choose a reason for hiding this comment

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

P2: Dialog form state is never reset; unsaved regenerated/edited style persists across close/reopen and can overwrite newer server state instead of reflecting currentWritingStyle

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx, line 87:

<comment>Dialog form state is never reset; unsaved regenerated/edited style persists across close/reopen and can overwrite newer server state instead of reflecting currentWritingStyle</comment>

<file context>
@@ -69,24 +71,41 @@ function WritingStyleDialog({
+        const newStyle = data?.data?.writingStyle;
+
+        if (newStyle) {
+          setValue("writingStyle", newStyle);
+          if (editorRef.current?.editor) {
+            editorRef.current.editor.commands.setContent(newStyle);
</file context>
Fix with Cubic

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
@apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx:
- Around line 80-98: The action is being called with generate({ emailAccountId
}) but regenerateWritingStyleAction expects the bound first arg (emailAccountId)
like saveWritingStyleAction; fix by binding/passing emailAccountId as the first
positional argument instead of as an input object — either call
generate(emailAccountId) or bind args in useAction (e.g.,
useAction(regenerateWritingStyleAction, { args: [emailAccountId], ... })) and
keep the payload as the second param if needed; update references to
regenerateWritingStyleAction, useAction, and generate accordingly.
🧹 Nitpick comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (2)

157-172: Minor: e.preventDefault() is unnecessary for type="button".

Since the button has type="button", it won't submit the form, making e.preventDefault() redundant.

♻️ Suggested simplification
  <Button
    type="button"
    variant="outline"
-   onClick={(e) => {
-     e.preventDefault();
-     generate({ emailAccountId });
-   }}
+   onClick={() => generate({})}
    disabled={isGenerating || isExecuting}
  >

83-92: Consider handling empty regeneration result.

When aiAnalyzeWritingStyle returns no style, the action returns { writingStyle: "" }. The current check if (newStyle) will skip the success toast for empty strings, leaving users without feedback.

♻️ Suggested improvement
  onSuccess: (data) => {
    const newStyle = data?.data?.writingStyle;

-   if (newStyle) {
+   if (newStyle !== undefined) {
      setValue("writingStyle", newStyle);
      if (editorRef.current?.editor) {
        editorRef.current.editor.commands.setContent(newStyle);
      }
-     toastSuccess({ description: "Writing style regenerated!" });
+     toastSuccess({
+       description: newStyle
+         ? "Writing style regenerated!"
+         : "No writing style could be generated from your sent emails.",
+     });
    }
  },
apps/web/utils/actions/assess.ts (1)

101-151: Consider extracting shared logic with analyzeWritingStyleAction.

The new action duplicates significant portions of analyzeWritingStyleAction:

  • Email account query (lines 104-116 vs 41-54)
  • Writing style formatting (lines 136-148 vs 79-91)

Extracting these to helper functions would reduce duplication and ensure consistency.

♻️ Example refactor
// Add at bottom of file
async function formatWritingStyle(style: {
  typicalLength?: string;
  formality?: string;
  commonGreeting?: string;
  notableTraits: string[];
  examples: string[];
}) {
  return [
    style.typicalLength ? `Typical Length: ${style.typicalLength}` : null,
    style.formality ? `Formality: ${style.formality}` : null,
    style.commonGreeting ? `Common Greeting: ${style.commonGreeting}` : null,
    style.notableTraits.length
      ? `Notable Traits: ${formatBulletList(style.notableTraits)}`
      : null,
    style.examples.length
      ? `Examples: ${formatBulletList(style.examples)}`
      : null,
  ]
    .filter(Boolean)
    .join("\n");
}

Then both actions can use formatWritingStyle(style).

📜 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 8be264e and 2b2c450.

📒 Files selected for processing (2)
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
  • apps/web/utils/actions/assess.ts
🧰 Additional context used
📓 Path-based instructions (22)
**/*.{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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
apps/web/utils/actions/**/*.ts

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

apps/web/utils/actions/**/*.ts: Server actions must be located in apps/web/utils/actions folder
Server action files must start with use server directive

Files:

  • apps/web/utils/actions/assess.ts
apps/web/**/*.{ts,tsx}

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

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas using z.infer<typeof schema> instead of duplicating as separate interfaces

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
apps/web/utils/actions/*.ts

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

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
Use 'use server' directive at the top of server action implementation files
Implement all server actions using the next-safe-action library with actionClient, actionClientUser, or adminActionClient for type safety and validation
Use actionClientUser when only authenticated user context (userId) is needed
Use actionClient when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client
Use adminActionClient for actions restricted to admin users
Add metadata with a meaningful action name using .metadata({ name: "actionName" }) for Sentry instrumentation and monitoring
Use .schema() method with Zod validation schemas from corresponding .validation.ts files in next-safe-action configuration
Access context (userId, emailAccountId, etc.) via the ctx object parameter in the .action() handler
Use revalidatePath or revalidateTag from 'next/cache' within server action handlers when mutations modify data displayed elsewhere

apps/web/utils/actions/*.ts: Use next-safe-action with proper Zod validation for server actions
Server actions should use actionClient.metadata({ name: 'actionName' }).schema(schema).action(...) pattern
Call revalidatePath in server actions after successful mutations
Use revalidatePath in server actions for cache invalidation

Files:

  • apps/web/utils/actions/assess.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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')

**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
**/{utils,helpers,lib}/**/*.{ts,tsx}

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

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/actions/assess.ts
apps/web/utils/actions/!(*.validation).ts

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

apps/web/utils/actions/!(*.validation).ts: Use next-safe-action for all server actions with actionClient, .metadata(), .inputSchema(), and .action() chain pattern
Add 'use server' directive at the top of all server action files

Files:

  • apps/web/utils/actions/assess.ts
apps/web/**/*.{ts,tsx,js,jsx}

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

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Use getActionErrorMessage(error.error) from @/utils/error to extract user-friendly error messages

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
apps/web/**/*.{ts,tsx,css}

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

Follow tailwindcss patterns with prettier-plugin-tailwindcss

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx,json}

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

Client-side environment variables must be prefixed with NEXT_PUBLIC_

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}

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

Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.

Files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
apps/web/**/*.{tsx,jsx}

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

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks
Use shadcn/ui components when available
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use useAction hook from next-safe-action/hooks with onSuccess and onError callbacks for form submission
Use LoadingContent component to handle loading and error states consistently
Call mutate() after successful mutations to refresh SWR data

Files:

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

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

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧠 Learnings (19)
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/utils/actions/!(*.validation).ts : Use `next-safe-action` for all server actions with `actionClient`, `.metadata()`, `.inputSchema()`, and `.action()` chain pattern

Applied to files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T17:27:31.556Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1234
File: apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:65-83
Timestamp: 2026-01-09T17:27:31.556Z
Learning: In the elie222/inbox-zero repository, for React components using next-safe-action, optimistic updates combined with mutate on success/error is an accepted pattern for handling potential race conditions in toggle handlers. Select components use disabled={isExecuting}, but rapid toggle clicks without isExecuting guards are considered acceptable because the optimistic UI + mutate reconciliation handles state correctly.

Applied to files:

  • apps/web/utils/actions/assess.ts
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use `actionClient.metadata({ name: 'actionName' }).schema(schema).action(...)` pattern

Applied to files:

  • apps/web/utils/actions/assess.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T17:27:19.225Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1234
File: apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:65-83
Timestamp: 2026-01-09T17:27:19.225Z
Learning: In the elie222/inbox-zero repo, for React components using next-safe-action, using optimistic updates with mutate on success/error is an accepted approach to address race conditions in toggle handlers. It is acceptable for components not to guard rapid toggles with isExecuting (disable) when the optimistic UI state is reconciled by mutate. Apply this guidance to similar TSX components in the web app where appropriate.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use `useAction` hook with `onSuccess` and `onError` callbacks for handling server action responses in forms

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `useAction` hook from `next-safe-action/hooks` with `onSuccess` and `onError` callbacks for form submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with `zodResolver` for form validation, combining it with `useAction` hook from `next-safe-action/hooks` for server action execution

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use React Hook Form with Zod validation for form handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
🧬 Code graph analysis (2)
apps/web/utils/actions/assess.ts (4)
apps/web/utils/actions/safe-action.ts (1)
  • actionClient (84-138)
apps/web/utils/error.ts (1)
  • SafeError (88-98)
apps/web/utils/email/provider.ts (1)
  • createEmailProvider (14-32)
apps/web/utils/ai/knowledge/writing-style.ts (1)
  • aiAnalyzeWritingStyle (13-91)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (5)
apps/web/utils/actions/user.validation.ts (2)
  • SaveWritingStyleBody (14-14)
  • saveWritingStyleBody (11-13)
apps/web/utils/actions/assess.ts (1)
  • regenerateWritingStyleAction (101-151)
apps/web/components/Toast.tsx (1)
  • toastSuccess (3-12)
apps/web/utils/actions/user.ts (1)
  • saveWritingStyleAction (40-50)
apps/web/utils/error.ts (1)
  • getActionErrorMessage (325-346)
🔇 Additional comments (1)
apps/web/utils/actions/assess.ts (1)

100-151: LGTM overall — the action follows established patterns.

The implementation correctly:

  • Uses actionClient with proper metadata
  • Validates email account ownership (via actionClient middleware)
  • Uses SafeError for user-facing errors
  • Returns a consistent response shape

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
@apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx:
- Around line 98-100: Update the toast message string in the else branch where
toastSuccess is called (the call currently is toastSuccess({ description: "No
enough data to generate style." })); change the description to read "Not enough
data to generate style." so the grammar is correct; ensure you update the string
passed to toastSuccess in WritingStyleSetting (the else block shown) and run a
quick lint/compile to verify no stray quotes or typos.
🧹 Nitpick comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (3)

98-100: Consider using an appropriate toast type for insufficient data.

Using toastSuccess when there's insufficient data to generate a style is semantically misleading. This is not a success scenario but rather an informational notice. If a toastInfo or warning variant is available, use that instead.


169-172: Remove redundant e.preventDefault() call.

Since the button has type="button", it won't trigger form submission. The e.preventDefault() call is unnecessary.

Proposed fix
             <Button
               type="button"
               variant="outline"
-              onClick={(e) => {
-                e.preventDefault();
-                generate();
-              }}
+              onClick={() => generate()}
               disabled={isGenerating || isExecuting}
             >

183-185: Add explicit type="submit" attribute.

Per coding guidelines, always include a type attribute for button elements to make intent clear.

Proposed fix
-            <Button type="submit" loading={isExecuting}>
+            <Button type="submit" loading={isExecuting} disabled={isGenerating}>
               Save
             </Button>

Note: Also consider adding disabled={isGenerating} to prevent saving while regeneration is in progress, maintaining consistent mutual exclusion between both operations.

📜 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 2b2c450 and 50ce27f.

📒 Files selected for processing (1)
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

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

**/*.{ts,tsx}: For API GET requests to server, use 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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
apps/web/**/*.{ts,tsx}

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

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas using z.infer<typeof schema> instead of duplicating as separate interfaces

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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')

**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.

Files:

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

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

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Use getActionErrorMessage(error.error) from @/utils/error to extract user-friendly error messages

Files:

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

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

Follow tailwindcss patterns with prettier-plugin-tailwindcss

Files:

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

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

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks
Use shadcn/ui components when available
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use useAction hook from next-safe-action/hooks with onSuccess and onError callbacks for form submission
Use LoadingContent component to handle loading and error states consistently
Call mutate() after successful mutations to refresh SWR data

Files:

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

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

Ensure responsive design with mobile-first approach

Files:

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

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

Client-side environment variables must be prefixed with NEXT_PUBLIC_

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}

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

Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧠 Learnings (22)
📚 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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/utils/actions/!(*.validation).ts : Use `next-safe-action` for all server actions with `actionClient`, `.metadata()`, `.inputSchema()`, and `.action()` chain pattern

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T17:27:19.225Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1234
File: apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:65-83
Timestamp: 2026-01-09T17:27:19.225Z
Learning: In the elie222/inbox-zero repo, for React components using next-safe-action, using optimistic updates with mutate on success/error is an accepted approach to address race conditions in toggle handlers. It is acceptable for components not to guard rapid toggles with isExecuting (disable) when the optimistic UI state is reconciled by mutate. Apply this guidance to similar TSX components in the web app where appropriate.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use `actionClient.metadata({ name: 'actionName' }).schema(schema).action(...)` pattern

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use `useAction` hook with `onSuccess` and `onError` callbacks for handling server action responses in forms

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `useAction` hook from `next-safe-action/hooks` with `onSuccess` and `onError` callbacks for form submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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 : System prompts must define the LLM's role and task specifications

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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} : All database queries must include user scoping with `emailAccountId` or `userId` filtering in WHERE clauses

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with `zodResolver` for form validation, combining it with `useAction` hook from `next-safe-action/hooks` for server action execution

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (3)

82-106: LGTM! Well-structured regenerate action integration.

The useAction hook usage follows the established patterns with proper onSuccess/onError callbacks. The defensive truncation and editor synchronization are good practices.


140-158: LGTM!

The Controller integration with Tiptap editor is correct, properly handling form state via field.value and field.onChange.


32-32: The constant correctly aligns with the Zod schema validation. WRITING_STYLE_MAX_LENGTH (2000) matches the z.string().max(2000) constraint in saveWritingStyleBody, and it's properly used to truncate the regenerated style before form submission, ensuring validation passes.

@CODEAbhinav-art
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

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

82-108: Remove unhelpful comment on Line 99.

The comment "Fixed grammar per CodeRabbit review" describes past review history rather than explaining the code's purpose. Per coding guidelines, comments should explain why not what happened during review.

♻️ Suggested fix
         } else {
-          // Fixed grammar per CodeRabbit review
           toastSuccess({ description: "Not enough data to generate style." });
         }

Otherwise, the regeneration logic is well-implemented:

  • Correctly uses useAction pattern consistent with the existing save action and learnings for form components
  • Proper error handling with getActionErrorMessage and toastError per guidelines
  • Defensive truncation ensures validation compatibility
  • Editor ref update is necessary to sync Tiptap's internal state with the form
  • Correctly omits mutate() call since regeneration doesn't persist to the database
📜 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 50ce27f and 6162b0b.

📒 Files selected for processing (1)
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

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

**/*.{ts,tsx}: For API GET requests to server, use 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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
apps/web/**/*.{ts,tsx}

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

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas using z.infer<typeof schema> instead of duplicating as separate interfaces

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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')

**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.

Files:

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

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

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Use getActionErrorMessage(error.error) from @/utils/error to extract user-friendly error messages

Files:

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

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

Follow tailwindcss patterns with prettier-plugin-tailwindcss

Files:

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

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

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks
Use shadcn/ui components when available
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use useAction hook from next-safe-action/hooks with onSuccess and onError callbacks for form submission
Use LoadingContent component to handle loading and error states consistently
Call mutate() after successful mutations to refresh SWR data

Files:

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

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

Ensure responsive design with mobile-first approach

Files:

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

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

Client-side environment variables must be prefixed with NEXT_PUBLIC_

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}

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

Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧠 Learnings (25)
📚 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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/utils/actions/!(*.validation).ts : Use `next-safe-action` for all server actions with `actionClient`, `.metadata()`, `.inputSchema()`, and `.action()` chain pattern

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T17:27:19.225Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1234
File: apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:65-83
Timestamp: 2026-01-09T17:27:19.225Z
Learning: In the elie222/inbox-zero repo, for React components using next-safe-action, using optimistic updates with mutate on success/error is an accepted approach to address race conditions in toggle handlers. It is acceptable for components not to guard rapid toggles with isExecuting (disable) when the optimistic UI state is reconciled by mutate. Apply this guidance to similar TSX components in the web app where appropriate.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use `actionClient.metadata({ name: 'actionName' }).schema(schema).action(...)` pattern

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use `useAction` hook with `onSuccess` and `onError` callbacks for handling server action responses in forms

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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 : System prompts must define the LLM's role and task specifications

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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 : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with `zodResolver` for form validation, combining it with `useAction` hook from `next-safe-action/hooks` for server action execution

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `useAction` hook from `next-safe-action/hooks` with `onSuccess` and `onError` callbacks for form submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (5)
apps/web/utils/actions/user.validation.ts (2)
  • SaveWritingStyleBody (14-14)
  • saveWritingStyleBody (11-13)
apps/web/utils/actions/assess.ts (1)
  • regenerateWritingStyleAction (101-151)
apps/web/components/Toast.tsx (2)
  • toastSuccess (3-12)
  • toastError (14-19)
apps/web/utils/error.ts (1)
  • getActionErrorMessage (325-346)
apps/web/utils/actions/user.ts (1)
  • saveWritingStyleAction (40-50)
🔇 Additional comments (4)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (4)

27-32: LGTM! Clean imports and constant definition.

The imports align with the new regeneration feature and the WRITING_STYLE_MAX_LENGTH constant correctly matches the validation schema's 2000-character limit.


76-76: LGTM! Necessary for programmatic form updates.

Adding setValue enables the regenerate action to update the form field programmatically after fetching the generated writing style.


110-124: LGTM! Improved messaging and consistent error handling.

The updated toast messages are more descriptive, and the error handling pattern is consistent with the regenerate action.


166-184: LGTM! Well-designed button layout with excellent UX.

The two-button layout is clean and user-friendly:

  • type="button" on Regenerate correctly prevents form submission
  • Appropriate disabled states prevent race conditions (both buttons disabled during generation, save also disabled during execution)
  • Clear visual feedback with loading spinner and sparkle icons
  • Right-aligned layout with proper spacing

@CODEAbhinav-art
Copy link
Author

CODEAbhinav-art commented Jan 11, 2026

@CLAassistant check

@CODEAbhinav-art
Copy link
Author

@elie222 ,I have signed the CLA (confirmed on the linked page), but the status check seems stuck on pending. I've double-checked my email config and everything matches.

@elie222
Copy link
Owner

elie222 commented Jan 11, 2026

Is there a reason you decided to change other things in this PR like the placeholder copy?

@CODEAbhinav-art
Copy link
Author

Is there a reason you decided to change other things in this PR like the placeholder copy?

That was unintentional! I truncated it while refactoring the component but missed restoring the full text. I've pushed a fix to restore the original placeholder.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (2)

32-32: Consider extracting max length to shared constant.

The WRITING_STYLE_MAX_LENGTH duplicates the validation limit from saveWritingStyleBody schema (2000). If the schema's max changes, this constant must be updated manually, creating a maintenance risk.

♻️ Extract to shared constant

In apps/web/utils/actions/user.validation.ts:

+export const WRITING_STYLE_MAX_LENGTH = 2000;
+
 export const saveWritingStyleBody = z.object({
-  writingStyle: z.string().max(2000),
+  writingStyle: z.string().max(WRITING_STYLE_MAX_LENGTH),
 });

Then import and use it here:

 import { saveWritingStyleAction } from "@/utils/actions/user";
 import { regenerateWritingStyleAction } from "@/utils/actions/assess";
+import { WRITING_STYLE_MAX_LENGTH } from "@/utils/actions/user.validation";
-
-const WRITING_STYLE_MAX_LENGTH = 2000;

98-100: Consider neutral toast for "no data" scenario.

Using toastSuccess for "Not enough data to generate style" is semantically odd—it's not a success, but rather an informational message. While not critical, a neutral or info-level toast would better match user expectations.

Alternative: Use info-level toast if available

If the toast utility supports an info variant:

-          toastSuccess({ description: "Not enough data to generate style." });
+          toast.info({ description: "Not enough data to generate style." });

Otherwise, the current implementation is acceptable.

📜 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 6162b0b and 4de3690.

📒 Files selected for processing (1)
  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

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

**/*.{ts,tsx}: For API GET requests to server, use 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}: 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 import type for types
Make sure all enum members are literal values
Don't use TypeScript const enum
Don't declare empty interfaces
Don't let variables evolve into any type through reassignments
Don't use the any type
Don't misuse the non-null assertion operator (!) in TypeScript files
Don't use implicit any type on variable declarations
Don't merge interfaces and classes unsafely
Don't use overload signatures that aren't next to each other
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces
Use consistent accessibility modifiers on class properties and methods
Use function types instead of object types wit...

Files:

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

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

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

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas using z.infer<typeof schema> instead of duplicating as separate interfaces

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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')

**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.

Files:

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

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

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Use getActionErrorMessage(error.error) from @/utils/error to extract user-friendly error messages

Files:

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

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

Follow tailwindcss patterns with prettier-plugin-tailwindcss

Files:

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

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

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks
Use shadcn/ui components when available
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Use useAction hook from next-safe-action/hooks with onSuccess and onError callbacks for form submission
Use LoadingContent component to handle loading and error states consistently
Call mutate() after successful mutations to refresh SWR data

Files:

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

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

Ensure responsive design with mobile-first approach

Files:

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

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

Client-side environment variables must be prefixed with NEXT_PUBLIC_

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}

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

Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
🧠 Learnings (23)
📚 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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/utils/actions/!(*.validation).ts : Use `next-safe-action` for all server actions with `actionClient`, `.metadata()`, `.inputSchema()`, and `.action()` chain pattern

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T17:27:19.225Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1234
File: apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:65-83
Timestamp: 2026-01-09T17:27:19.225Z
Learning: In the elie222/inbox-zero repo, for React components using next-safe-action, using optimistic updates with mutate on success/error is an accepted approach to address race conditions in toggle handlers. It is acceptable for components not to guard rapid toggles with isExecuting (disable) when the optimistic UI state is reconciled by mutate. Apply this guidance to similar TSX components in the web app where appropriate.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use `actionClient.metadata({ name: 'actionName' }).schema(schema).action(...)` pattern

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use `useAction` hook with `onSuccess` and `onError` callbacks for handling server action responses in forms

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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 : System prompts must define the LLM's role and task specifications

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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 : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with `zodResolver` for form validation, combining it with `useAction` hook from `next-safe-action/hooks` for server action execution

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `useAction` hook from `next-safe-action/hooks` with `onSuccess` and `onError` callbacks for form submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.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/settings/WritingStyleSetting.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/settings/WritingStyleSetting.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (4)
apps/web/utils/actions/user.validation.ts (2)
  • SaveWritingStyleBody (14-14)
  • saveWritingStyleBody (11-13)
apps/web/utils/actions/assess.ts (1)
  • regenerateWritingStyleAction (101-151)
apps/web/components/Toast.tsx (2)
  • toastSuccess (3-12)
  • toastError (14-19)
apps/web/utils/error.ts (1)
  • getActionErrorMessage (325-346)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/settings/WritingStyleSetting.tsx (2)

76-76: LGTM! Clean regenerate implementation.

The regenerate action is well-structured:

  • Uses useAction consistently with the existing save action pattern in this file
  • Properly truncates the result before updating form state to ensure validation compliance
  • Updates both the form field (via setValue) and editor content (via ref)
  • Handles empty results gracefully with appropriate user feedback
  • Follows error handling guidelines with getActionErrorMessage

Also applies to: 82-107


173-192: LGTM! Well-implemented button controls.

The button layout properly handles:

  • Race condition prevention via disabled states (Regenerate disabled during both actions; Save disabled during regeneration)
  • Clear loading feedback with appropriate icons (spinning Loader2 and idle Sparkles)
  • Correct button types (type="button" prevents unintended form submission)
  • Standard visual hierarchy (outline for secondary, primary for main action)

@elie222
Copy link
Owner

elie222 commented Jan 13, 2026

Your copy-pasting code from other parts in the app. I'm going to close this because I think it will be easier to just one-shot with AI rather than have other people do it.

@elie222 elie222 closed this Jan 13, 2026
@elie222
Copy link
Owner

elie222 commented Jan 13, 2026

If you look over your actual code that you changed, then you'll see that you've gone and changed things. It just didn't need changing here.

And lastly, you have random comments with ---------------- put in, which is not like the style anywhere else.

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.

3 participants

Comments