Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughThis PR adds the "Brief My Meeting" premium feature by updating configuration and UI, while enhancing email similarity calculation to properly handle HTML content from Outlook through ParsedMessage object support and content normalization utilities. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add 'Brief My Meeting' feature link in footer and include 'Pre-meeting briefings' in Business tier features in Footer.tsx and config.ts to introduce the Brief My Meeting feature pageAdd a footer navigation item linking to 📍Where to StartStart with the Macroscope summarized 1545b1c. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/utils/similarity-score.test.ts (2)
107-113: Remove unnecessary module reset and unmock.The
vi.doUnmock("@/utils/mail")is unmocking a module that was never mocked in the first place. The only mock in this file is for"server-only". This entirebeforeAllblock appears unnecessary sincecalculateSimilarityis already imported at line 2.🔎 Proposed simplification
describe("calculateSimilarity - integration tests with ParsedMessage", () => { - // Import real implementation without mocks - let realCalculateSimilarity: typeof calculateSimilarity; - - beforeAll(async () => { - // Clear the module cache and re-import without mocks - vi.resetModules(); - vi.doUnmock("@/utils/mail"); - const module = await import("./similarity-score"); - realCalculateSimilarity = module.calculateSimilarity; - }); + // Use the already-imported calculateSimilarity directly + const realCalculateSimilarity = calculateSimilarity;Then update all usages of
realCalculateSimilarityin the integration tests, or simply usecalculateSimilaritydirectly throughout.
115-137: Consider using test helpers from@/__tests__/helpers.Per coding guidelines, prefer using existing helpers like
getMockMessagefrom@/__tests__/helpers.tsfor creating mock data instead of custom test data helpers. However, since this helper creates a specific structure needed for these tests with controlledbodyContentType, this approach is acceptable if the existing helpers don't support this use case.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/web/app/(app)/premium/config.tsapps/web/app/(landing)/home/Footer.tsxapps/web/app/(marketing)apps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
🧰 Additional context used
📓 Path-based instructions (22)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor error handling in async operations
**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
**/*.{ts,tsx}: For early access feature flags, create hooks using the naming conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g.,inbox-cleaner,pricing-options-2)
Always define types for A/B test variant flags (e.g.,type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the!postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g.,
import groupBy from 'lodash/groupBy')
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Implement responsive design with Tailwind CSS using a mobile-first approach
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(landing)/home/Footer.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-hidden="true"on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like<marquee>or<blink>
Only use thescopeprop on<th>elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include atitleelement for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
AssigntabIndexto non-interactive HTML elements witharia-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use bothchildrenanddangerouslySetInnerHTMLprops on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use<>...</>instead of<Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't usetarget="_blank"withoutrel="noopener"
Don't use<img>elements in Next.js projects
Don't use<head>elements in Next.js projects
Files:
apps/web/app/(landing)/home/Footer.tsx
!(pages/_document).{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't use the next/head module in pages/_document.js on Next.js projects
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.tsapps/web/app/(marketing)
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g.,import groupBy from 'lodash/groupBy')
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
apps/web/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.ts
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor error handling in forms
Files:
apps/web/app/(landing)/home/Footer.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/app/(landing)/home/Footer.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
apps/web/app/(app)/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/premium/config.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma'sselectoption. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. AllfindUnique/findFirstcalls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
AllfindManyqueries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g.,emailAccount: { id: emailAccountId }) to validate ownership
Files:
apps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
apps/web/**/*.{example,ts,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Add environment variables to
.env.example,env.ts, andturbo.json
Files:
apps/web/app/(app)/premium/config.tsapps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
Logger should be passed as a parameter to helper functions instead of creating their own logger instances
Files:
apps/web/utils/reply-tracker/draft-tracking.tsapps/web/utils/similarity-score.test.tsapps/web/utils/similarity-score.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests
Files:
apps/web/utils/similarity-score.test.ts
apps/web/**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Co-locate test files next to source files (e.g.,
utils/example.test.ts). Only E2E and AI tests go in__tests__/
Files:
apps/web/utils/similarity-score.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
**/*.test.{ts,tsx}: Usevitestas the testing framework
Colocate test files next to the tested file with.test.tsor.test.tsxnaming convention (e.g.,dir/format.tsanddir/format.test.ts)
Mockserver-onlyusingvi.mock("server-only", () => ({}))
Mock Prisma usingvi.mock("@/utils/prisma")and the provided mock from@/utils/__mocks__/prisma
Use test helper functionsgetEmail,getEmailAccount, andgetRulefrom@/__tests__/helpersfor creating mock data
Clear all mocks between tests usingbeforeEach(() => { vi.clearAllMocks(); })
Use descriptive test names that clearly indicate what is being tested
Do not mock the Logger in tests
Files:
apps/web/utils/similarity-score.test.ts
**/*.test.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/notes.mdc)
Co-locate test files next to source files (e.g.,
utils/example.test.ts). Only E2E and AI tests go in__tests__/
Files:
apps/web/utils/similarity-score.test.ts
🧠 Learnings (8)
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/utils/reply-tracker/draft-tracking.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Applied to files:
apps/web/utils/reply-tracker/draft-tracking.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers
Applied to files:
apps/web/utils/similarity-score.test.ts
📚 Learning: 2026-01-01T10:42:29.775Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.775Z
Learning: Applies to **/*.test.{ts,tsx} : Use descriptive test names that clearly indicate what is being tested
Applied to files:
apps/web/utils/similarity-score.test.ts
📚 Learning: 2026-01-01T10:42:29.775Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.775Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helper functions `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for creating mock data
Applied to files:
apps/web/utils/similarity-score.test.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to **/*.test.ts : Include security tests in test suites to verify: authentication is required, IDOR protection works (other users cannot access resources), parameter validation rejects invalid inputs, and error messages don't leak information
Applied to files:
apps/web/utils/similarity-score.test.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments
Applied to files:
apps/web/utils/similarity-score.test.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions
Applied to files:
apps/web/utils/similarity-score.ts
🧬 Code graph analysis (2)
apps/web/utils/reply-tracker/draft-tracking.ts (1)
apps/web/utils/similarity-score.ts (1)
calculateSimilarity(44-76)
apps/web/utils/similarity-score.test.ts (1)
apps/web/utils/similarity-score.ts (1)
calculateSimilarity(44-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Baz Reviewer
- GitHub Check: cubic · AI code reviewer
- GitHub Check: test
🔇 Additional comments (11)
apps/web/app/(marketing) (1)
1-1: Verify the private marketing submodule commit contains all expected changes.This is a submodule commit update to the private marketing repository. The commit
9ca3dc0d4f8a8cf8b2e3565e7acc2db6d1affd10includes a Brief My Meeting feature page. However, since the marketing repository is private and not accessible in this environment, verify that the commit contains all expected changes described in the PR objectives:
- New
/brief-my-meetingfeature page with custom two-column hero section- Email briefing mockup component integration
- "Brief My Meeting" footer link added to Product section
- "Pre-meeting briefings" added to Starter tier pricing features with tooltip
- Proper reuse of Inbox Zero's blue color scheme and typography components
- Composition of BrandScroller, Banner, Testimonials, Pricing, and FinalCTA sections
You can verify this in the private marketing repository or during CI/build verification.
apps/web/app/(landing)/home/Footer.tsx (1)
12-12: LGTM!The new footer navigation item follows the existing pattern and is correctly placed in the Product section without
target="_blank"since it's an internal page.apps/web/app/(app)/premium/config.ts (1)
165-169: LGTM!The new feature entry follows the established pattern for features with tooltips, and the tooltip text clearly describes the pre-meeting briefing functionality.
apps/web/utils/reply-tracker/draft-tracking.ts (3)
22-29: LGTM!Good defensive addition to guard against missing
sentMessageIdwith a warning log before early return. This prevents potential issues downstream when creating thedraftSendLogrecord.
82-83: LGTM!Passing the full
messageobject enables proper handling of Outlook HTML content through the updatedcalculateSimilarityfunction, which now supportsParsedMessageand applies appropriate normalization based onbodyContentType.
167-172: LGTM!The updated condition correctly handles emails that only have HTML content (common with Outlook), and passing the full
draftDetailsobject allowscalculateSimilarityto properly normalize based on the content type.apps/web/utils/similarity-score.test.ts (2)
6-96: Good test coverage for basic similarity calculations.The tests comprehensively cover edge cases including null/undefined handling, case-insensitivity, whitespace normalization, partial similarity, special characters, and realistic email scenarios.
139-242: Good integration test coverage for Outlook and Gmail content handling.The integration tests effectively validate the key scenarios: Outlook HTML content with various structures (div wrappers, signatures, quoted content), Gmail quote stripping, newline normalization, and backward compatibility with plain strings.
apps/web/utils/similarity-score.ts (3)
10-17: LGTM!The normalization approach correctly handles the stored draft content by converting newlines to
<br>tags before HTML-to-text conversion, preserving line break semantics. The subsequent quote stripping and case normalization ensure consistent comparison.
23-34: LGTM!Clean implementation that properly handles the Outlook HTML case by converting to plain text when
bodyContentType === "html", then applying consistent normalization.
64-68: Good fallback logic for HTML-only emails.The fallback from
textPlaintotextHtmlwith forced"html"content type correctly handles emails that only contain HTML content (common with Outlook). This ensures proper conversion to plain text before comparison.
| if (typeof providerMessage === "string") { | ||
| // Legacy: plain string - use parseReply for backwards compatibility with Gmail | ||
| const reply = parseReply(providerMessage); | ||
| normalized2 = reply.toLowerCase().trim(); | ||
| } else { | ||
| // ParsedMessage - use proper normalization with bodyContentType | ||
| // Fall back to textHtml if textPlain is empty (some emails only have HTML) | ||
| const text = providerMessage.textPlain || providerMessage.textHtml || ""; | ||
| const contentType = providerMessage.textPlain | ||
| ? providerMessage.bodyContentType | ||
| : "html"; | ||
| normalized2 = normalizeProviderContent(text, contentType); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for parseReply and stripQuotedContent implementations
echo "=== Locating parseReply ==="
rg -n -B 2 -A 20 'export.*parseReply|function parseReply' --type ts
echo ""
echo "=== Locating stripQuotedContent ==="
rg -n -B 2 -A 20 'export.*stripQuotedContent|function stripQuotedContent' --type ts
echo ""
echo "=== Locating normalizeProviderContent ==="
rg -n -B 2 -A 15 'export.*normalizeProviderContent|function normalizeProviderContent' --type tsRepository: elie222/inbox-zero
Length of output: 4569
Normalization inconsistency confirmed: legacy and ParsedMessage paths use fundamentally different quote-stripping mechanisms.
The legacy string path uses parseReply which leverages the EmailReplyParser library's getVisibleText() method, while the ParsedMessage path uses stripQuotedContent which applies manual regex patterns (On .* wrote:, ----Original Message----, >+ On, From:). These implementations could identify and strip quoted content differently, causing inconsistent similarity scores for identical emails. Consider consolidating both paths to use the same quote-stripping mechanism.
🤖 Prompt for AI Agents
apps/web/utils/similarity-score.ts lines 57-69: the legacy string branch uses
parseReply (EmailReplyParser.getVisibleText semantics) while the ParsedMessage
branch uses stripQuotedContent with different regexes, causing inconsistent
quote-stripping and similarity scores; unify both paths to use the same
quote-stripping/normalization function: extract visible text using a single
helper (either standardize on EmailReplyParser.getVisibleText or standardize on
stripQuotedContent), ensure it accepts bodyContentType (plain vs html) and falls
back from textPlain to textHtml, then apply lowercase/trim normalization to the
helper result for both branches; update calls so the string path runs through
this helper instead of raw parseReply, and add/adjust tests to cover both input
shapes.
| const createParsedMessage = ( | ||
| textPlain: string, | ||
| bodyContentType?: "html" | "text", | ||
| ) => ({ | ||
| id: "msg-123", |
There was a problem hiding this comment.
The new integration suite introduces an ad-hoc createParsedMessage factory (lines 115‑137) instead of consuming the shared email mocks from @/__tests__/helpers (e.g., getMockMessage), which breaches the .cursor/rules/testing.mdc rule that all email/account mock data must come from that central helper.
Prompt for AI Agents:
In apps/web/utils/similarity-score.test.ts around lines 115-119, the local
createParsedMessage factory duplicates email mock data and violates the testing rule
that all email/account mocks must come from @/__tests__/helpers. Replace the local
factory by importing the shared helper (e.g., getMockMessage or getParsedMessage) from
@/__tests__/helpers at the top of the file, remove lines 115-137 (the
createParsedMessage function), and update every test that called createParsedMessage to
instead call the shared helper while passing the same textPlain/textHtml and
bodyContentType values. Ensure the helper calls set id/threadId/subject/headers as
needed so existing assertions and behavior remain unchanged.
Finding type: AI Coding Guidelines
User description
Add dedicated feature page for Brief My Meeting within Inbox Zero.
TLDR: Creates a feature page at /brief-my-meeting with custom hero, adds footer link, and includes pre-meeting briefings in pricing features.
Generated description
Below is a concise technical summary of the changes proposed in this PR:
Introduces a new feature page for 'Brief My Meeting' at
/brief-my-meeting, integrating it into the application's navigation and pricing structure. Updates theFooter.tsxcomponent to include a link to the new page and modifiesconfig.tsto list 'Pre-meeting briefings' as a feature in the premium tier.Latest Contributors(2)