Skip to content

Remove a lot of group functionality to simplify the product and how the AI creates rules for users#316

Merged
elie222 merged 29 commits intomainfrom
autoupdating-groups
Jan 29, 2025
Merged

Remove a lot of group functionality to simplify the product and how the AI creates rules for users#316
elie222 merged 29 commits intomainfrom
autoupdating-groups

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Jan 28, 2025

Summary by CodeRabbit

Based on the comprehensive summary, here are the updated release notes:

  • Major Changes

    • Removed group management functionality across the application.
    • Simplified rule and automation workflows.
    • Enhanced error handling in form submissions.
  • Rule Management

    • Updated rule creation process to exclude group associations.
    • Improved validation for rule names.
    • Added cascading deletion for rules and associated groups.
  • User Experience

    • Introduced new collapsible UI components.
    • Streamlined automation and rule creation interfaces.
    • Removed group-related tabs and modals.
    • Added a new LearnedPatterns component for better pattern management.
  • Technical Improvements

    • Refactored database relationships.
    • Updated type constraints.
    • Simplified condition matching logic.
  • Deprecations

    • Removed group creation and management features.
    • Eliminated group-specific rule types.

@vercel
Copy link

vercel bot commented Jan 28, 2025

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

Name Status Preview Updated (UTC)
inbox-zero ✅ Ready (Inspect) Visit Preview Jan 29, 2025 9:30pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 28, 2025

Warning

Rate limit exceeded

@elie222 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 5 minutes and 24 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 a86f1ac and 737128a.

📒 Files selected for processing (5)
  • apps/web/utils/ai/choose-rule/match-rules.test.ts (3 hunks)
  • apps/web/utils/ai/choose-rule/match-rules.ts (1 hunks)
  • apps/web/utils/ai/rule/create-prompt-from-rule.test.ts (3 hunks)
  • apps/web/utils/ai/rule/create-prompt-from-rule.ts (0 hunks)
  • turbo.json (1 hunks)

Walkthrough

The pull request introduces significant changes to the group and rule management functionalities across multiple files. The primary modifications involve removing group-related components, simplifying rule creation processes, and updating database relationships. Key changes include eliminating group creation modals, modifying rule form interfaces, updating database cascading delete behaviors, and refactoring how rules and groups interact. The changes suggest a strategic simplification of the group management system while maintaining core automation capabilities.

Changes

File Path Change Summary
apps/web/app/(app)/automation/RuleForm.tsx Removed GroupsTab, added LearnedPatterns, updated form error handling
apps/web/app/(app)/automation/group/CreateGroupModal.tsx Entire file removed, including group creation modal logic
apps/web/app/(app)/automation/group/Groups.tsx Removed CreateGroupModalButton, eliminating group creation UI
apps/web/app/(app)/automation/group/ViewGroup.tsx Removed ViewGroupButton, simplified component structure
apps/web/app/(app)/automation/group/[groupId]/page.tsx Removed router functionality related to group deletion
apps/web/app/(app)/automation/page.tsx Removed TabsContent for groups, indicating it's no longer in use
apps/web/prisma/migrations/20250128141602_cascade_delete_group/migration.sql Modified foreign key constraints for cascading deletes
apps/web/prisma/schema.prisma Added cascading delete for groups, added unique constraint on userId
apps/web/utils/actions/ai-rule.ts Updated group and rule creation logic, added error handling
apps/web/utils/actions/group.ts Removed group management functions, simplified item management actions
apps/web/utils/actions/rule.ts Refactored rule management functions, added delete functionality
apps/web/utils/actions/validation.ts Removed group-related schemas, updated rule creation schema
apps/web/utils/ai/group/create-group.ts Comment removed indicating unused code
apps/web/utils/ai/rule/create-prompt-from-rule.ts Disabled functionality for adding group names to prompts
apps/web/utils/condition.ts Removed group condition handling, refactored condition string generation
apps/web/utils/group/group.ts Entire createGroup function removed
apps/web/utils/rule/rule.ts Updated function signatures and logic for rule management
apps/web/utils/ai/assistant/process-user-request.ts Shifted focus from group items to pattern management
apps/web/app/(app)/automation/group/LearnedPatterns.tsx Introduced new LearnedPatterns component for UI
apps/web/components/ui/collapsible.tsx New collapsible component implemented using Radix UI
apps/web/package.json Added dependency for Radix UI collapsible components
apps/web/app/(app)/automation/rule/create/page.tsx Updated type definitions for conditions, excluding groups
apps/web/utils/ai/choose-rule/match-rules.ts Restructured logic for matching rules, focusing on static rules
apps/web/app/(app)/automation/create/examples.tsx Removed group ID constants, shifted to AI-driven instructions
apps/web/utils/ai/rule/create-rule-schema.ts Removed group field from rule schema
apps/web/utils/config.ts Removed GroupName constant

Poem

🐰 A Rabbit's Ode to Code Refactoring

Groups vanish like carrots in the night,
Rules dance with simpler, leaner might,
Cascading deletes, a database dream,
Complexity fades like morning's gleam!

hop hop 🥕✨


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

🔭 Outside diff range comments (1)
apps/web/utils/ai/rule/create-prompt-from-rule.ts (1)

Group condition code is commented out but tests still expect it to work

The removal of the group condition appears to be unintentional as the test file create-prompt-from-rule.test.ts still includes test cases that expect group conditions to work. This mismatch between implementation and tests needs to be addressed.

  • apps/web/utils/ai/rule/create-prompt-from-rule.ts: Commented out group condition code (lines 33-42)
  • apps/web/utils/ai/rule/create-prompt-from-rule.test.ts: Contains active test cases for group conditions
🔗 Analysis chain

Line range hint 23-92: Verify prompt generation without group condition.

The removal of the group condition from the prompt generation might affect the AI's understanding of the rule context. Please verify if this is intentional and if the AI model has been retrained or updated to handle prompts without group information.

Let's check for any AI model or prompt-related configurations that might need updating:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for AI model configurations and prompt templates

# Search for AI model configurations
echo "Searching for AI model configurations..."
fd -e json -e yaml -e env . | xargs rg -l "model|prompt|openai"

# Search for other prompt generation functions
echo "Searching for other prompt generators..."
rg -A 5 "createPrompt|generatePrompt" "apps/web"

Length of output: 15357

🧹 Nitpick comments (6)
apps/web/utils/condition.ts (2)

208-214: Consider extracting static field names into constants.

The implementation is clean and well-organized. For better maintainability and consistency, consider extracting the field labels ("From", "Subject", "To", "Body") into constants.

+const STATIC_FIELD_LABELS = {
+  from: "From",
+  subject: "Subject",
+  to: "To",
+  body: "Body",
+} as const;

 const staticConditions: string[] = [];
-if (rule.from) staticConditions.push(`From: "${rule.from}"`);
-if (rule.subject) staticConditions.push(`Subject: "${rule.subject}"`);
-if (rule.to) staticConditions.push(`To: "${rule.to}"`);
-if (rule.body) staticConditions.push(`Body: "${rule.body}"`);
+if (rule.from) staticConditions.push(`${STATIC_FIELD_LABELS.from}: "${rule.from}"`);
+if (rule.subject) staticConditions.push(`${STATIC_FIELD_LABELS.subject}: "${rule.subject}"`);
+if (rule.to) staticConditions.push(`${STATIC_FIELD_LABELS.to}: "${rule.to}"`);
+if (rule.body) staticConditions.push(`${STATIC_FIELD_LABELS.body}: "${rule.body}"`);

219-233: Consider improvements to category handling.

While the implementation works well, there are a few potential improvements:

  1. Extract the magic number 3 into a named constant
  2. Use template literals consistently
  3. Extract the pluralization logic into a helper function
+const MAX_DISPLAYED_CATEGORIES = 3;
+const pluralize = (word: string, count: number) => count === 1 ? word : `${word}s`;

 const categoryFilters = rule.categoryFilters;
 if (rule.categoryFilterType && categoryFilters?.length) {
-  const max = 3;
   const categories =
     categoryFilters
-      .slice(0, max)
+      .slice(0, MAX_DISPLAYED_CATEGORIES)
       .map((category) => category.name)
-      .join(", ") + (categoryFilters.length > max ? ", ..." : "");
+      .join(", ") + (categoryFilters.length > MAX_DISPLAYED_CATEGORIES ? ", ..." : "");

   conditions.push(
-    `${rule.categoryFilterType === CategoryFilterType.EXCLUDE ? "Exclude " : ""}${
-      categoryFilters.length === 1 ? "Category" : "Categories"
-    }: ${categories}`,
+    `${rule.categoryFilterType === CategoryFilterType.EXCLUDE ? "Exclude " : ""}${
+      pluralize("Category", categoryFilters.length)
+    }: ${categories}`
   );
 }
apps/web/prisma/schema.prisma (2)

279-284: Consider further Group model simplification.

The comments indicate that the Group model has evolved significantly:

  1. Groups are now rule-dependent
  2. The prompt and name fields are no longer actively used
  3. There's potential for further simplification by removing the Group model entirely

Consider creating a follow-up ticket to evaluate the suggested model simplification.

Would you like me to help create an issue to track the potential Group model simplification?


284-284: Document the Group model transition strategy.

Since the Group model is in transition:

  1. Consider adding a deprecation timeline in the comments
  2. Document the migration path for existing groups
  3. Plan for handling the 1:1 relationship between Rule and Group

This will help track the evolution of the model and ensure smooth transitions in future updates.

apps/web/app/(app)/automation/group/ViewGroup.tsx (1)

109-119: Ensure server/client time consistency
The "New!" badge logic uses client-side time to determine recency. If there's a clock mismatch between server and client, items added slightly over two minutes ago might still appear as "New!" or vice versa. Depending on requirements, consider server-synchronized timestamps.

apps/web/app/(app)/automation/group/[groupId]/page.tsx (1)

4-4: Remove or refactor the comment
Line 4 states: “Not in use anymore. Could delete this.” If confirmed unused, removing this code or comment will keep the file tidy and reduce confusion.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b04d429 and b54f0ff.

📒 Files selected for processing (17)
  • apps/web/app/(app)/automation/RuleForm.tsx (9 hunks)
  • apps/web/app/(app)/automation/group/CreateGroupModal.tsx (0 hunks)
  • apps/web/app/(app)/automation/group/Groups.tsx (0 hunks)
  • apps/web/app/(app)/automation/group/ViewGroup.tsx (7 hunks)
  • apps/web/app/(app)/automation/group/[groupId]/page.tsx (1 hunks)
  • apps/web/app/(app)/automation/page.tsx (1 hunks)
  • apps/web/prisma/migrations/20250128141602_cascade_delete_group/migration.sql (1 hunks)
  • apps/web/prisma/schema.prisma (2 hunks)
  • apps/web/utils/actions/ai-rule.ts (13 hunks)
  • apps/web/utils/actions/group.ts (1 hunks)
  • apps/web/utils/actions/rule.ts (3 hunks)
  • apps/web/utils/actions/validation.ts (1 hunks)
  • apps/web/utils/ai/group/create-group.ts (1 hunks)
  • apps/web/utils/ai/rule/create-prompt-from-rule.ts (1 hunks)
  • apps/web/utils/condition.ts (1 hunks)
  • apps/web/utils/group/group.ts (2 hunks)
  • apps/web/utils/rule/rule.ts (4 hunks)
💤 Files with no reviewable changes (2)
  • apps/web/app/(app)/automation/group/CreateGroupModal.tsx
  • apps/web/app/(app)/automation/group/Groups.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/web/utils/ai/group/create-group.ts
🔇 Additional comments (41)
apps/web/app/(app)/automation/page.tsx (1)

64-67: Verify complete removal of group-related code.

Let's ensure all related group functionality has been properly removed across the codebase.

apps/web/utils/ai/rule/create-prompt-from-rule.ts (1)

Line range hint 9-19: Verify if group-related types should be removed.

The RuleWithRelations type still includes the group property and its related types. If group functionality is being removed, should these type definitions be updated as well?

Let's verify the usage of group-related types:

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

204-207: LGTM! Good refactoring to array-based approach.

The change from string concatenation to array-based string building improves maintainability and performance.


216-217: LGTM! Clean and straightforward implementation.


240-240: LGTM! Clean implementation.

The final join operation correctly uses the conditional operator to combine all conditions.

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

4-4: No issues with this import.
It correctly references the Prisma client for database operations.

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

3-3: New typed import looks good.
Using gmail_v1 from @googleapis/gmail improves type-safety for Gmail operations.


42-44: New rule and group-related imports.
These imports for deleteRule, safeCreateRule, safeUpdateRule, createNewsletterGroup, and createReceiptGroup align with the redesigned group management flow. They're organized and clear.


193-195: Access token check before Gmail usage.
This block ensures that the user session has a valid access token before making Gmail API calls, enhancing reliability and error handling.


219-225: Modular retrieval of group ID.
This call to getGroupId for retrieving or creating a relevant group keeps the code clean and maintainable.


227-227: Rule creation with group link.
Passing groupIdResult.groupId into safeCreateRule properly associates the new rule with a specific group.


233-240: Expanded function signature for getGroupId.
Adding userEmail, gmail, and accessToken parameters centralizes the logic needed for group creation. The return structure providing groupId, existingRuleId, or an error is flexible and comprehensive.


263-270: Creating or returning an existing newsletter group.
Using createNewsletterGroup here is a streamlined approach. The check for "error" in result ensures early returns for failures.


292-299: Creating or returning an existing receipt group.
Mirrors the newsletter group logic, preserving consistency and clarity.


309-309: Returning the identified groupId.
Clean exit from the getGroupId function, ensuring the final outcome is concise and unambiguous.


405-405: Access token check for saveRulesPromptAction.
Again, verifying session.accessToken before Gmail-related logic prevents invalid calls.


552-555: Deleting a rule with optional group reference.
Passing groupId into deleteRule helps ensure that any related database references can be cleaned up or handled appropriately.


599-607: Retrieving or creating group for rule edits.
This block fetches a groupIdResult for an existing rule and properly checks for errors before proceeding, avoiding partial updates.


627-627: Safe rule update with new group reference.
Leveraging safeUpdateRule centralizes validation and ensures the rule is updated only if constraints are met.


656-663: Ensuring group presence for new rules.
Invoking getGroupId again for newly added rules maintains consistency and reusability.


676-676: Associating the created rule with its group.
Providing groupIdResult?.groupId finalizes the link between the rule and the newly formed or existing group.

apps/web/utils/group/group.ts (5)

1-6: Comprehensive imports for group support.
Pulling in gmail_v1, findNewsletters, and findReceipts provides a well-rounded approach for creating specialized groups (e.g., newsletter and receipt groups).


10-15: Enhanced createGroup signature.
Accepting an optional ruleId is a clean way to link a newly created group to an existing rule if needed.


25-25: Conditional rule connection.
Using ruleId ? { connect: { id: ruleId } } : undefined ensures that a group is only associated with a rule when appropriate without forcing a relationship.


38-68: Creation of newsletter group with discovered items.

  • Finds matching "newsletter" senders via findNewsletters.
  • Creates a group with those senders as items.
  • Returns the newly created group's ID.

This approach is straightforward, keeps the business logic separated, and gracefully handles the case of an existing group.


70-97: Parallel receipt group logic.
Similar to the newsletter creation, it finds matching receipts and constructs a group. Reusing the same pattern ensures maintainability and reduces complexity.

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

118-118: LGTM! Good validation enhancement.

Adding a minimum length validation with a custom error message for the rule name is a good practice to prevent empty names.

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

34-39: LGTM! Improved function parameter organization.

The refactoring to use object destructuring for parameters improves code readability and maintainability.

Also applies to: 44-49, 78-83


99-109: LGTM! Enhanced type safety with object parameters.

The function signature change to use a typed object parameter improves type safety and makes the function more maintainable.

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

90-101: LGTM! Good handling of group creation.

The code correctly checks for GROUP type conditions and creates a group when needed. The implementation is clean and follows a good separation of concerns.


289-292: LGTM! Proper use of the new deleteRule function.

The code correctly passes all required parameters to the new deleteRule function.

apps/web/app/(app)/automation/RuleForm.tsx (3)

181-194: LGTM! Enhanced error feedback.

Good improvement to error handling UI that shows all validation errors in a clear, user-friendly list format.


320-320: LGTM! Improved field placeholders.

The email field placeholders now provide clearer examples using a standard email format.

Also applies to: 331-331


726-741: LGTM! Improved group management UI.

The GroupsTab component has been simplified and improved with:

  1. Clear description of group functionality
  2. Proper scrollable area for group items
  3. Better user guidance when no group exists
apps/web/prisma/migrations/20250128141602_cascade_delete_group/migration.sql (2)

1-5: LGTM! Cascading constraints properly configured.

The foreign key modification correctly implements cascading delete and update behavior between Rules and Groups, which aligns with the auto-updating groups objective.


7-13: Verify the impact of group deletion.

The cleanup query removes orphaned groups, which is good practice. However, ensure there's no critical data in these groups that might need to be preserved.

Run this script to assess the impact:

✅ Verification successful

Orphaned group deletion is safe to proceed

The cleanup is safe because:

  • Groups are only meaningful when attached to rules (per schema design)
  • Orphaned groups by definition have no rules using them
  • Cascade delete is properly configured for related data
  • This aligns with the documented evolution of the Group model
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for groups that would be deleted and their associated data

# Find groups that would be deleted
echo "Groups that would be deleted:"
rg -l "Group" | xargs ast-grep --pattern 'group.*=.*Group.*{.*}' -

# Check for any references to Group in other parts of the codebase
echo "References to Group in the codebase:"
rg "Group\." --type ts --type tsx

Length of output: 282


Script:

#!/bin/bash
# Check Prisma schema and Group usage
echo "=== Prisma Schema ==="
cat apps/web/prisma/schema.prisma

echo -e "\n=== Group Usage in Code ==="
# Search in all files without extension filtering
rg "Group" -A 3 -B 3

echo -e "\n=== Group Model Relations ==="
# Look specifically for relations in schema
rg "Group.*{" -A 10 apps/web/prisma/schema.prisma

Length of output: 77615

apps/web/prisma/schema.prisma (1)

194-194: LGTM! Cascade delete properly configured in schema.

The onDelete: Cascade directive on the Rule-Group relation matches the SQL migration and ensures referential integrity.

apps/web/app/(app)/automation/group/ViewGroup.tsx (3)

4-5: Imports verified and consistent
These newly introduced imports appear aligned with their usage in the code below and do not conflict with existing dependencies or functionalities.

Also applies to: 19-20, 25-25, 35-36


38-38: Handle null groupId scenario
If groupId can indeed be null, the call to /api/user/group/${groupId}/items might fail or cause unexpected behavior. Consider returning early or rendering a fallback UI when groupId is null to avoid unexpected errors.


47-49: Consider hooking up the toggle control
The "Auto-add patterns" toggle is always enabled with an empty onChange handler. If auto-adding patterns is intended, consider wiring up the toggle to the relevant state or removing the toggle if it’s not yet needed.

Also, the new "Add Item" and "Matches" buttons look correct, but double-check that groupId won’t be null to avoid invalid URLs or form submissions.

Also applies to: 51-52, 54-65, 66-74, 76-86

apps/web/app/(app)/automation/group/[groupId]/page.tsx (1)

9-9: Confirm groupId usage
Calling <ViewGroup groupId={params.groupId} /> matches the revised signature. Consider handling invalid or missing IDs to avoid rendering issues.

Comment on lines +64 to 67
{/* no longer in use */}
<TabsContent value="groups" className="content-container mb-10">
<Groups />
</TabsContent>
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

Remove unused Groups tab content.

The Groups tab trigger is commented out in the UI, but the corresponding TabsContent and component are still present. This creates dead code that's loaded but inaccessible.

Apply this diff to clean up the unused code:

-        {/* no longer in use */}
-        <TabsContent value="groups" className="content-container mb-10">
-          <Groups />
-        </TabsContent>

Also remove the unused import:

-import { Groups } from "@/app/(app)/automation/group/Groups";

Comment on lines +235 to +237
// Group condition
if (rule.groupId) {
conditions.push("Group");
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

Include group name in the output string.

The current implementation only shows "Group" without any identifying information. Since the group name is available in the type definition (group?: { name: string } | null), consider including it in the output string for better clarity.

 if (rule.groupId) {
-  conditions.push("Group");
+  conditions.push(`Group: ${rule.group?.name ?? "Unknown"}`);
 }
📝 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
// Group condition
if (rule.groupId) {
conditions.push("Group");
// Group condition
if (rule.groupId) {
conditions.push(`Group: ${rule.group?.name ?? "Unknown"}`);

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (6)
apps/web/utils/actions/group.ts (1)

41-41: Consider adding error handling for the update operation.
If the group item does not exist, or if an unrelated database error occurs, the user receives no immediate feedback. A try/catch block around rejectGroupItem can help gracefully handle transient failures.

 export const rejectGroupItemAction = withActionInstrumentation(
   "rejectGroupItem",
   async (id: string) => {
     const session = await auth();
     if (!session?.user.id) return { error: "Not logged in" };

+    try {
       await rejectGroupItem({ id, userId: session.user.id });
+    } catch (error) {
+      return { error: "Failed to reject group item. Please try again." };
+    }

     revalidatePath("/automation");
   },
 );
apps/web/utils/group/group-item.ts (1)

21-31: Switching from deletion to setting a REJECTED status is a solid approach.
By preserving a record of rejected items, you enable future auditing, analytics, or potential recovery. If needed, consider adding a timestamp or reason field to further enhance traceability.

apps/web/app/(app)/automation/group/ViewGroup.tsx (4)

84-92: Add security attributes to external link

The external link opens in a new tab but is missing recommended security attributes.

Add rel="noopener noreferrer" to prevent potential security vulnerabilities:

              <Link
                href={`/automation/group/${groupId}/examples`}
                target="_blank"
+               rel="noopener noreferrer"
              >

191-193: Prevent potential race condition in form submission

The form submission could be triggered multiple times if the user clicks rapidly.

Add a loading state check:

        onClick={() => {
+         if (isSubmitting) return;
          handleSubmit(onSubmit)();
        }}

211-214: Optimize status grouping

The default status fallback could be moved to the groupBy selector for better clarity.

Consider this optimization:

-  const groupedByStatus = groupBy(
-    items,
-    (item) => item.status || GroupItemStatus.APPROVED,
-  );
+  const groupedByStatus = groupBy(items, 'status');
+  const approvedItems = groupedByStatus[GroupItemStatus.APPROVED] ?? 
+    groupedByStatus[null] ?? [];

263-264: Extract time comparison logic

The time comparison logic could be extracted into a utility function for reusability and testing.

Consider creating a utility function:

const isWithinLastMinutes = (date: Date, minutes: number) => {
  const threshold = new Date(Date.now() - 1000 * 60 * minutes);
  return new Date(date) > threshold;
};
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b54f0ff and 7fe7e06.

📒 Files selected for processing (8)
  • apps/web/app/(app)/automation/ReportMistake.tsx (2 hunks)
  • apps/web/app/(app)/automation/group/ViewGroup.tsx (6 hunks)
  • apps/web/app/(app)/automation/rule/[ruleId]/examples/example-list.tsx (2 hunks)
  • apps/web/prisma/migrations/20250128220758_group_item_status/migration.sql (1 hunks)
  • apps/web/prisma/schema.prisma (4 hunks)
  • apps/web/utils/actions/group.ts (2 hunks)
  • apps/web/utils/ai/assistant/process-user-request.ts (2 hunks)
  • apps/web/utils/group/group-item.ts (2 hunks)
🔇 Additional comments (17)
apps/web/utils/actions/group.ts (3)

4-4: No issues with the updated import statement.


11-11: Importing both addGroupItem and rejectGroupItem is consistent with the new item-rejection flow.


35-36: Clear and concise naming for the new rejectGroupItemAction.

apps/web/utils/group/group-item.ts (1)

2-2: Importing GroupItemStatus to set the item’s status to REJECTED aligns nicely with an auditable workflow.

apps/web/app/(app)/automation/rule/[ruleId]/examples/example-list.tsx (1)

8-8: Import alignment is correct for the new rejection-based flow.

apps/web/utils/ai/assistant/process-user-request.ts (2)

20-20: Import statement updated to reflect new group item management approach.

The change from deleteGroupItem to rejectGroupItem aligns with the new status-based approach for managing group items.


391-393: Function call updated to use status-based rejection.

The implementation now uses rejectGroupItem instead of deleteGroupItem, which is a better approach as it:

  • Preserves historical data
  • Enables potential recovery of rejected items
  • Provides better audit trails
apps/web/app/(app)/automation/ReportMistake.tsx (2)

52-52: Import statement updated to use new group item management action.

The change from deleteGroupItemAction to rejectGroupItemAction maintains consistency with the new status-based approach.


546-546: Function call updated to use status-based rejection.

The implementation now uses rejectGroupItemAction instead of deletion, which is more maintainable and provides better data preservation.

apps/web/prisma/migrations/20250128220758_group_item_status/migration.sql (2)

1-2: Well-designed enum type for group item status management.

The GroupItemStatus enum provides clear states for managing group items:

  • APPROVED: Auto-approve matching emails
  • REJECTED: Auto-reject matching emails
  • NEEDS_AI: Require AI verification

4-5: Good default value choice for the status column.

Setting the default status to 'APPROVED' maintains backward compatibility with existing group items.

apps/web/prisma/schema.prisma (4)

194-194: Good addition of cascade deletion for group-rule relationship.

The onDelete: Cascade directive ensures referential integrity when a group is deleted.


279-284: Helpful documentation about group management evolution.

The comments provide valuable context about:

  • Historical group management approach
  • Current dependency on rules
  • Potential future cleanup of detached groups
  • Deprecation of certain fields

300-307: Well-structured GroupItem model with status management.

The model includes:

  • Proper cascade deletion for group relationship
  • Status field with appropriate default value
  • Unique constraint on (groupId, type, value)

466-470: Clear documentation of GroupItemStatus enum values.

Each status value is well-documented with its specific use case:

  • APPROVED: Auto-approve matching emails
  • REJECTED: Auto-reject matching emails
  • NEEDS_AI: Require AI verification before approval
apps/web/app/(app)/automation/group/ViewGroup.tsx (2)

132-132: Remove non-null assertion operator

Using groupId! in defaultValues is unsafe as groupId is nullable.

Add a validation check or provide a default value:

-    defaultValues: { groupId: groupId! },
+    defaultValues: { groupId: groupId ?? '' },

Line range hint 316-332: LGTM! Well-structured presentational component

The GroupItemDisplay component is well-implemented with clear separation of concerns and proper type safety.

className="mt-4 text-wrap"
onClick={() => {
const result = deleteGroupItemAction(matchingGroupItem.id);
const result = rejectGroupItemAction(matchingGroupItem.id);
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

Use await to handle the asynchronous server action properly.
Without await, isActionError(result) might not receive the resolved result, which could lead to silent failures or inconsistent UI updates.

- const result = rejectGroupItemAction(matchingGroupItem.id);
+ const result = await rejectGroupItemAction(matchingGroupItem.id);
📝 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 result = rejectGroupItemAction(matchingGroupItem.id);
const result = await rejectGroupItemAction(matchingGroupItem.id);

Comment on lines 284 to 299
<Button
variant="outline"
size="icon"
onClick={async () => {
const result = await rejectGroupItemAction(item.id);
if (isActionError(result)) {
toastError({
description: `Failed to remove ${item.value} from group. ${result.error}`,
});
} else {
mutate();
}
}}
>
<TrashIcon className="size-4" />
</Button>
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 confirmation dialog for delete operation

The delete operation lacks a confirmation dialog, which could lead to accidental deletions.

Add a confirmation dialog before deletion:

                <Button
                  variant="outline"
                  size="icon"
                  onClick={async () => {
+                   if (!confirm('Are you sure you want to delete this item?')) return;
                    const result = await rejectGroupItemAction(item.id);
📝 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
<Button
variant="outline"
size="icon"
onClick={async () => {
const result = await rejectGroupItemAction(item.id);
if (isActionError(result)) {
toastError({
description: `Failed to remove ${item.value} from group. ${result.error}`,
});
} else {
mutate();
}
}}
>
<TrashIcon className="size-4" />
</Button>
<Button
variant="outline"
size="icon"
onClick={async () => {
if (!confirm('Are you sure you want to delete this item?')) return;
const result = await rejectGroupItemAction(item.id);
if (isActionError(result)) {
toastError({
description: `Failed to remove ${item.value} from group. ${result.error}`,
});
} else {
mutate();
}
}}
>
<TrashIcon className="size-4" />
</Button>

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)/automation/RuleForm.tsx (1)

729-744: Consider improving the GroupsTab implementation.

While the conditional rendering and scrollable area for groups work well, there are a few suggestions for improvement:

  1. The hardcoded ScrollArea height (310px) might not be responsive. Consider using dynamic sizing based on viewport height or container size.
  2. The description text could be more concise while maintaining clarity.

Consider this alternative implementation:

-        Advanced: Groups are usually managed by our AI. A group is a static
-        collection of senders and subjects. Our AI collects these for you to
-        more efficiently match future emails.
+        Groups are AI-managed collections of senders and subjects, automatically
+        gathered to improve email matching efficiency.

-          <ScrollArea className="h-[310px]">
+          <ScrollArea className="max-h-[50vh]">
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7fe7e06 and cef80f3.

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

183-196: Well-implemented form error handling!

The error handling implementation follows best practices by showing validation errors only after form submission and presenting them in an accessible, structured list format.


261-261: LGTM - Group condition type added consistently.

The Group condition type is properly integrated into the existing condition types array.


323-323: Good placeholder text improvements!

The placeholders now provide clear, consistent examples of the expected email format.

Also applies to: 334-334

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

🧹 Nitpick comments (7)
apps/web/app/(app)/automation/group/ViewGroup.tsx (2)

272-274: Extract time-based badge logic.

Consider extracting the time-based badge logic into a separate utility function for better reusability and testability.

+const isRecentlyModified = (date: Date) => {
+  const twoMinutesAgo = new Date(Date.now() - 1000 * 60 * 2);
+  return new Date(date) > twoMinutesAgo;
+};
+
 function GroupItemList({ ... }) {
   return (
     <Table>
       <TableBody>
         {items.map((item) => {
-          const twoMinutesAgo = new Date(Date.now() - 1000 * 60 * 2);
-          const isCreatedRecently = new Date(item.createdAt) > twoMinutesAgo;
-          const isUpdatedRecently = new Date(item.updatedAt) > twoMinutesAgo;
+          const isCreatedRecently = isRecentlyModified(item.createdAt);
+          const isUpdatedRecently = isRecentlyModified(item.updatedAt);

64-72: Consider implementing auto-add patterns functionality.

The commented-out Toggle component suggests an incomplete feature for automatically detecting and adding new matching patterns from incoming emails.

Would you like me to help implement the auto-add patterns functionality or create an issue to track this task?

apps/web/app/(app)/automation/RuleForm.tsx (4)

191-204: Consider grouping errors by section.

While the error display is functional, consider organizing errors by their respective sections (Conditions, Actions) for better user experience.

   {isSubmitted && Object.keys(errors).length > 0 && (
     <div className="mt-4">
       <AlertError
         title="Error"
         description={
-          <ul className="list-disc">
-            {Object.values(errors).map((error) => (
-              <li key={error.message}>{error.message}</li>
-            ))}
-          </ul>
+          <div className="space-y-2">
+            {errors.conditions && (
+              <div>
+                <strong>Conditions:</strong>
+                <ul className="list-disc pl-4">
+                  {Object.values(errors.conditions).map((error) => (
+                    <li key={error.message}>{error.message}</li>
+                  ))}
+                </ul>
+              </div>
+            )}
+            {errors.actions && (
+              <div>
+                <strong>Actions:</strong>
+                <ul className="list-disc pl-4">
+                  {Object.values(errors.actions).map((error) => (
+                    <li key={error.message}>{error.message}</li>
+                  ))}
+                </ul>
+              </div>
+            )}
+          </div>
         }
       />
     </div>
   )}

501-505: Consider handling loading state for LearnedPatterns.

The LearnedPatterns component might benefit from a loading state to improve user experience during data fetching.

   {rule.groupId && (
     <div className="mt-4">
+      <LoadingContent
+        loading={isLoading}
+        error={error}
+        loadingComponent={<Skeleton className="h-24" />}
+      >
         <LearnedPatterns groupId={rule.groupId} />
+      </LoadingContent>
     </div>
   )}

191-204: Enhance error message formatting for better user experience.

While the consolidated error display is good, the error messages could be more user-friendly by adding context and formatting.

Consider enhancing the error display:

               <ul className="list-disc">
-                {Object.values(errors).map((error) => (
-                  <li key={error.message}>{error.message}</li>
+                {Object.entries(errors).map(([field, error]) => (
+                  <li key={error.message}>
+                    {capitalCase(field)}: {error.message}
+                  </li>
                ))}
               </ul>

501-505: Consider adding error boundary for LearnedPatterns.

The LearnedPatterns component is rendered without error boundary protection, which could cause the entire form to fail if there's an error in the component.

Consider wrapping the component with an error boundary:

       {rule.groupId && (
         <div className="mt-4">
+          <ErrorBoundary fallback={<div>Error loading learned patterns</div>}>
             <LearnedPatterns groupId={rule.groupId} />
+          </ErrorBoundary>
         </div>
       )}
apps/web/prisma/schema.prisma (1)

279-284: Consider cleaning up deprecated group functionality.

The comments indicate significant architectural changes:

  1. Groups are now dependent on rules
  2. Some fields like "Prompt" and "Name" are no longer used
  3. There are detached groups that might need cleanup

Consider:

  1. Making the rule field required in the Group model
  2. Removing unused fields
  3. Creating a migration to clean up detached groups

Would you like me to help create a cleanup migration?

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between cef80f3 and cc5c155.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • apps/web/app/(app)/automation/RuleForm.tsx (9 hunks)
  • apps/web/app/(app)/automation/group/LearnedPatterns.tsx (1 hunks)
  • apps/web/app/(app)/automation/group/ViewGroup.tsx (5 hunks)
  • apps/web/components/ui/collapsible.tsx (1 hunks)
  • apps/web/package.json (1 hunks)
  • apps/web/prisma/migrations/20250128221751_group_item_status/migration.sql (1 hunks)
  • apps/web/prisma/schema.prisma (4 hunks)
  • apps/web/utils/actions/validation.ts (1 hunks)
  • apps/web/utils/condition.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/condition.ts
👮 Files not reviewed due to content moderation or server errors (2)
  • apps/web/app/(app)/automation/group/ViewGroup.tsx
  • apps/web/app/(app)/automation/RuleForm.tsx
🔇 Additional comments (26)
apps/web/package.json (1)

44-44: LGTM! Good choice of UI library.

The addition of @radix-ui/react-collapsible from Radix UI is a solid choice for implementing accessible collapsible components.

apps/web/components/ui/collapsible.tsx (1)

1-11: LGTM! Clean and maintainable implementation.

The component follows best practices:

  • Uses "use client" directive appropriately
  • Implements a clean re-export pattern for Radix UI components
  • Maintains simplicity while allowing for future customization
apps/web/utils/actions/validation.ts (1)

117-119: LGTM! Improved validation with better error handling.

The changes enhance the schema by:

  • Adding minimum length validation for the name field with a user-friendly error message
  • Making groupId optional while maintaining type safety
apps/web/app/(app)/automation/group/LearnedPatterns.tsx (3)

14-17: LGTM! Clean state management.

The component uses appropriate state hooks for managing the collapsible state and auto-learn toggle.


24-48: LGTM! Well-structured trigger section.

The collapsible trigger implementation:

  • Uses semantic HTML structure
  • Provides clear visual feedback with the chevron icon
  • Includes helpful tooltip explanation

50-52: Verify ViewGroup component implementation.

The ViewGroup component is rendered with groupId, but its implementation needs verification to ensure it handles the group display logic previously managed in this component.

✅ Verification successful

ViewGroup component implementation is properly handling all group display logic

The component is well-implemented with comprehensive functionality including:

  • Group items fetching and management
  • Pattern addition and removal
  • Organized display of patterns by status
  • Proper loading and error states
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for ViewGroup component implementation
ast-grep --pattern 'export function ViewGroup({ groupId }: { groupId: string }) {
  $$$
}'

Length of output: 92


Script:

#!/bin/bash
# Search for ViewGroup component with flexible pattern
ast-grep --pattern 'ViewGroup = $$$'

# Search for ViewGroup component declaration
ast-grep --pattern 'function ViewGroup$$$'

# Search for ViewGroup imports and usage
rg "ViewGroup" -A 2

# Find files containing ViewGroup in name
fd ViewGroup

Length of output: 5675


Script:

#!/bin/bash
# Get the content of ViewGroup component
cat apps/web/app/\(app\)/automation/group/ViewGroup.tsx

Length of output: 9467

apps/web/app/(app)/automation/group/ViewGroup.tsx (11)

155-164: LGTM! Well-implemented keyboard handling.

The handleKeyDown implementation correctly prevents default behavior and event propagation while handling the Enter key for form submission.


204-248: Well-structured status-based organization.

Good use of groupBy to organize items by status, with clear separation between approved, rejected, and evaluation states. The implementation is clean and maintainable.


296-305: 🛠️ Refactor suggestion

Add confirmation dialog for delete operation.

The delete operation lacks a confirmation dialog, which could lead to accidental deletions.

   onClick={async () => {
+    if (!confirm('Are you sure you want to remove this pattern?')) return;
     const result = await rejectGroupItemAction(item.id);
     if (isActionError(result)) {

Likely invalid or redundant comment.


64-72: Consider implementing or removing the commented code.

The commented-out toggle for auto-adding patterns suggests an incomplete feature. If this functionality is planned for future implementation, consider creating a tracking issue. Otherwise, remove the commented code to maintain cleaner codebase.

Let me check if this feature is tracked:

✅ Verification successful

Remove redundant commented code from ViewGroup

The auto-pattern toggle functionality is already implemented in the LearnedPatterns component. The commented-out code in ViewGroup is redundant and should be removed to avoid confusion about feature ownership.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for related issues or TODOs
rg -i "auto.*pattern|pattern.*auto" -g "!*.{lock,min.js}"

Length of output: 909


Script:

#!/bin/bash
# Check LearnedPatterns implementation
cat apps/web/app/\(app\)/automation/group/LearnedPatterns.tsx

Length of output: 6787


132-132: ⚠️ Potential issue

Replace unsafe non-null assertion with proper null check.

Using groupId! is unsafe as groupId is defined as nullable (string | null). This could lead to runtime errors if groupId is null.

Apply this diff to handle the null case:

-    defaultValues: { groupId: groupId! },
+    defaultValues: groupId ? { groupId } : undefined,

Likely invalid or redundant comment.


293-309: 🛠️ Refactor suggestion

Add confirmation dialog for delete operation.

The delete operation lacks a confirmation dialog, which could lead to accidental deletions.

Add a confirmation dialog before deletion:

                 <Button
                   variant="outline"
                   size="icon"
                   onClick={async () => {
+                    if (!confirm('Are you sure you want to delete this item?')) return;
                     const result = await rejectGroupItemAction(item.id);
                     if (isActionError(result)) {
                       toastError({
                         description: `Failed to remove ${item.value} from group. ${result.error}`,
                       });
                     } else {
                       mutate();
                     }
                   }}
                 >

Likely invalid or redundant comment.


211-214: Review default status handling in groupBy operation.

Defaulting to APPROVED status when an item's status is null might not be the safest choice. Consider explicitly handling null status items separately.

Let's verify the status handling in the database:


155-164: Great addition of keyboard support!

The implementation of handleKeyDown for form submission on Enter key press improves user experience.


211-214: Well-structured status grouping implementation.

Good use of groupBy with a fallback to APPROVED status when status is null, ensuring all items are properly categorized.


272-274: Great use of visual feedback!

The implementation of "New!" and "Updated" badges for recent changes provides excellent visual feedback to users.

Also applies to: 282-284


296-305: 🛠️ Refactor suggestion

Add confirmation dialog for delete operation.

The delete operation lacks a confirmation dialog, which could lead to accidental deletions.

Apply this diff to add a confirmation dialog:

-                  onClick={async () => {
+                  onClick={async () => {
+                    if (!confirm('Are you sure you want to remove this pattern?')) return;
                     const result = await rejectGroupItemAction(item.id);

Likely invalid or redundant comment.

apps/web/app/(app)/automation/RuleForm.tsx (5)

330-330: LGTM! Clear and helpful placeholder text.

The updated placeholder text provides clear examples for email addresses, improving user understanding.

Also applies to: 341-341


501-505: Well-structured integration of LearnedPatterns component.

Good job on separating the learned patterns functionality into a dedicated component and conditionally rendering it based on groupId.


Line range hint 330-341: Clear and helpful placeholder text for email fields.

The updated placeholder text provides good examples and clear guidance for users.


191-204: Excellent error handling implementation!

The comprehensive error display shows all validation errors at once, improving user experience by making it clear what needs to be fixed.


330-330: Improved field guidance with clear placeholders.

The updated placeholder text e.g. hello@company.com provides clear examples for email address fields.

Also applies to: 341-341

apps/web/prisma/migrations/20250128221751_group_item_status/migration.sql (2)

1-2: LGTM! The enum type creation looks good.

The GroupItemStatus enum provides a clear set of states for group items: 'APPROVED', 'REJECTED', and 'EVALUATE'.


4-5: Verify the impact of adding a NOT NULL column.

The migration adds a new required column with a default value of 'APPROVED'. While this maintains backward compatibility, verify that existing group items should indeed default to 'APPROVED' status.

Consider running this script to analyze the existing group items:

✅ Verification successful

Default APPROVED status maintains existing behavior

The migration is safe because:

  • GroupItems have always been treated as approved patterns by default in the matching logic
  • Setting APPROVED as the default status maintains this existing behavior
  • The new status column adds functionality (REJECTED, EVALUATE) without changing the default matching behavior
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check existing group items that will be affected by the migration
# This helps verify if defaulting to 'APPROVED' is appropriate

ast-grep --pattern 'GroupItem.$$$status$$$' | rg -A 5 'status'

# Check for any existing group items handling in the codebase
rg -g '!*.{json,lock}' -A 5 'GroupItem'

Length of output: 74333


Script:

#!/bin/bash
# Check previous migrations and GroupItem behavior
echo "=== Previous GroupItem migrations ==="
rg -g "*.sql" "GroupItem" apps/web/prisma/migrations/

echo -e "\n=== GroupItem creation patterns ==="
rg -g "!*.{json,lock,test.ts}" "GroupItem.create" apps/web

echo -e "\n=== Test assertions for GroupItem behavior ==="
rg -g "*.test.ts" "GroupItem" apps/web

Length of output: 6578

apps/web/prisma/schema.prisma (2)

194-194: LGTM! The cascade deletion ensures data consistency.

Adding onDelete: Cascade to the group relation is a good practice to maintain referential integrity.


466-470: LGTM! The GroupItemStatus enum is well documented.

The enum values are clearly documented with their intended use:

  • APPROVED: Auto match emails
  • REJECTED: Never match emails
  • EVALUATE: Use other conditions

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 (4)
apps/web/utils/actions/ai-rule.ts (1)

511-511: Ensure consistent rule update parameters.
If group references are removed, confirm that safeUpdateRule no longer requires a groupId. Align the parameters with your create/delete flows.

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

Line range hint 1-200: Consider documenting the architectural changes.

The removal of group-related schemas (createGroupBody, UpdateGroupPromptBody) and modifications to rule schemas indicate a significant architectural shift in how groups and rules interact. Consider:

  1. Adding migration notes to help users adapt to these changes
  2. Updating related documentation
  3. Adding comments explaining the new rule-group relationship model

Would you like me to help draft the documentation for these architectural changes?

apps/web/utils/ai/assistant/process-user-request.ts (1)

284-345: Remove commented out code.

The commented out code for pattern addition should be removed. If needed in the future, it can be retrieved from version control.

-      // We may bring this back as "learned patterns"
-      // add_pattern: tool({
-      //   description: "Add a pattern",
-      //   parameters: z.object({
-      //     ruleName: z
-      //       .string()
-      //       .describe("The name of the rule to add the pattern to"),
-      //     type: z
-      //       .enum(["from", "subject"])
-      //       .describe("The type of the pattern to add"),
-      //     value: z
-      //       .string()
-      //       .describe(
-      //         "The value of the pattern to add. e.g. '@company.com', 'matt@company.com', 'Receipt from'",
-      //       ),
-      //   }),
-      //   execute: async ({ ruleName, type, value }) => {
-      //     logger.info("Add To Learned Patterns", { ruleName, type, value });
-      //     const group = rules.find((r) => r.group?.name === groupName)?.group;
-      //     const groupId = group?.id;
-      //     if (!groupId) {
-      //       logger.error("Group not found", {
-      //         ...loggerOptions,
-      //         groupName,
-      //       });
-      //       return { error: "Group not found" };
-      //     }
-      //     const groupItemType = getPatternType(type);
-      //     if (!groupItemType) {
-      //       logger.error("Invalid pattern type", {
-      //         ...loggerOptions,
-      //         type,
-      //       });
-      //       return { error: "Invalid pattern type" };
-      //     }
-      //     try {
-      //       await addGroupItem({ groupId, type: groupItemType, value });
-      //     } catch (error) {
-      //       const message =
-      //         error instanceof Error ? error.message : String(error);
-      //       logger.error("Error while adding pattern", {
-      //         ...loggerOptions,
-      //         groupId,
-      //         type: groupItemType,
-      //         value,
-      //         error: message,
-      //       });
-      //       return {
-      //         error: "Failed to add pattern",
-      //         message,
-      //       };
-      //     }
-      //     return { success: true };
-      //   },
-      // }),
apps/web/utils/actions/rule.ts (1)

Line range hint 1-309: Consider implementing a migration strategy for existing rules.

Given the architectural shift from group-based to AI-based rules, consider:

  1. Adding a migration script to convert existing group-based rules to AI-based rules
  2. Implementing feature flags to gradually roll out the changes
  3. Adding telemetry to monitor the effectiveness of AI-based rules compared to group-based rules
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 819ba38 and 4f0ec4c.

📒 Files selected for processing (11)
  • apps/web/app/(app)/automation/RuleForm.tsx (8 hunks)
  • apps/web/app/(app)/automation/create/examples.tsx (2 hunks)
  • apps/web/utils/actions/ai-rule.ts (6 hunks)
  • apps/web/utils/actions/rule.ts (2 hunks)
  • apps/web/utils/actions/validation.ts (1 hunks)
  • apps/web/utils/ai/assistant/process-user-request.ts (8 hunks)
  • apps/web/utils/ai/rule/create-rule-schema.ts (0 hunks)
  • apps/web/utils/condition.ts (2 hunks)
  • apps/web/utils/config.ts (0 hunks)
  • apps/web/utils/group/group.ts (0 hunks)
  • apps/web/utils/rule/rule.ts (4 hunks)
💤 Files with no reviewable changes (3)
  • apps/web/utils/config.ts
  • apps/web/utils/ai/rule/create-rule-schema.ts
  • apps/web/utils/group/group.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/rule/rule.ts
🔇 Additional comments (21)
apps/web/utils/actions/ai-rule.ts (5)

40-40: Centralizing rule logic is a good move.
It’s beneficial to consolidate all rule-related operations (deleteRule, safeCreateRule, etc.) in one module for improved consistency and error handling.


190-190: Good defensive programming.
Validating session.accessToken ensures that automation actions are performed only by authenticated users.


214-214: Verify passing null for group ID.
Double-check that safeCreateRule gracefully handles null for the group ID. If group IDs are universally removed, consider refactoring the function signature accordingly.


310-310: Consistent session access check.
Mirroring the earlier safeguard for session.accessToken maintains a uniform security posture.


457-460: Confirm necessity of groupId during deletion.
The codebase appears to deprecate group handling elsewhere. Confirm whether groupId remains necessary here, or remove it if obsolete.

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

106-108: Verify the impact of optional groupId on existing rules.

The addition of an optional groupId field and the stricter name validation look good. However, we should verify the handling of existing rules during this architectural change.

Let's verify the impact on existing rules and their group associations:

✅ Verification successful

Optional groupId field is safely implemented and backward compatible

The implementation properly handles both grouped and ungrouped rules with appropriate validation and error handling. Existing rules are unaffected by this change.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for existing rules and their group relationships

# Search for rule creation/updates to understand current usage
rg -A 5 "createRule|updateRule" --type ts

# Search for group-related database queries to ensure proper migration
rg -A 5 "groupId|\.group" --type ts

Length of output: 70967

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

91-91: LGTM! Type parameter updated to exclude group conditions.

The type change ensures type safety by preventing the creation of group conditions, aligning with the removal of group functionality.


187-197: LGTM! Improved string building logic.

The refactoring to use arrays for collecting string segments improves code readability and maintainability.

Also applies to: 199-200, 202-216, 223-223


218-220: Include group name in the output string.

The current implementation only shows "Group" without any identifying information. Since the group name is available in the type definition (group?: { name: string } | null), consider including it in the output string for better clarity.

 if (rule.groupId) {
-  conditions.push("Group");
+  conditions.push(`Group: ${rule.group?.name ?? "Unknown"}`);
 }

Line range hint 654-668: LGTM! Well-structured XML representation for patterns.

The XML representation for patterns maintains consistent structure and proper indentation.


Line range hint 686-686: LGTM! Function renamed to reflect pattern terminology.

The function name change from getGroupItemType to getPatternType aligns with the shift from group items to patterns.

apps/web/utils/ai/assistant/process-user-request.ts (3)

20-20: LGTM! Import added for pattern deletion.

The import for deleteGroupItem is correctly placed and used in the pattern removal functionality.


69-79: LGTM! Clear and accurate system prompt for pattern management.

The system prompt effectively explains:

  • Patterns are learned from email history
  • Patterns ignore the conditionalOperator setting
  • The section is conditionally included based on pattern availability

89-89: LGTM! Clear explanation of condition matching logic.

The explanation effectively communicates:

  • Top-level conditions support both AND and OR logic
  • The logic is controlled by the conditionalOperator setting
apps/web/app/(app)/automation/RuleForm.tsx (4)

66-66: LGTM! Added form submission state for error handling.

The addition of isSubmitted enables better error message handling by showing validation errors only after form submission.


182-195: LGTM! Well-structured error display.

The error display section effectively:

  • Shows errors only after form submission
  • Uses a list structure for better readability
  • Properly scopes error messages

492-496: LGTM! Added learned patterns section.

The learned patterns section is properly:

  • Conditionally rendered based on groupId
  • Integrated with the LearnedPatterns component

321-321: LGTM! Clear and consistent placeholder text.

The placeholder text for email fields:

  • Provides clear examples
  • Maintains consistent format

Also applies to: 332-332

apps/web/app/(app)/automation/create/examples.tsx (1)

28-29: Verify the migration impact of replacing group-based conditions with AI instructions.

The shift from RuleType.GROUP to RuleType.AI with instruction-based conditions represents a significant architectural change. While this aligns with the PR's objective of auto-updating groups, we should ensure:

  1. Existing rules using RuleType.GROUP are properly migrated
  2. The AI instructions provide equivalent or better functionality compared to the previous group-based approach

Also applies to: 45-46

✅ Verification successful

Migration from group-based to AI instructions is properly implemented

The codebase has been properly structured to handle the migration:

  • The UI prevents creation of new group-based rules
  • Form validation ensures only AI, STATIC, and CATEGORY types are available
  • Examples demonstrate correct usage of AI instructions
  • Type system properly handles the transition
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining GROUP type usage that might need migration
rg -l "RuleType\.GROUP" --type ts --type tsx

# Check for existing rules that might be affected
ast-grep --pattern 'type: RuleType.GROUP'

Length of output: 118


Script:

#!/bin/bash
# Search for RuleType.GROUP usage with correct extension handling
rg "RuleType\.GROUP" --type typescript

# Find RuleType enum definition
rg "enum\s+RuleType" --type typescript -A 5

# Look for rule-related files
fd -e ts -e tsx | grep -i "rule"

# Search for any group-related configurations or types
rg "type.*Group|interface.*Group" --type typescript

Length of output: 2601


Script:

#!/bin/bash
# Check content of potential type definition files
cat apps/web/utils/ai/rule/types.ts
cat apps/web/utils/ai/choose-rule/types.ts

# Search for RuleType usage with correct type flag
rg "RuleType" -t ts

# Check RuleForm implementation
cat apps/web/app/\(app\)/automation/RuleForm.tsx

# Look for migration-related code
cat apps/web/utils/ai/rule/diff-rules.ts

Length of output: 37615

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

22-22: LGTM! Import changes align with the new architecture.

The addition of RuleType and deleteRule imports support the transition to AI-based rules and improved rule deletion handling.

Also applies to: 30-30


274-277: Verify cascade deletion behavior for rules with associated groups.

The new deleteRule implementation includes groupId, suggesting potential changes in how rule-group relationships are handled during deletion.

✅ Verification successful

Cascade deletion behavior for rules and associated groups is properly implemented

The deletion behavior is safe and well-implemented through:

  • Explicit group deletion in the same transaction as rule deletion
  • Cascade deletion configuration for all dependent entities
  • Atomic transaction ensuring data consistency
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential orphaned groups or related entities after rule deletion
ast-grep --pattern 'prisma.rule.delete'

# Search for cascade delete configurations in schema
rg "onDelete:" --type prisma

Length of output: 190


Script:

#!/bin/bash
# Search for schema definitions and relationships
fd -e prisma | xargs cat

# Find all rule deletion implementations
rg -A 5 "rule.*delete" 

# Look for group-rule relationship handling
rg -B 3 -A 3 "groupId.*rule|rule.*groupId"

Length of output: 21076

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)/smart-categories/page.tsx (1)

103-106: LGTM! Consider enhancing the description clarity.

The text changes effectively communicate the feature's purpose. However, the description could be more explicit about the AI's role.

Consider this minor improvement to the description:

-                    Now that you have some categories, our AI can categorize
-                    senders.
+                    Now that you have some categories, our AI can help you categorize
+                    your email senders.
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4f0ec4c and c9ea2a9.

📒 Files selected for processing (3)
  • apps/web/app/(app)/automation/group/LearnedPatterns.tsx (1 hunks)
  • apps/web/app/(app)/smart-categories/page.tsx (1 hunks)
  • apps/web/app/(app)/smart-categories/setup/SetUpCategories.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/app/(app)/smart-categories/setup/SetUpCategories.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(app)/automation/group/LearnedPatterns.tsx

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/utils/ai/rule/prompt-to-rules.ts (3)

66-66: Consider maintaining consistency in logging labels.

The logging label "Input" is inconsistent with the logger scope name "ai-prompt-to-rules" defined earlier. Consider using a consistent naming convention across all logging statements.

-    logger.trace("Input", {
+    logger.trace("prompt-to-rules:input", {

91-91: Maintain consistency with the previous logging label suggestion.

For consistency with the previous logging statement and the logger scope name:

-  logger.trace("Output", { rules });
+  logger.trace("prompt-to-rules:output", { rules });

Line range hint 190-201: Update rule name and enhance urgency criteria.

The example has several inconsistencies:

  1. The rule name "Matt Urgent Emails" is too specific for a domain-wide filter.
  2. The urgency criteria could benefit from more specific guidelines in the AI instructions.
-          "name": "Matt Urgent Emails",
+          "name": "Company Urgent Emails",
           "condition": {
             "conditionalOperator": "AND",
-            "aiInstructions": "Apply this rule to urgent emails",
+            "aiInstructions": "Apply this rule to emails marked as urgent, containing urgent keywords, or with high priority flags",
             "static": {
               "from": "@company.com"
             }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c9ea2a9 and 7d6befc.

📒 Files selected for processing (1)
  • apps/web/utils/ai/rule/prompt-to-rules.ts (5 hunks)
🔇 Additional comments (1)
apps/web/utils/ai/rule/prompt-to-rules.ts (1)

130-131: Consider adding validation for newsletter detection.

While the AI instructions are clear, consider adding validation logic or confidence thresholds to handle cases where the AI might misclassify newsletters. This could help prevent false positives.

Would you like me to propose a validation approach or generate example code for handling misclassifications?

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 comments (1)
apps/web/utils/ai/assistant/process-user-request.ts (1)

Line range hint 350-408: Improve error handling in remove_pattern tool.

The error handling could be more informative and consistent:

- logger.error("Pattern not found", {
+ logger.error("Pattern not found in the matched rule", {
    ...loggerOptions,
    type,
    value,
+   ruleId: matchedRule.id,
+   groupId: matchedRule.group?.id,
  });
- return { error: "Pattern not found" };
+ return { 
+   error: "Pattern not found",
+   details: `Pattern '${value}' of type '${type}' was not found in the matched rule.`
+ };
🧹 Nitpick comments (2)
apps/web/utils/ai/assistant/process-user-request.ts (2)

286-347: Consider preserving add_pattern functionality.

The commented-out add_pattern tool suggests that pattern addition might be needed in the future. Since the system still supports pattern removal, consider:

  1. Keeping pattern addition for manual pattern learning
  2. Adding validation for pattern format

If you plan to bring this back, consider:

+ // Validate pattern format
+ const isValidPattern = (type: string, value: string) => {
+   if (type === "from") return value.includes("@");
+   if (type === "subject") return value.length >= 3;
+   return false;
+ };

688-691: Improve type safety in getPatternType function.

The function could be more type-safe and handle invalid inputs better:

- function getPatternType(type: string) {
+ function getPatternType(type: string): GroupItemType | undefined {
    if (type === "from") return GroupItemType.FROM;
    if (type === "subject") return GroupItemType.SUBJECT;
+   return undefined;
  }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7d6befc and a86f1ac.

📒 Files selected for processing (2)
  • apps/web/utils/ai/assistant/process-user-request.ts (7 hunks)
  • apps/web/utils/ai/rule/prompt-to-rules.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/ai/rule/prompt-to-rules.ts
🔇 Additional comments (1)
apps/web/utils/ai/assistant/process-user-request.ts (1)

69-98: System prompt updates need clarification on pattern management.

The system prompt introduces "Learned Patterns" but doesn't clearly explain:

  • How patterns are learned/derived from email history
  • Whether patterns are automatically or manually added
  • The relationship between patterns and rules

Could you clarify these aspects to ensure users understand the new pattern-based system?

Comment on lines +655 to +670

${
rule.group?.items?.length
? `<patterns>
${rule.group.items
.map(
(item) =>
`<pattern>
<type>${item.type}</type>
<value>${item.value}</value>
</pattern>`,
)
.join("\n ")}
</patterns>`
: ""
}
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

XML representation of patterns needs error handling.

The XML generation for patterns lacks escaping of special characters which could cause XML parsing issues.

- <value>${item.value}</value>
+ <value>${escapeXml(item.value)}</value>

+ // Add this helper function
+ function escapeXml(unsafe: string) {
+   return unsafe.replace(/[<>&'"]/g, (c) => {
+     switch (c) {
+       case '<': return '&lt;';
+       case '>': return '&gt;';
+       case '&': return '&amp;';
+       case "'": return '&apos;';
+       case '"': return '&quot;';
+       default: return c;
+     }
+   });
+ }

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

@elie222 elie222 changed the title WIP: Auto updating groups Remove a lot of group functionality to simplify the product and how the AI creates rules for users Jan 29, 2025
@elie222 elie222 merged commit c84424f into main Jan 29, 2025
4 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Aug 24, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 11, 2025
@elie222 elie222 deleted the autoupdating-groups branch December 18, 2025 22:59
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