Skip to content

Report mistakes when testing#268

Merged
elie222 merged 19 commits intomainfrom
report-mistake
Dec 15, 2024
Merged

Report mistakes when testing#268
elie222 merged 19 commits intomainfrom
report-mistake

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Dec 10, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a ReportMistake component for users to report AI-generated response errors.
    • Added functionality for testing cold emails within the new TestRules component.
    • Implemented a new action to report AI mistakes with enhanced error handling.
    • Enhanced the getMessages function to increase the maximum results returned and improve authentication checks.
    • Added new validation schemas for reporting AI mistakes and testing AI functionalities.
    • Introduced a new action for updating rule instructions.
    • Enhanced UI components with improved styling and structure.
    • Updated the HoverCard component to allow custom class names for better styling flexibility.
    • Added a new API route to check if a specified Gmail thread contains multiple messages.
  • Bug Fixes

    • Added unit tests for the aiRuleFix function to ensure proper handling of specific email types.
  • Chores

    • Updated import paths for UI components to align with the new structure.
    • Added a new dependency to the project.

- Added `strip-indent` package (version 4.0.0) to the project dependencies.
- Introduced `aiRuleFix` function to improve email rule handling based on provided email content.
- Created a new test file for `aiRuleFix` to validate its functionality.
- Updated `ReportMistake` component to utilize the new AI rule fixing logic.
- Refactored `TestRules` and `TestResultDisplay` components to integrate the new reporting and rule fixing features.
- Enhanced form validation for reporting mistakes in AI rules.
- Removed console log from `reportAiMistakeAction` for cleaner output.
- Updated `reportAiMistakeAction` to include trimmed explanation in the result.
- Modified `aiRuleFix` function to accept an optional explanation parameter and included it in the prompt for better context when fixing rules.
@vercel
Copy link

vercel bot commented Dec 10, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
inbox-zero ✅ Ready (Inspect) Visit Preview Dec 15, 2024 8:23pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2024

Warning

Rate limit exceeded

@elie222 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 9 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ff2ab07 and f0e4498.

📒 Files selected for processing (1)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)

Walkthrough

This pull request introduces several enhancements across multiple files, focusing on the implementation of a new ReportMistake component for reporting AI errors, the addition of unit tests for the aiRuleFix function, and the restructuring of existing components. New functionalities include a reporting action for AI mistakes, validation schemas, and improved UI elements. The changes also involve updates to the import paths and button styles, alongside the introduction of a new utility file for fixing email rules.

Changes

File Change Summary
apps/web/__tests__/ai-rule-fix.test.ts Added a test suite for aiRuleFix, validating its behavior with sales emails and ensuring proper instruction adjustments.
apps/web/app/(app)/automation/ReportMistake.tsx Introduced a ReportMistake component for users to report AI mistakes, utilizing react-hook-form and toast notifications.
apps/web/app/(app)/automation/TestRules.tsx Updated UI components, changed button variants, and modified function signatures to include a new message parameter.
apps/web/app/(app)/cold-email-blocker/TestRules.tsx Implemented a new TestRules component for testing cold emails, including form handling and API interactions.
apps/web/components/SearchForm.tsx Updated import paths and button properties in the SearchForm component without changing core functionality.
apps/web/package.json Added a new dependency: "strip-indent": "^4.0.0".
apps/web/utils/actions/ai-rule.ts Added reportAiMistakeAction for reporting AI mistakes with input validation and enhanced error handling.
apps/web/utils/actions/validation.ts Introduced reportAiMistakeBody schema and ReportAiMistakeBody type for validating report submissions.
apps/web/utils/ai/rule/rule-fix.ts Created rule-fix.ts with aiRuleFix function for fixing email rules using AI, including structured error handling.
apps/web/app/api/google/messages/route.ts Modified getMessages function to enhance authentication checks, increase result limits, and refine message filtering.
apps/web/utils/actions/user.ts Enhanced validation logic in user.ts, updating schemas and error handling for user-related actions.
apps/web/app/(app)/automation/ExecutedRulesTable.tsx Modified RuleCell component to add a className property to the HoverCard component for styling.
apps/web/components/HoverCard.tsx Added an optional className property in HoverCard props for custom styling.
apps/web/components/PlanBadge.tsx Added className property to HoverCard components for enhanced styling.
apps/web/utils/actions/rule.ts Introduced updateRuleInstructionsAction for updating rule instructions with input validation.
apps/web/app/api/google/webhook/process-history.ts Enhanced the processHistoryItem function to utilize hasMultipleMessages for better readability and error handling.
apps/web/utils/gmail/thread.ts Added hasMultipleMessages function to check if a Gmail thread contains multiple messages.
apps/web/app/api/google/threads/[id]/check/route.ts Introduced a new API route to check if a specified Gmail thread contains multiple messages.

Possibly related PRs

  • AI prompt for each generated argument #191: The changes in the main PR introduce a new test file for the aiRuleFix function, which is related to the AI-generated fields and actions discussed in this PR.
  • Add support for Anthropic #215: The main PR's focus on AI functionalities aligns with the addition of support for Anthropic in this PR, as both involve AI-driven processes.
  • Generate groups with AI prompt #244: The main PR's updates to the RuleForm component and its handling of AI-generated actions relate to the changes in this PR, which also focuses on AI prompts and their integration into the system.
  • AI template responses #263: The introduction of a test suite for AI template responses in this PR complements the main PR's focus on AI functionalities and testing, as both aim to enhance the reliability of AI-driven actions.

🐇 In the fields of code, we hop and play,
New tests and features brighten the day.
Reporting mistakes, we’ve built a way,
With buttons and forms, we’ll save the day!
So here’s to the changes, let’s cheer and sway! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 6

🧹 Outside diff range and nitpick comments (11)
apps/web/utils/ai/rule/rule-fix.ts (1)

77-77: Reassess the necessity of passing user.email to chatCompletionObject

If user.email is not essential for the function of chatCompletionObject, consider omitting it to minimize handling of PII.

apps/web/__tests__/ai-rule-fix.test.ts (1)

46-46: Remove console.log statements from test code

Consider removing the console.log statement to keep test output clean. Tests should rely on assertions rather than logs.

apps/web/app/(app)/automation/ReportMistake.tsx (2)

52-55: Remove commented-out code

Consider removing the commented-out console error statements to keep the codebase clean and maintainable.


100-110: Make the explanation field required and add validation

Since the explanation helps in understanding the mistake, consider making it a required field and adding appropriate validation to ensure it is not empty.

Apply this diff to update the validation schema and form:

- import {
-   reportAiMistakeBody,
-   type ReportAiMistakeBody,
- } from "@/utils/actions/validation";
+ const reportAiMistakeFormSchema = reportAiMistakeBody.extend({
+   explanation: z.string().min(1, "Explanation is required"),
+ });
+ type ReportAiMistakeForm = z.infer<typeof reportAiMistakeFormSchema>;

      // In useForm:
-   } = useForm<ReportAiMistakeBody>({
-     resolver: zodResolver(reportAiMistakeBody),
+   } = useForm<ReportAiMistakeForm>({
+     resolver: zodResolver(reportAiMistakeFormSchema),

      // Update Input component to display required indicator
      <Input
        type="text"
        autosizeTextarea
        rows={3}
        name="explanation"
        label="Explanation"
+       required
        placeholder="What was incorrect about this response?"
        registerProps={register("explanation")}
        error={errors.explanation}
      />
apps/web/app/(app)/cold-email-blocker/TestRules.tsx (4)

Line range hint 1-3: Consider extracting common components.

The comment indicates this is a copy/paste of automation/TestRules.tsx. Consider extracting shared components into a common location to avoid code duplication.


Line range hint 91-139: Enhance form validation and error handling.

The form validation could be improved:

  1. Add input sanitization
  2. Add validation for email format
  3. Consider adding max length validation
 const {
   register,
   handleSubmit,
   formState: { errors, isSubmitting },
 } = useForm<TestRulesInputs>({
   defaultValues: {
     message:
       "Hey, I run a development agency. I was wondering if you need extra hands on your team?",
   },
+  validate: {
+    message: (value) => {
+      if (value.length > 1000) return "Message too long";
+      if (!/\S+/.test(value)) return "Message cannot be empty";
+      return true;
+    },
+  },
 });

Line range hint 108-126: Improve error handling in onSubmit callback.

The error handling could be enhanced:

  1. Add error boundary
  2. Add retry mechanism for transient failures
  3. Clean up error logging
 const onSubmit: SubmitHandler<TestRulesInputs> = useCallback(async (data) => {
+  try {
     const res = await postRequest<
       ColdEmailBlockerResponse,
       ColdEmailBlockerBody
     >("/api/ai/cold-email", {
       email: {
         from: "",
         subject: "",
         textHtml: null,
         textPlain: data.message,
         snippet: null,
         threadId: null,
       },
     });

     if (isError(res)) {
-      console.error(res);
+      // Log structured error for better debugging
+      console.error("Cold email check failed:", {
+        error: res.error,
+        message: data.message.substring(0, 100), // Log truncated message for context
+      });
       toastError({
         title: "Error checking if cold email.",
         description: res.error,
       });
     } else {
       setColdEmailResponse(res);
     }
+  } catch (error) {
+    console.error("Unexpected error in cold email check:", error);
+    toastError({
+      title: "Unexpected error",
+      description: "Please try again later",
+    });
+  }
 }, []);

Line range hint 141-186: Potential memory leak in event handler.

The click handler creates a new function on every render. Consider extracting it to a useCallback hook to prevent unnecessary re-renders and potential memory leaks.

+const handleTest = useCallback(async () => {
+  setLoading(true);
+  try {
+    const res = await postRequest<ColdEmailBlockerResponse, ColdEmailBlockerBody>(
+      "/api/ai/cold-email",
+      {
+        email: {
+          from: message.headers.from,
+          subject: message.headers.subject,
+          textHtml: message.textHtml || null,
+          textPlain: message.textPlain || null,
+          snippet: message.snippet || null,
+          threadId: message.threadId,
+        },
+      }
+    );
+    if (isError(res)) {
+      console.error(res);
+      toastError({
+        title: "Error checking whether it's a cold email.",
+        description: res.error,
+      });
+    } else {
+      setColdEmailResponse(res);
+    }
+  } finally {
+    setLoading(false);
+  }
+}, [message, setColdEmailResponse]);
apps/web/app/(app)/automation/TestRules.tsx (1)

Line range hint 251-266: Improve accessibility for alert components.

Add ARIA labels and roles to enhance screen reader support.

-      <Alert variant="destructive">
+      <Alert 
+        variant="destructive"
+        role="alert"
+        aria-live="assertive"
+      >
-      <Alert variant="blue">
+      <Alert 
+        variant="blue"
+        role="status"
+        aria-live="polite"
+      >

Also applies to: 296-322

apps/web/utils/actions/ai-rule.ts (2)

884-885: Address the TODO comment and improve error handling.

The TODO comment indicates uncertainty about handling missing rule instructions. Consider implementing a more specific error message that guides the user on how to resolve the issue.

Would you like me to help implement a more robust error handling strategy for this case?


869-920: Consider adding logging for error cases.

The action would benefit from logging error cases to help with debugging and monitoring. Consider adding logging statements for:

  • Input validation failures
  • Missing rule cases
  • AI rule fixing failures
 export const reportAiMistakeAction = withActionInstrumentation(
   "reportAiMistake",
   async (unsafeBody: ReportAiMistakeBody) => {
     const session = await auth();
     if (!session?.user.id) return { error: "Not logged in" };

     const { success, data, error } = reportAiMistakeBody.safeParse(unsafeBody);
-    if (!success) return { error: error.message };
+    if (!success) {
+      logger.error("Input validation failed", { error: error.message });
+      return { error: error.message };
+    }
     const { ruleId, email, explanation } = data;

     if (!ruleId) return { error: "Rule ID is required" };

     const rule = await prisma.rule.findUnique({
       where: { id: ruleId, userId: session.user.id },
     });
-    if (!rule?.instructions) return { error: "No instructions for rule" };
+    if (!rule?.instructions) {
+      logger.error("Missing rule instructions", { ruleId });
+      return { error: "No instructions found for the specified rule" };
+    }

     // ... rest of the implementation

-    if (isActionError(result)) return { error: result.error };
-    if (!result) return { error: "Error fixing rule" };
+    if (isActionError(result)) {
+      logger.error("AI rule fixing failed", { error: result.error });
+      return { error: result.error };
+    }
+    if (!result) {
+      logger.error("AI rule fixing returned null result");
+      return { error: "Failed to generate fixed instructions" };
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between af10d8e and 6292366.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • apps/web/__tests__/ai-rule-fix.test.ts (1 hunks)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)
  • apps/web/app/(app)/automation/TestRules.tsx (8 hunks)
  • apps/web/app/(app)/cold-email-blocker/TestRules.tsx (1 hunks)
  • apps/web/components/SearchForm.tsx (2 hunks)
  • apps/web/package.json (1 hunks)
  • apps/web/utils/actions/ai-rule.ts (3 hunks)
  • apps/web/utils/actions/validation.ts (1 hunks)
  • apps/web/utils/ai/rule/rule-fix.ts (1 hunks)
🔇 Additional comments (7)
apps/web/components/SearchForm.tsx (1)

44-44: LGTM! Button variant change is appropriate

The change from color="transparent" to variant="ghost" follows common component library patterns while maintaining the same visual effect. The loading state is properly handled.

apps/web/utils/actions/validation.ts (1)

95-107: Validation schema added correctly

The reportAiMistakeBody schema is well-defined and appropriately validates the required fields for reporting AI mistakes.

apps/web/package.json (1)

119-119: LGTM: Added strip-indent dependency.

The added dependency is at its latest version and is actively maintained.

apps/web/app/(app)/automation/TestRules.tsx (1)

38-38: LGTM: Good type definition.

Extracting the Message type improves code readability and maintainability.

apps/web/utils/actions/ai-rule.ts (3)

32-33: LGTM! Import statements are properly organized.

The new imports for report mistake functionality are correctly placed and properly typed.

Also applies to: 45-45


905-914: LGTM! Proper error handling and type safety.

The implementation correctly:

  • Passes typed parameters to aiRuleFix
  • Trims the explanation text
  • Makes explanation optional with undefined fallback

899-903: Consider handling empty content case.

The emailToContent call should handle the case where all content fields (textHtml, textPlain, and snippet) are empty or null.

import { type SubmitHandler, useForm } from "react-hook-form";
import { SearchIcon } from "lucide-react";
import { Button } from "@/components/Button";
import { Button } from "@/components/ui/button";
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Several files still use the old Button import path

The verification revealed inconsistent Button import paths across the codebase. Multiple files are still using the old import path @/components/Button:

  • apps/web/components/TopNav.tsx
  • apps/web/components/PremiumAlert.tsx
  • apps/web/components/GroupHeading.tsx
  • apps/web/components/ErrorPage.tsx
  • apps/web/components/Celebration.tsx
  • And 19 other files in the apps/web directory

The import path should be updated to @/components/ui/button to maintain consistency with the new component structure.

🔗 Analysis chain

Verify consistent Button import paths across the codebase

The import path change follows good practices by organizing UI components under a dedicated directory.

Let's verify the consistency of Button imports across the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining old Button import paths
# Expect: All Button imports should use the new path

# Search for old import pattern
echo "Checking for old Button import pattern..."
rg "from ['\"]@/components/Button['\"]"

# Search for new import pattern for reference
echo "Checking new Button import pattern..."
rg "from ['\"]@/components/ui/button['\"]"

Length of output: 10601

Comment on lines 72 to 79
const aiResponse = await chatCompletionObject({
userAi: user,
prompt,
system,
schema: ruleFixSchema,
userEmail: user.email ?? "",
usageLabel: "ai-rule-fix",
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for chatCompletionObject to improve robustness

The asynchronous call to chatCompletionObject may throw exceptions. Adding error handling will enhance stability and prevent unhandled promise rejections.

Apply this diff to implement error handling:

      logger.trace({ system, prompt });

+     try {
        const aiResponse = await chatCompletionObject({
          userAi: user,
          prompt,
          system,
          schema: ruleFixSchema,
          userEmail: user.email ?? "",
          usageLabel: "ai-rule-fix",
        });

        logger.trace(aiResponse.object);

        return aiResponse.object;
+     } catch (error) {
+       logger.error('Error in aiRuleFix:', error);
+       throw error; // Handle the error appropriately
+     }

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

Comment on lines 61 to 64
alert(
"No rule found. Can't report mistake. Will be implemented in the future.",
);
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using alert for user notifications

Using alert can disrupt the user experience and is discouraged in modern web applications. Consider utilizing a toast notification or modal to provide feedback.

Apply this diff to replace alert with a toast notification:

          if (!data?.ruleId) {
-           alert(
-             "No rule found. Can't report mistake. Will be implemented in the future.",
-           );
+           toastError({
+             title: "Reporting Unavailable",
+             description:
+               "No rule found. Can't report mistake. This feature will be implemented in the future.",
+           });
            return;
          }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
alert(
"No rule found. Can't report mistake. Will be implemented in the future.",
);
return;
toastError({
title: "Reporting Unavailable",
description:
"No rule found. Can't report mistake. This feature will be implemented in the future.",
});
return;

Comment on lines 240 to 246
function TestResultDisplay({
result,
message,
}: {
result: TestResult;
message: Message | null;
}) {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance type safety for message parameter.

Consider making the message parameter required when there's a rule match, as the ReportMistake component expects a non-null message.

-function TestResultDisplay({
-  result,
-  message,
-}: {
-  result: TestResult;
-  message: Message | null;
-}) {
+type TestResultDisplayProps =
+  | { result: TestResult & { rule: null }; message: Message | null }
+  | { result: TestResult & { rule: { name: string } }; message: Message };
+
+function TestResultDisplay(props: TestResultDisplayProps) {
+  const { result, message } = props;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function TestResultDisplay({
result,
message,
}: {
result: TestResult;
message: Message | null;
}) {
type TestResultDisplayProps =
| { result: TestResult & { rule: null }; message: Message | null }
| { result: TestResult & { rule: { name: string } }; message: Message };
function TestResultDisplay(props: TestResultDisplayProps) {
const { result, message } = props;

- Updated the `saveAboutBody` schema to enforce a maximum length of 2000 characters for the `about` field, improving data integrity and user input validation.
- Enhanced the `saveAboutAction` and `saveOnboardingAnswersAction` functions to include safe parsing of input data using Zod schemas, ensuring better validation and error handling.
- Updated the parameter names for clarity, changing `options` to `unsafeBody` in `saveAboutAction` and similarly in `saveOnboardingAnswersAction`.
- Improved error responses to return specific error messages when validation fails, enhancing user feedback.
- Introduced a new Zod schema `testAiBody` for validating input in the `testAiAction`, ensuring proper structure and error handling.
- Updated the `testAiAction` to accept a structured input object instead of separate parameters, improving clarity and maintainability.
- Modified the `ReportMistake` component's placeholder text to provide clearer guidance for users on what to include in their feedback.
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

🧹 Outside diff range and nitpick comments (3)
apps/web/utils/actions/validation.ts (1)

101-111: Consider strengthening validation rules

The email object's validation could be enhanced:

  1. textHtml and textPlain are both optional - consider requiring at least one
  2. explanation being optional might miss valuable user feedback
 export const reportAiMistakeBody = z.object({
   email: z.object({
     from: z.string(),
     subject: z.string(),
     snippet: z.string(),
-    textHtml: z.string().nullish(),
-    textPlain: z.string().nullish(),
+    textHtml: z.string().optional(),
+    textPlain: z.string().optional(),
   }).refine(
+    data => data.textHtml || data.textPlain,
+    "At least one of textHtml or textPlain must be provided"
   ),
   ruleId: z.string().nullish(),
-  explanation: z.string().nullish(),
+  explanation: z.string().min(1, "Please provide an explanation"),
 });
apps/web/utils/actions/ai-rule.ts (2)

891-892: Address the TODO comment regarding error handling.

The comment "TODO: how should we handle this?" needs to be addressed. Consider implementing proper error handling for cases where the rule exists but has no instructions.

Would you like me to help implement a more robust error handling strategy for this case? We could:

  1. Log the incident for monitoring
  2. Return a more specific error message
  3. Potentially create a new rule if the existing one is invalid

876-927: Consider adding transaction handling and logging.

The function could benefit from:

  1. Transaction handling to ensure data consistency
  2. Logging for better debugging and monitoring
  3. More specific error messages

Here's a suggested improvement:

 export const reportAiMistakeAction = withActionInstrumentation(
   "reportAiMistake",
   async (unsafeBody: ReportAiMistakeBody) => {
+    const logger = createScopedLogger("reportAiMistake");
     const session = await auth();
     if (!session?.user.id) return { error: "Not logged in" };
 
     const { success, data, error } = reportAiMistakeBody.safeParse(unsafeBody);
     if (!success) return { error: error.message };
     const { ruleId, email, explanation } = data;
 
-    if (!ruleId) return { error: "Rule ID is required" };
+    if (!ruleId) {
+      logger.error("Rule ID missing in request");
+      return { error: "Rule ID is required to report an AI mistake" };
+    }
 
-    const rule = await prisma.rule.findUnique({
-      where: { id: ruleId, userId: session.user.id },
-    });
-    if (!rule?.instructions) return { error: "No instructions for rule" };
+    return await prisma.$transaction(async (tx) => {
+      const rule = await tx.rule.findUnique({
+        where: { id: ruleId, userId: session.user.id },
+      });
+      
+      if (!rule) {
+        logger.error("Rule not found", { ruleId });
+        return { error: "Rule not found. It might have been deleted." };
+      }
+      
+      if (!rule.instructions) {
+        logger.error("Rule has no instructions", { ruleId });
+        return { error: "Cannot fix rule: missing instructions" };
+      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6292366 and decd390.

📒 Files selected for processing (5)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)
  • apps/web/app/api/google/messages/route.ts (1 hunks)
  • apps/web/utils/actions/ai-rule.ts (4 hunks)
  • apps/web/utils/actions/user.ts (2 hunks)
  • apps/web/utils/actions/validation.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(app)/automation/ReportMistake.tsx
🔇 Additional comments (10)
apps/web/app/api/google/messages/route.ts (4)

15-15: LGTM: Improved authentication check

The more specific check for session?.user.email enhances security by ensuring the email is present.


28-33: LGTM: Enhanced null safety and filtering

Good addition of null checks and the use of isDefined filter to handle potential undefined messages safely.


21-21: Verify impact of increased maxResults

Increasing maxResults from 10 to 20 could impact performance and rate limits.

Consider implementing pagination if you need to process more messages, rather than increasing the batch size.


35-38: Verify the email filtering logic

The comment suggests that -from:me wasn't working as expected. The new filtering approach looks correct but should be tested thoroughly.

Would you like me to help create test cases for this filtering logic?

✅ Verification successful

The previous search might have been too specific. Let's broaden our search to find any related test files and understand the implementation context better. This will help us verify if the email filtering logic is properly tested or if there are potential issues.


Let's examine the complete implementation file and any dependencies to better understand the email filtering logic and its usage context.


Email filtering logic is correctly implemented

The implementation is sound for the following reasons:

  • The comment accurately explains why -from:me query parameter wasn't suitable (it would filter out entire threads where the user responded)
  • The current approach correctly filters messages by checking the sender's email against the authenticated user's email
  • The filtering is applied after fetching the full message details, which ensures accurate sender information
  • The implementation is used across multiple components (email panel, test rules, compose form) suggesting it's working as expected in production
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Look for related tests
rg -l 'describe.*getMessages|test.*getMessages|it.*getMessages' -g '*.test.*'

Length of output: 79


Script:

#!/bin/bash
# Let's look for any tests related to Google messages or email filtering
rg -l "google.*messages|email.*filter" -g "*.test.*"

# Also search for the actual implementation to understand the context better
rg -A 5 "fullMessages.filter.*message.*headers.*from" 

Length of output: 110


Script:

#!/bin/bash
# Let's look at the entire route file to understand the context better
cat "apps/web/app/api/google/messages/route.ts"

# Also search for any files that might be importing or using this route
rg -l "api/google/messages"

Length of output: 2125

apps/web/utils/actions/validation.ts (1)

95-99: LGTM: Clear and focused test schema

The schema correctly validates required message and thread IDs.

apps/web/utils/actions/user.ts (2)

17-17: LGTM: Added maximum length constraint

Good addition of max length constraint (2000 chars) for the about field.


106-109: LGTM: Consistent error handling

Good use of safeParse for validation with clear error messages.

apps/web/utils/actions/ai-rule.ts (3)

32-37: LGTM! New imports are well-organized.

The new imports for validation schemas, types, and the aiRuleFix utility are properly structured and align with the new functionality being added.

Also applies to: 47-47


912-921: LGTM! AI rule fix integration looks good.

The integration with aiRuleFix is well-structured:

  • Passes all required parameters
  • Properly handles the explanation field
  • Maintains type safety

906-911: Consider handling empty content edge case.

The email content processing should handle the case where all content fields (textHtml, textPlain, and snippet) are empty or null.

Let's verify if this edge case is handled properly:

Comment on lines +93 to +97
const saveOnboardingAnswersBody = z.object({
surveyId: z.string().optional(),
questions: z.any(),
answers: z.any(),
});
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

Improve type safety in onboarding schema

The schema uses z.any() for questions and answers, which bypasses TypeScript's type checking.

Consider defining specific types for questions and answers:

 const saveOnboardingAnswersBody = z.object({
   surveyId: z.string().optional(),
-  questions: z.any(),
-  answers: z.any(),
+  questions: z.array(z.object({
+    id: z.string(),
+    text: z.string(),
+    type: z.enum(['text', 'multiple_choice', 'checkbox']),
+  })),
+  answers: z.record(z.string(), z.union([z.string(), z.array(z.string())])),
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const saveOnboardingAnswersBody = z.object({
surveyId: z.string().optional(),
questions: z.any(),
answers: z.any(),
});
const saveOnboardingAnswersBody = z.object({
surveyId: z.string().optional(),
questions: z.array(z.object({
id: z.string(),
text: z.string(),
type: z.enum(['text', 'multiple_choice', 'checkbox']),
})),
answers: z.record(z.string(), z.union([z.string(), z.array(z.string())])),
});

…unctionality

- Reduced the number of rows in the ReportMistake input field from 3 to 2 for a more compact design.
- Adjusted the minimum width of the key label in TestResultDisplay from 20 to 16 for better alignment.
- Added a maximum height and overflow handling to the value display in TestResultDisplay, enhancing readability for longer text.
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

🧹 Outside diff range and nitpick comments (7)
apps/web/components/HoverCard.tsx (1)

7-11: LGTM! Consider using ComponentProps for better type safety.

The addition of the optional className prop and its implementation is clean and improves component reusability.

Consider using ComponentProps from React for better type safety:

+import type { ComponentProps } from "react";

 export function HoverCard(props: {
   children: React.ReactNode;
   content: React.ReactNode;
-  className?: string;
+  className?: ComponentProps<typeof HoverCardContent>["className"];
 })

Also applies to: 15-15

apps/web/app/(app)/automation/ExecutedRulesTable.tsx (1)

71-73: LGTM! Consider extracting the width class as a constant.

The width class addition is appropriate for the hover content.

Consider extracting the width class to a shared constant since it's used across multiple components:

// constants/styles.ts
export const HOVER_CARD_WIDTH_CLASS = "w-80" as const;

// Usage
import { HOVER_CARD_WIDTH_CLASS } from "@/constants/styles";
<HoverCard className={HOVER_CARD_WIDTH_CLASS} />
apps/web/utils/actions/validation.ts (1)

101-121: Consider adding additional validation constraints.

While the schema structure is good, consider adding:

  • Email format validation for the from field
  • Maximum length constraints for text fields to prevent excessive data
  • Minimum length constraints for the explanation field when provided
 export const reportAiMistakeBody = z
   .object({
     email: z.object({
-      from: z.string(),
+      from: z.string().email(),
-      subject: z.string(),
+      subject: z.string().max(500),
-      snippet: z.string(),
+      snippet: z.string().max(1000),
       textHtml: z.string().nullish(),
       textPlain: z.string().nullish(),
     }),
     correctRuleId: z.string().nullish(),
     incorrectRuleId: z.string().nullish(),
-    explanation: z.string().nullish(),
+    explanation: z.string().min(10).max(1000).nullish(),
   })
apps/web/utils/ai/rule/rule-fix.ts (1)

94-167: Consider refactoring for better maintainability

The function could be simplified by:

  1. Extracting the schema and examples into separate constants
  2. Using a map or switch statement instead of multiple if blocks
+const RULE_FIX_SCHEMAS = {
+  BOTH_RULES: z.object({
+    rule: z.enum(["matched_rule", "correct_rule"]),
+    fixedInstructions: z.string().describe("The updated instructions"),
+  }),
+  SINGLE_RULE: z.object({
+    fixedInstructions: z.string().describe("The updated instructions"),
+  }),
+};

+const RULE_FIX_EXAMPLES = {
+  BOTH_RULES: [
+    stripIndent(`{...}`), // existing examples
+  ],
+  SINGLE_RULE: [
+    stripIndent(`{...}`), // existing examples
+  ],
+};

 function getRuleFixPromptConfig(
   incorrectRule: Pick<Rule, "instructions"> | null,
   correctRule: Pick<Rule, "instructions"> | null,
 ) {
+  const config = {
+    INCORRECT_AND_CORRECT: {
+      problem: stripIndent(`...`),
+      schema: RULE_FIX_SCHEMAS.BOTH_RULES,
+      examples: RULE_FIX_EXAMPLES.BOTH_RULES,
+    },
+    // ... other configurations
+  };
+
+  const key = getConfigKey(incorrectRule, correctRule);
+  const result = config[key];
+
+  if (!result) throw new Error("No rule to fix");
+  return result;
 }
apps/web/app/(app)/automation/ReportMistake.tsx (2)

146-148: Remove or implement error logging properly

The commented-out error logging should either be removed or properly implemented with a logging service.

-  // if (Object.keys(errors).length > 0) {
-  //   console.error("Errors:", errors);
-  // }

Also applies to: 212-214


150-164: Consider implementing optimistic updates

The form submission handlers could benefit from optimistic updates to improve the user experience. This would involve:

  1. Immediately updating the UI
  2. Rolling back changes if the request fails

Example implementation for updateRule:

const updateRule: SubmitHandler<UpdateRuleBody> = useCallback(
  async (data) => {
    // Store previous value
    const previousValue = rule.instructions;
    
    try {
      // Optimistically update UI
      // Update local state or invalidate SWR cache
      
      const response = await updateRuleAction(data);
      
      if (isActionError(response)) {
        throw new Error(response.error);
      }
      
      toastSuccess({ description: "Rule updated!" });
    } catch (error) {
      // Rollback on error
      // Restore previous value
      
      toastError({
        title: "Error updating rule",
        description: error.message,
      });
    }
  },
  [rule.instructions]
);

Also applies to: 216-242

apps/web/utils/actions/ai-rule.ts (1)

934-943: Consider improving clarity and null handling.

  1. The ternary operator for determining the returned ruleId might be confusing. Consider making it more explicit:
  2. The explanation trimming should check for null/undefined first.
-      explanation: explanation?.trim() || undefined,
+      explanation: explanation ? explanation.trim() : undefined,
+    });
+
+    if (isActionError(result)) return { error: result.error };
+    if (!result) return { error: "Error fixing rule" };
+
+    const ruleId = result.rule === "matched_rule" 
+      ? incorrectRuleId  // Rule matched incorrectly
+      : correctRuleId;   // Rule matched correctly
+
+    return {
+      ruleId,
+      fixedInstructions: result.fixedInstructions,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between decd390 and 8193ca7.

📒 Files selected for processing (10)
  • apps/web/__tests__/ai-rule-fix.test.ts (1 hunks)
  • apps/web/app/(app)/automation/ExecutedRulesTable.tsx (1 hunks)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)
  • apps/web/app/(app)/automation/TestRules.tsx (8 hunks)
  • apps/web/app/api/google/messages/route.ts (1 hunks)
  • apps/web/components/HoverCard.tsx (1 hunks)
  • apps/web/components/PlanBadge.tsx (2 hunks)
  • apps/web/utils/actions/ai-rule.ts (4 hunks)
  • apps/web/utils/actions/validation.ts (1 hunks)
  • apps/web/utils/ai/rule/rule-fix.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/components/PlanBadge.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/tests/ai-rule-fix.test.ts
  • apps/web/app/api/google/messages/route.ts
  • apps/web/app/(app)/automation/TestRules.tsx
🔇 Additional comments (6)
apps/web/utils/actions/validation.ts (1)

95-99: LGTM: Schema definition is clear and appropriate.

The schema correctly defines the required fields for testing AI functionality.

apps/web/utils/ai/rule/rule-fix.ts (2)

46-46: Avoid including user's 'about' information in AI prompts to prevent PII exposure

Including user.about in the AI prompt may expose sensitive personal information.


71-79: Add error handling for chatCompletionObject to improve robustness

The asynchronous call lacks error handling which could lead to unhandled promise rejections.

apps/web/app/(app)/automation/ReportMistake.tsx (1)

221-224: Avoid using alert for user notifications

Using alert can disrupt the user experience and is discouraged in modern web applications.

apps/web/utils/actions/ai-rule.ts (2)

112-119: LGTM! Good improvements to input validation.

The changes enhance type safety and error handling by adding proper validation of the input parameters.


876-945: LGTM! Well-structured implementation with good practices.

The implementation includes:

  • Proper input validation
  • Concurrent data fetching
  • User ownership validation
  • Clear error messages

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: 4

🧹 Outside diff range and nitpick comments (3)
apps/web/utils/actions/validation.ts (1)

87-93: Consider adding length constraints to the instructions field.

The instructions field in updateRuleInstructionsBody should have length constraints to prevent excessively long inputs that could impact performance or storage.

 export const updateRuleInstructionsBody = z.object({
   id: z.string(),
-  instructions: z.string(),
+  instructions: z.string().min(1).max(5000),
 });
apps/web/app/(app)/automation/ReportMistake.tsx (2)

265-267: Improve loading state feedback.

The "Fix with AI" button shows a loading state, but there's no indication of progress or what's happening during the AI processing.

-        <Button type="submit" loading={isSubmitting}>
-          Fix with AI
-        </Button>
+        <Button type="submit" loading={isSubmitting}>
+          {isSubmitting ? "Analyzing with AI..." : "Fix with AI"}
+        </Button>

68-70: Uncomment and update the dialog description.

The commented dialog description would help users understand the feature better.

-          {/* <DialogDescription>
-            Explain what went wrong and our AI will suggest a fix.
-          </DialogDescription> */}
+          <DialogDescription>
+            Select the expected rule and explain what went wrong. Our AI will suggest improvements to make the rules more accurate.
+          </DialogDescription>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8193ca7 and 4da3641.

📒 Files selected for processing (4)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)
  • apps/web/utils/actions/ai-rule.ts (4 hunks)
  • apps/web/utils/actions/rule.ts (2 hunks)
  • apps/web/utils/actions/validation.ts (2 hunks)
🔇 Additional comments (3)
apps/web/app/(app)/automation/ReportMistake.tsx (1)

240-246: Address the TODO comment about undefined ruleId.

The TODO comment indicates uncertainty about when ruleId could be undefined. This should be investigated and properly handled.

Would you like me to help investigate when ruleId could be undefined and implement proper error handling?

apps/web/utils/actions/ai-rule.ts (2)

112-119: Great addition of input validation!

The changes improve security by validating the input data before processing, using proper error handling.


876-945: Well-structured implementation with proper validation and error handling!

The action effectively handles AI mistakes with proper input validation, concurrent data fetching, and comprehensive error handling.

Comment on lines +876 to +945
export const reportAiMistakeAction = withActionInstrumentation(
"reportAiMistake",
async (unsafeBody: ReportAiMistakeBody) => {
const session = await auth();
if (!session?.user.id) return { error: "Not logged in" };

const { success, data, error } = reportAiMistakeBody.safeParse(unsafeBody);
if (!success) return { error: error.message };
const { correctRuleId, incorrectRuleId, email, explanation } = data;

if (!correctRuleId && !incorrectRuleId)
return { error: "Either correct or incorrect rule ID is required" };

const [correctRule, incorrectRule, user] = await Promise.all([
correctRuleId
? prisma.rule.findUnique({
where: { id: correctRuleId, userId: session.user.id },
})
: null,
incorrectRuleId
? prisma.rule.findUnique({
where: { id: incorrectRuleId, userId: session.user.id },
})
: null,
prisma.user.findUnique({
where: { id: session.user.id },
select: {
email: true,
about: true,
aiProvider: true,
aiModel: true,
aiApiKey: true,
},
}),
]);

if (correctRuleId && !correctRule)
return { error: "Correct rule not found" };

if (incorrectRuleId && !incorrectRule)
return { error: "Incorrect rule not found" };

if (!user) return { error: "User not found" };

const content = emailToContent({
textHtml: email.textHtml || null,
textPlain: email.textPlain || null,
snippet: email.snippet,
});

const result = await aiRuleFix({
user,
incorrectRule,
correctRule,
email: {
...email,
content,
},
explanation: explanation?.trim() || undefined,
});

if (isActionError(result)) return { error: result.error };
if (!result) return { error: "Error fixing rule" };

return {
ruleId: result.rule === "matched_rule" ? incorrectRuleId : correctRuleId,
fixedInstructions: result.fixedInstructions,
};
},
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding transaction handling and rate limiting.

To improve reliability and security:

  1. Wrap database operations in a transaction to ensure data consistency
  2. Add rate limiting to prevent potential abuse of the AI service
  3. Enhance error messages to be more descriptive for better debugging

Example implementation:

 export const reportAiMistakeAction = withActionInstrumentation(
   "reportAiMistake",
   async (unsafeBody: ReportAiMistakeBody) => {
     const session = await auth();
     if (!session?.user.id) return { error: "Not logged in" };
 
+    // Add rate limiting
+    const rateLimitKey = `report-ai-mistake:${session.user.id}`;
+    const rateLimit = await getRateLimit(rateLimitKey);
+    if (!rateLimit.success) {
+      return { error: "Too many requests. Please try again later." };
+    }
 
     const { success, data, error } = reportAiMistakeBody.safeParse(unsafeBody);
     if (!success) return { error: error.message };
     const { correctRuleId, incorrectRuleId, email, explanation } = data;
 
     if (!correctRuleId && !incorrectRuleId)
-      return { error: "Either correct or incorrect rule ID is required" };
+      return { error: "Please provide either the correct rule ID or the incorrect rule ID that was applied to this email" };
 
+    // Wrap operations in a transaction
+    return await prisma.$transaction(async (tx) => {
       const [correctRule, incorrectRule, user] = await Promise.all([
         correctRuleId
           ? prisma.rule.findUnique({
               where: { id: correctRuleId, userId: session.user.id },
             })
           : null,
         // ... rest of the implementation
       ]);
+    });
   }
 );

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

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

🧹 Outside diff range and nitpick comments (1)
apps/web/app/(app)/automation/ReportMistake.tsx (1)

270-270: Address the TODO: Determine when ruleId can be undefined

There is a TODO comment questioning when ruleId could be undefined. Clarifying this can prevent potential runtime errors.

Would you like assistance in identifying cases where ruleId might be undefined?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4da3641 and 74cf1d3.

📒 Files selected for processing (2)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)
  • apps/web/app/(app)/automation/TestRules.tsx (7 hunks)
🔇 Additional comments (1)
apps/web/app/(app)/automation/ReportMistake.tsx (1)

253-255: Remove debug console.error statements

Debug console statements should not be present in production code. Consider using proper error logging or monitoring services.

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

🧹 Outside diff range and nitpick comments (5)
apps/web/app/(app)/automation/ReportMistake.tsx (5)

72-74: Remove commented out code

Remove the commented DialogDescription if it's not needed. If it might be needed later, consider tracking it in a TODO ticket instead.

-          {/* <DialogDescription>
-            Explain what went wrong and our AI will suggest a fix.
-          </DialogDescription> */}

57-58: Consider combining related states

The checking and testResult states are closely related. Consider combining them into a single state object for better state management.

-  const [checking, setChecking] = useState(false);
-  const [testResult, setTestResult] = useState<TestResult>();
+  const [testState, setTestState] = useState<{
+    isChecking: boolean;
+    result?: TestResult;
+  }>({ isChecking: false });

277-278: Clarify TODO comment with specific scenarios

The TODO comment about undefined ruleId needs more context. Consider documenting specific scenarios when this could happen or add validation to prevent undefined cases.

-        // TODO: when is ruleId undefined?
+        // TODO: Add validation for undefined ruleId. This can happen when:
+        // 1. <document specific scenarios>

192-206: Extract common form submission logic into a custom hook

Both updateRule and reportMistake handlers share similar error handling patterns. Consider extracting this logic into a custom hook for better reusability.

Example implementation:

function useFormSubmission<T>(
  action: (data: T) => Promise<ActionResponse>,
  successMessage: string
) {
  return useCallback(async (data: T) => {
    const response = await action(data);
    if (isActionError(response)) {
      toastError({
        title: "Error",
        description: response.error,
      });
    } else {
      toastSuccess({ description: successMessage });
      return response;
    }
  }, []);
}

Also applies to: 264-287


329-329: Use design system tokens for colors

Instead of using hardcoded color values, consider using design system tokens for consistency.

-      <div className="mt-2 rounded border border-gray-200 bg-gray-50 p-2 text-sm">
+      <div className="mt-2 rounded border border-border bg-muted p-2 text-sm">
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 74cf1d3 and 7d9c1d1.

📒 Files selected for processing (1)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)

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

🧹 Outside diff range and nitpick comments (3)
apps/web/app/(app)/automation/ReportMistake.tsx (3)

72-74: Remove commented code

Remove the commented DialogDescription to improve code clarity. If the description is needed in the future, track it in a TODO comment or version control instead.

-          {/* <DialogDescription>
-            Explain what went wrong and our AI will suggest a fix.
-          </DialogDescription> */}

106-119: Improve error handling in test rerun

The error handling could be enhanced by clearing the previous test result on error and providing more specific error information.

 const result = await testAiAction({
   messageId: message.id,
   threadId: message.threadId,
 });
 if (isActionError(result)) {
+  setTestResult(undefined);
   toastError({
     title: "There was an error testing the email",
-    description: result.error,
+    description: `Error: ${result.error}. Please try again or contact support if the issue persists.`,
   });
 } else {
   setTestResult(result);
 }

334-347: Enhance error handling and state management

The error handling should be more robust with proper cleanup in all cases and more informative error messages.

 onClick={async () => {
   setIsSaving(true);
-  const res = await updateRuleInstructionsAction({
-    id: ruleId,
-    instructions: fixedInstructions,
-  });
+  try {
+    const res = await updateRuleInstructionsAction({
+      id: ruleId,
+      instructions: fixedInstructions,
+    });

-  if (isActionError(res)) {
-    toastError({ description: res.error });
-  } else {
-    toastSuccess({ description: "Rule updated!" });
-  }
-  setIsSaving(false);
+    if (isActionError(res)) {
+      toastError({
+        title: "Failed to update rule",
+        description: `Error: ${res.error}. Please try again.`
+      });
+    } else {
+      toastSuccess({ description: "Rule updated successfully!" });
+    }
+  } catch (error) {
+    toastError({
+      title: "Unexpected error",
+      description: "Failed to update the rule. Please try again."
+    });
+  } finally {
+    setIsSaving(false);
+  }
 }}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7d9c1d1 and b923b8d.

📒 Files selected for processing (1)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)

<div>
<Label name="matchedRule" label="Matched rule:" />
<div className="mt-1">
<TestResultDisplay result={result!} />
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

Add null check for test result access

The code assumes result is non-null with the ! operator, which could cause runtime errors. Add proper null checking.

-              <TestResultDisplay result={result!} />
+              {result ? (
+                <TestResultDisplay result={result} />
+              ) : (
+                <div>No test result available</div>
+              )}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TestResultDisplay result={result!} />
{result ? (
<TestResultDisplay result={result} />
) : (
<div>No test result available</div>
)}

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

🧹 Outside diff range and nitpick comments (3)
apps/web/utils/actions/ai-rule.ts (1)

116-118: Consider enhancing error message handling.

The error message from safeParse might be too technical for end users. Consider mapping validation errors to more user-friendly messages.

-    if (!success) return { error: error.message };
+    if (!success) {
+      const errorMessage = error.errors.map(err => 
+        `Invalid ${err.path.join('.')}: ${err.message}`
+      ).join('. ');
+      return { error: `Invalid input: ${errorMessage}` };
+    }
apps/web/utils/gmail/thread.ts (1)

85-87: Consider adding type narrowing for better type safety

The implementation is clean and follows good practices. However, we can improve type safety.

Consider this TypeScript improvement:

-export function hasMultipleMessages(thread: gmail_v1.Schema$Thread) {
+export function hasMultipleMessages(thread: gmail_v1.Schema$Thread): boolean {
   return !!thread.messages && thread.messages.length > 1;
 }
apps/web/app/api/google/webhook/process-history.ts (1)

Line range hint 355-424: Consider implementing retry mechanism for transient failures

While the error handling is good for known cases, the webhook processing could benefit from a more robust retry mechanism for transient failures, especially given the async nature of Gmail API operations.

Consider implementing:

  1. Exponential backoff for retries
  2. Dead letter queue for failed operations
  3. Circuit breaker pattern for API calls

This would improve reliability, especially for premium users.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b923b8d and 15479c4.

📒 Files selected for processing (3)
  • apps/web/app/api/google/webhook/process-history.ts (2 hunks)
  • apps/web/utils/actions/ai-rule.ts (7 hunks)
  • apps/web/utils/gmail/thread.ts (1 hunks)
🔇 Additional comments (6)
apps/web/utils/actions/ai-rule.ts (3)

876-945: LGTM! Well-structured implementation with comprehensive error handling.

The function properly validates inputs, handles errors, and coordinates between different services.


878-881: 🛠️ Refactor suggestion

Add rate limiting to prevent potential abuse.

Consider implementing rate limiting to protect the AI service from excessive requests.

   async (unsafeBody: ReportAiMistakeBody) => {
     const session = await auth();
     if (!session?.user.id) return { error: "Not logged in" };
 
+    const rateLimitKey = `report-mistake:${session.user.id}`;
+    const rateLimit = await getRateLimit(rateLimitKey);
+    if (!rateLimit.success) {
+      return { error: "Too many requests. Please try again later." };
+    }

Likely invalid or redundant comment.


889-910: 🛠️ Refactor suggestion

Consider wrapping database operations in a transaction.

The multiple database operations should be wrapped in a transaction to ensure data consistency.

-    const [correctRule, incorrectRule, user] = await Promise.all([
+    const result = await prisma.$transaction(async (tx) => {
+      const [correctRule, incorrectRule, user] = await Promise.all([
       correctRuleId
         ? prisma.rule.findUnique({
             where: { id: correctRuleId, userId: session.user.id },
           })
         : null,
       incorrectRuleId
         ? prisma.rule.findUnique({
             where: { id: incorrectRuleId, userId: session.user.id },
           })
         : null,
       prisma.user.findUnique({
         where: { id: session.user.id },
         select: {
           email: true,
           about: true,
           aiProvider: true,
           aiModel: true,
           aiApiKey: true,
         },
       }),
-    ]);
+      ]);
+      return { correctRule, incorrectRule, user };
+    });
+    const { correctRule, incorrectRule, user } = result;

Likely invalid or redundant comment.

apps/web/app/api/google/webhook/process-history.ts (3)

17-17: LGTM! Clean import addition

The import of hasMultipleMessages is properly organized alongside related functions.


Line range hint 417-424: LGTM! Improved error handling for Gmail API quirks

The error handling is well-documented and properly handles the known Gmail API limitation for snoozed emails. The logging is informative and will help with debugging.


355-355: Verify cold email blocker behavior remains consistent

The switch to hasMultipleMessages is good for maintainability, but we should verify it maintains the same behavior as the previous implementation.

Let's verify the change doesn't affect existing threads:

✅ Verification successful

Based on the search results, I can now provide a definitive response about the cold email blocker behavior:

Cold email blocker behavior remains consistent with hasMultipleMessages implementation

The implementation of hasMultipleMessages in apps/web/utils/gmail/thread.ts directly checks for thread.messages.length > 1, which maintains the same thread validation logic. The cold email blocker specifically requires !isThread (single message) to run, as seen in shouldRunColdEmailBlocker function in process-history.ts:

return (
  coldEmailBlocker &&
  coldEmailBlocker !== ColdEmailSetting.DISABLED &&
  hasColdEmailAccess &&
  !isThread
);

This ensures cold email blocking only triggers on initial (non-thread) messages, maintaining consistent behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any existing cold email blocker implementations to ensure consistent behavior
rg -A 5 "coldEmailBlocker.*thread" --type typescript

Length of output: 89


Script:

#!/bin/bash
# Search for hasMultipleMessages implementation and cold email blocker usage
rg -A 5 "hasMultipleMessages|coldEmailBlocker" 

Length of output: 21202


Script:

#!/bin/bash
# Find the previous implementation using git
git show HEAD~1 -- "apps/web/app/api/google/webhook/process-history.ts"

Length of output: 71


Script:

#!/bin/bash
# Search for thread-related validations
ast-grep --pattern 'function hasMultipleMessages($_) { $$$ }'

Length of output: 295

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

🧹 Outside diff range and nitpick comments (2)
apps/web/app/(app)/automation/ReportMistake.tsx (2)

319-322: Enhance error messages with more specific information

The current error messages could be more helpful by including specific details about what went wrong.

-        toastError({
-          title: "Error reporting mistake",
-          description: response.error,
-        });
+        toastError({
+          title: "Error reporting mistake",
+          description: `Failed to report mistake: ${response.error}. Please ensure all required fields are filled correctly and try again.`,
+        });

40-404: Consider architectural improvements for state management and race conditions

  1. State Management: As the component grows more complex, consider using a state management solution like Zustand or Jotai for better state organization and maintenance.

  2. Race Conditions: The form submissions could potentially race if a user submits multiple times quickly. Consider implementing a debounce mechanism or disabling the submit button during submission.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 15479c4 and d4156a2.

📒 Files selected for processing (1)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)
🔇 Additional comments (3)
apps/web/app/(app)/automation/ReportMistake.tsx (3)

61-61: Replace invalid 'size-4' class with 'h-4 w-4'

The class 'size-4' is not a valid Tailwind CSS utility.


238-240: Remove debug console.error statements

Also applies to: 310-312


327-333: Address TODO comment about undefined ruleId

Comment on lines 117 to 118
// shouldn't happen
<p>No rule matched</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling for the "no rule matched" case

Instead of a comment stating "shouldn't happen", implement proper error handling and logging for this edge case.

-          // shouldn't happen
-          <p>No rule matched</p>
+          <div className="text-red-500">
+            <p>No rule matched. This is unexpected.</p>
+            <p>Please report this issue to the development team.</p>
+          </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// shouldn't happen
<p>No rule matched</p>
<div className="text-red-500">
<p>No rule matched. This is unexpected.</p>
<p>Please report this issue to the development team.</p>
</div>

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

🧹 Outside diff range and nitpick comments (5)
apps/web/app/(app)/automation/ReportMistake.tsx (3)

76-78: Remove commented out DialogDescription

Commented out code should be either removed or implemented. If this description is needed, implement it; otherwise, remove it.

Apply this diff:

-          {/* <DialogDescription>
-            Explain what went wrong and our AI will suggest a fix.
-          </DialogDescription> */}

325-325: Extract success messages to constants

Success messages are duplicated. Consider extracting them to constants for better maintainability.

Apply this diff:

+const SUCCESS_MESSAGES = {
+  RULE_UPDATED: "Rule updated!",
+};
+
 // ... in the components
-        toastSuccess({ description: "Rule updated!" });
+        toastSuccess({ description: SUCCESS_MESSAGES.RULE_UPDATED });

-            toastSuccess({ description: "Rule updated!" });
+            toastSuccess({ description: SUCCESS_MESSAGES.RULE_UPDATED });

Also applies to: 468-468


81-111: Simplify complex conditional rendering

The nested conditional rendering is complex and could be simplified using early returns or component composition.

Consider extracting the conditional logic into a separate component or using early returns:

+const RuleContent = ({ correctRuleId, correctRule, ...props }) => {
+  if (!correctRuleId) {
+    return <RuleMismatch {...props} />;
+  }
+
+  if (!correctRule?.runOnThreads) {
+    return <ImproveRulesOrShowThreadMessage {...props} correctRule={correctRule} correctRuleId={correctRuleId} />;
+  }
+
+  return <ImproveRules {...props} correctRule={correctRule} correctRuleId={correctRuleId} />;
+};

-        {correctRuleId ? (
-          correctRule?.runOnThreads ? (
-            <ImproveRules
-              incorrectRule={incorrectRule}
-              correctRule={correctRule}
-              message={message}
-              result={result}
-              correctRuleId={correctRuleId}
-              setCorrectRuleId={setCorrectRuleId}
-            />
-          ) : (
-            <ImproveRulesOrShowThreadMessage
-              incorrectRule={incorrectRule}
-              correctRule={correctRule}
-              message={message}
-              result={result}
-              correctRuleId={correctRuleId}
-              setCorrectRuleId={setCorrectRuleId}
-              threadId={message.threadId}
-            />
-          )
-        ) : (
-          <RuleMismatch
-            result={result}
-            setCorrectRuleId={setCorrectRuleId}
-            data={data}
-            isLoading={isLoading}
-            error={error}
-            message={message}
-          />
-        )}
+        <RuleContent
+          correctRuleId={correctRuleId}
+          correctRule={correctRule}
+          incorrectRule={incorrectRule}
+          message={message}
+          result={result}
+          setCorrectRuleId={setCorrectRuleId}
+          data={data}
+          isLoading={isLoading}
+          error={error}
+          threadId={message.threadId}
+        />
apps/web/app/api/google/threads/[id]/check/route.ts (2)

6-6: Consider enhancing type documentation

The ThreadCheckResponse type could benefit from JSDoc documentation explaining what isThread represents in the context of Gmail threads.

+/** Response indicating whether a Gmail thread contains multiple messages */
 export type ThreadCheckResponse = { isThread: boolean };

8-12: Consider standardizing error response structure

While the authentication check is correct, consider standardizing the error response structure across all endpoints.

-    return Response.json({ error: "Not logged in" }, { status: 401 });
+    return Response.json(
+      { 
+        error: {
+          code: "UNAUTHORIZED",
+          message: "Not logged in"
+        }
+      },
+      { status: 401 }
+    );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d4156a2 and 34ac7b3.

📒 Files selected for processing (3)
  • apps/web/app/(app)/automation/ReportMistake.tsx (1 hunks)
  • apps/web/app/(app)/automation/TestRules.tsx (7 hunks)
  • apps/web/app/api/google/threads/[id]/check/route.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(app)/automation/TestRules.tsx
🔇 Additional comments (5)
apps/web/app/(app)/automation/ReportMistake.tsx (4)

383-385: Remove debug console.error statements

Debug console statements should not be present in production code. Consider using proper error logging or monitoring service.


400-406: Address TODO comment about undefined ruleId

The TODO comment indicates uncertainty about when ruleId is undefined. This should be properly handled.


68-68: Replace invalid 'size-4' class with 'h-4 w-4'

The class 'size-4' is not a valid Tailwind CSS utility.

Also applies to: 198-198, 279-279


136-138: ⚠️ Potential issue

Add null check for TestResultDisplay component

The current implementation assumes result is non-null when rendering TestResultDisplay. This could lead to runtime errors.

Apply this diff to add proper null checking:

-        {result ? (
-          <TestResultDisplay result={result} />
-        ) : (
-          <p>No rule matched</p>
-        )}
+        {result ? (
+          result.rule ? (
+            <TestResultDisplay result={result} />
+          ) : (
+            <p>Rule evaluation completed but no rule matched</p>
+          )
+        ) : (
+          <p>No evaluation result available</p>
+        )}

Likely invalid or redundant comment.

apps/web/app/api/google/threads/[id]/check/route.ts (1)

1-29: Verify integration with mistake reporting flow

Since this PR is about reporting mistakes during testing, let's verify how this thread checking endpoint is integrated into the mistake reporting flow.

✅ Verification successful

Based on the code analysis, I can now provide a final response about the thread checking endpoint's integration with the mistake reporting flow.

Thread check endpoint is correctly integrated with mistake reporting

The thread check endpoint is used in the ImproveRulesOrShowThreadMessage component to determine if a rule mismatch was due to thread settings rather than incorrect AI instructions. This integration helps users understand and fix rule application issues by:

  • Checking if a message is part of a thread when a rule is configured to not run on threads
  • Providing appropriate feedback to users about why a rule didn't match
  • Guiding users to either fix the rule's thread settings or improve the AI instructions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usages of the thread check endpoint in the mistake reporting components
rg -t typescript -t tsx "threads/[^\"']+/check" 

# Look for components or utilities related to mistake reporting that might use this endpoint
ast-grep --pattern 'function $reportMistake($_) {
  $$$
}'

Length of output: 147


Script:

#!/bin/bash
# Search for usages of the thread check endpoint with correct file extensions
rg -t ts -t tsx "threads/.+/check"

# Look for components or utilities related to mistake reporting
rg -t ts -t tsx "reportMistake|mistake|report" -A 3

# Search for files that might be related to mistake reporting
fd -e ts -e tsx -e js -e jsx . | grep -i "mistake|report"

Length of output: 204


Script:

#!/bin/bash
# Search for usages of the thread check endpoint
rg "threads/.+/check"

# Look for components or utilities related to mistake reporting
rg "reportMistake|mistake|report"

# Find TypeScript/JavaScript files that might contain mistake reporting logic
find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) -exec grep -l -i "mistake\|report" {} \;

Length of output: 97239


Script:

#!/bin/bash
# Search for the ReportMistake component implementation
cat apps/web/app/\(app\)/automation/ReportMistake.tsx

# Look for the validation schema for mistake reporting
cat apps/web/utils/actions/validation.ts

# Look for the action implementation
cat apps/web/utils/actions/ai-rule.ts

Length of output: 44990

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/web/app/(app)/automation/TestRules.tsx (3)

85-127: Consider adding cleanup and error handling for test all functionality

A few suggestions to improve the robustness of the test all implementation:

  1. Reset isTestingAllRef on component unmount
  2. Add error handling for the test all loop
+ useEffect(() => {
+   return () => {
+     isTestingAllRef.current = false;
+   };
+ }, []);

 const handleTestAll = async () => {
   handleStart();
+  try {
     for (const message of data?.messages || []) {
       if (!isTestingAllRef.current) break;
       await onTest(message);
     }
+  } catch (error) {
+    toastError({
+      title: "Error testing all messages",
+      description: error instanceof Error ? error.message : "Unknown error occurred",
+    });
+  } finally {
     handleStop();
+  }
-  handleStop();
 };

Line range hint 324-324: Move MAX_LENGTH constant outside component

The MAX_LENGTH constant should be defined outside the component to prevent recreation on each render.

+const MAX_CONTENT_LENGTH = 280;
+
 export function TestResultDisplay({
   result,
   prefix,
 }: {
   result: TestResult;
   prefix?: string;
 }) {
   if (!result) return null;

   if (result.actionItems) {
-    const MAX_LENGTH = 280;

Line range hint 287-385: Consider extracting alert components and improving type safety

The TestResultDisplay component could be improved by:

  1. Extracting common Alert patterns into reusable components
  2. Using discriminated unions for better type safety
+type BaseAlertProps = {
+  title: string;
+  children: React.ReactNode;
+  variant: "destructive" | "blue";
+};
+
+function RuleAlert({ title, children, variant }: BaseAlertProps) {
+  return (
+    <Alert variant={variant} className="bg-white">
+      {variant === "blue" && <CheckCircle2Icon className="h-4 w-4" />}
+      <AlertTitle>{title}</AlertTitle>
+      <AlertDescription>{children}</AlertDescription>
+    </Alert>
+  );
+}
+
+type TestResult =
+  | { rule: null; reason?: string }
+  | { rule: { name: string; type: RuleType; instructions: string }; actionItems?: any[]; reason?: string };

This would simplify the main component and make it more maintainable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34ac7b3 and d01052c.

📒 Files selected for processing (1)
  • apps/web/app/(app)/automation/TestRules.tsx (9 hunks)
🔇 Additional comments (1)
apps/web/app/(app)/automation/TestRules.tsx (1)

381-381: Replace invalid 'size-4' class with 'h-4 w-4'

The class 'size-4' is not a valid Tailwind CSS utility. Replace it with 'h-4 w-4' to properly size the icon.

-<CircleCheckIcon className="mr-2 size-4" />
+<CircleCheckIcon className="mr-2 h-4 w-4" />

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 (3)
apps/web/app/(app)/automation/TestRules.tsx (3)

85-127: Consider simplifying state management

The current implementation uses both useRef and useState to manage testing state. This could be simplified to improve maintainability.

Consider this alternative implementation:

-  const isTestingAllRef = useRef(false);
-  const [isTestingAll, setIsTestingAll] = useState(false);
+  const [isTestingAll, setIsTestingAll] = useState(false);
   
   const handleTestAll = async () => {
-    handleStart();
+    setIsTestingAll(true);
 
     for (const message of data?.messages || []) {
-      if (!isTestingAllRef.current) break;
+      if (!isTestingAll) break;
       await onTest(message);
     }
 
-    handleStop();
+    setIsTestingAll(false);
   };
 
-  const handleStart = () => {
-    setIsTestingAll(true);
-    isTestingAllRef.current = true;
-  };
-
-  const handleStop = () => {
-    isTestingAllRef.current = false;
-    setIsTestingAll(false);
-  };
+  const handleStop = () => setIsTestingAll(false);

90-106: Enhance error handling for retry scenarios

The current error handling shows a toast but doesn't preserve the error state for potential retry attempts.

Consider adding error state and retry functionality:

+  const [testErrors, setTestErrors] = useState<Record<string, string>>({});

   const onTest = useCallback(async (message: Message) => {
     setIsTesting((prev) => ({ ...prev, [message.id]: true }));
+    setTestErrors((prev) => ({ ...prev, [message.id]: '' }));

     const result = await testAiAction({
       messageId: message.id,
       threadId: message.threadId,
     });
     if (isActionError(result)) {
+      setTestErrors((prev) => ({ ...prev, [message.id]: result.error }));
       toastError({
         title: "There was an error testing the email",
         description: result.error,
       });
     } else {
       setTestResult((prev) => ({ ...prev, [message.id]: result }));
     }
     setIsTesting((prev) => ({ ...prev, [message.id]: false }));
   }, []);

Line range hint 302-389: Consider extracting HoverCard alert content

The alert content in HoverCard could be extracted into separate components to improve maintainability and reusability.

Consider creating separate components for different alert types:

function NoRuleAlert({ result, prefix }: { result: TestResult; prefix?: string }) {
  return (
    <Alert variant="destructive" className="bg-white">
      <AlertTitle>No rule found</AlertTitle>
      <AlertDescription>
        {/* ... existing content ... */}
      </AlertDescription>
    </Alert>
  );
}

function RuleFoundAlert({ result }: { result: TestResult }) {
  return (
    <Alert variant="blue" className="bg-white">
      <CheckCircle2Icon className="h-4 w-4" />
      <AlertTitle>Rule found: "{result.rule.name}"</AlertTitle>
      <AlertDescription>
        {/* ... existing content ... */}
      </AlertDescription>
    </Alert>
  );
}

This would simplify the TestResultDisplay component and make the alert content more maintainable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d01052c and ff2ab07.

📒 Files selected for processing (1)
  • apps/web/app/(app)/automation/TestRules.tsx (8 hunks)
🔇 Additional comments (3)
apps/web/app/(app)/automation/TestRules.tsx (3)

42-42: LGTM: Type definition enhances code clarity

The Message type alias improves type safety and readability by providing a clear interface for message objects.


271-278: Handle undefined testResult case

The current implementation still assumes testResult is defined when showing the result.


385-385: Replace invalid 'size-4' class with 'h-4 w-4'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments