-
-
Notifications
You must be signed in to change notification settings - Fork 906
feat(dashboard): login with google and "last used" indicator #2746
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
WalkthroughAdds Google OAuth support across the webapp: new optional env vars for Google client ID/secret; a Google auth strategy and helper; new routes to initiate and handle Google OAuth (with redirect-cookie and MFA handling); user model logic to find/create/link Google-authenticated users and a Prisma migration adding AuthenticationMethod.GOOGLE; UI changes to surface Google login and persist last-used auth method via a new lastAuthMethod cookie service; minor avatar image change adding referrerPolicy="no-referrer"; and the remix-auth-google dependency. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Areas requiring extra attention:
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this 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 (1)
apps/webapp/app/routes/login._index/route.tsx (1)
20-41: Consider extractingGoogleIconto a shared component.The inline
GoogleIconcomponent works correctly. However, since@trigger.dev/companyiconsis already used forGitHubLightIcon, consider adding the Google icon to that package for consistency and reusability across the codebase.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (14)
apps/webapp/app/components/UserProfilePhoto.tsx(1 hunks)apps/webapp/app/env.server.ts(1 hunks)apps/webapp/app/models/user.server.ts(4 hunks)apps/webapp/app/routes/auth.github.callback.tsx(2 hunks)apps/webapp/app/routes/auth.google.callback.tsx(1 hunks)apps/webapp/app/routes/auth.google.ts(1 hunks)apps/webapp/app/routes/login._index/route.tsx(6 hunks)apps/webapp/app/routes/magic.tsx(2 hunks)apps/webapp/app/services/auth.server.ts(2 hunks)apps/webapp/app/services/googleAuth.server.ts(1 hunks)apps/webapp/app/services/lastAuthMethod.server.ts(1 hunks)apps/webapp/package.json(1 hunks)internal-packages/database/prisma/migrations/20251204143136_add_google_auth_method/migration.sql(1 hunks)internal-packages/database/prisma/schema.prisma(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
Files:
apps/webapp/app/services/googleAuth.server.tsapps/webapp/app/services/auth.server.tsapps/webapp/app/routes/auth.google.callback.tsxapps/webapp/app/models/user.server.tsapps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/services/lastAuthMethod.server.tsapps/webapp/app/env.server.tsapps/webapp/app/routes/login._index/route.tsxapps/webapp/app/routes/magic.tsxapps/webapp/app/components/UserProfilePhoto.tsxapps/webapp/app/routes/auth.google.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/services/googleAuth.server.tsapps/webapp/app/services/auth.server.tsapps/webapp/app/routes/auth.google.callback.tsxapps/webapp/app/models/user.server.tsapps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/services/lastAuthMethod.server.tsapps/webapp/app/env.server.tsapps/webapp/app/routes/login._index/route.tsxapps/webapp/app/routes/magic.tsxapps/webapp/app/components/UserProfilePhoto.tsxapps/webapp/app/routes/auth.google.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
apps/webapp/app/services/googleAuth.server.tsapps/webapp/app/services/auth.server.tsapps/webapp/app/routes/auth.google.callback.tsxapps/webapp/app/models/user.server.tsapps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/services/lastAuthMethod.server.tsapps/webapp/app/env.server.tsapps/webapp/app/routes/login._index/route.tsxapps/webapp/app/routes/magic.tsxapps/webapp/app/components/UserProfilePhoto.tsxapps/webapp/app/routes/auth.google.ts
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/services/googleAuth.server.tsapps/webapp/app/services/auth.server.tsapps/webapp/app/routes/auth.google.callback.tsxapps/webapp/app/models/user.server.tsapps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/services/lastAuthMethod.server.tsapps/webapp/app/env.server.tsapps/webapp/app/routes/login._index/route.tsxapps/webapp/app/routes/magic.tsxapps/webapp/app/components/UserProfilePhoto.tsxapps/webapp/app/routes/auth.google.ts
apps/webapp/app/services/**/*.server.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Separate testable services from configuration files; follow the pattern of
realtimeClient.server.ts(testable service) andrealtimeClientGlobal.server.ts(configuration) in the webapp
Files:
apps/webapp/app/services/googleAuth.server.tsapps/webapp/app/services/auth.server.tsapps/webapp/app/services/lastAuthMethod.server.ts
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Files:
apps/webapp/app/services/googleAuth.server.tsapps/webapp/app/services/auth.server.tsapps/webapp/app/routes/auth.google.callback.tsxapps/webapp/app/models/user.server.tsapps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/services/lastAuthMethod.server.tsapps/webapp/app/env.server.tsapps/webapp/app/routes/login._index/route.tsxapps/webapp/app/routes/magic.tsxapps/webapp/app/components/UserProfilePhoto.tsxapps/webapp/app/routes/auth.google.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier
Files:
apps/webapp/app/services/googleAuth.server.tsapps/webapp/app/services/auth.server.tsapps/webapp/package.jsonapps/webapp/app/routes/auth.google.callback.tsxapps/webapp/app/models/user.server.tsapps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/services/lastAuthMethod.server.tsapps/webapp/app/env.server.tsapps/webapp/app/routes/login._index/route.tsxapps/webapp/app/routes/magic.tsxapps/webapp/app/components/UserProfilePhoto.tsxapps/webapp/app/routes/auth.google.ts
🧠 Learnings (8)
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/services/**/*.server.{ts,tsx} : Separate testable services from configuration files; follow the pattern of `realtimeClient.server.ts` (testable service) and `realtimeClientGlobal.server.ts` (configuration) in the webapp
Applied to files:
apps/webapp/app/services/auth.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: The webapp at apps/webapp is a Remix 2.1 application using Node.js v20
Applied to files:
apps/webapp/package.json
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Applied to files:
apps/webapp/package.jsonapps/webapp/app/routes/auth.google.callback.tsxapps/webapp/app/routes/auth.google.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL
Applied to files:
apps/webapp/app/models/user.server.tsinternal-packages/database/prisma/migrations/20251204143136_add_google_auth_method/migration.sql
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Leverage the PostgreSQL database through the `trigger.dev/database` Prisma 6.14.0 client in the webapp for all data access patterns
Applied to files:
apps/webapp/app/models/user.server.ts
📚 Learning: 2025-09-02T11:27:36.336Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2463
File: apps/webapp/app/routes/_app.github.callback/route.tsx:33-44
Timestamp: 2025-09-02T11:27:36.336Z
Learning: In the GitHub App installation callback flow in apps/webapp/app/routes/_app.github.callback/route.tsx, the install session cookie is not cleared after use due to interface limitations with redirectWithSuccessMessage/redirectWithErrorMessage not supporting custom headers. The maintainer accepts this design as the 1-hour cookie expiration provides sufficient protection against replay attacks.
Applied to files:
apps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/services/lastAuthMethod.server.tsapps/webapp/app/routes/magic.tsx
📚 Learning: 2025-09-02T11:18:06.602Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2463
File: apps/webapp/app/services/gitHubSession.server.ts:31-36
Timestamp: 2025-09-02T11:18:06.602Z
Learning: In the GitHub App installation flow in apps/webapp/app/services/gitHubSession.server.ts, the redirectTo parameter stored in httpOnly session cookies is considered acceptable without additional validation by the maintainer, as the httpOnly cookie provides sufficient security for this use case.
Applied to files:
apps/webapp/app/routes/auth.github.callback.tsxapps/webapp/app/routes/magic.tsx
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp
Applied to files:
apps/webapp/app/env.server.ts
🧬 Code graph analysis (8)
apps/webapp/app/services/googleAuth.server.ts (3)
apps/webapp/app/services/auth.server.ts (1)
authenticator(31-31)apps/webapp/app/env.server.ts (1)
env(1261-1261)apps/webapp/app/models/user.server.ts (1)
findOrCreateUser(38-50)
apps/webapp/app/services/auth.server.ts (4)
apps/webapp/app/env.server.ts (1)
env(1261-1261)apps/webapp/app/services/gitHubAuth.server.ts (1)
addGitHubStrategy(9-54)apps/webapp/app/services/googleAuth.server.ts (1)
addGoogleStrategy(9-54)apps/webapp/app/services/emailAuth.server.tsx (1)
addEmailLinkStrategy(48-50)
apps/webapp/app/routes/auth.google.callback.tsx (8)
apps/webapp/app/routes/auth.github.callback.tsx (1)
loader(11-60)apps/webapp/app/routes/auth.google.ts (2)
loader(4-4)redirectCookie(29-32)apps/webapp/app/routes/login._index/route.tsx (1)
loader(74-120)apps/webapp/app/routes/magic.tsx (1)
loader(10-57)apps/webapp/app/utils.ts (1)
sanitizeRedirectPath(13-42)apps/webapp/app/services/auth.server.ts (1)
authenticator(31-31)apps/webapp/app/models/message.server.ts (1)
redirectWithErrorMessage(201-218)apps/webapp/app/services/lastAuthMethod.server.ts (1)
setLastAuthMethodHeader(22-24)
apps/webapp/app/models/user.server.ts (1)
apps/webapp/app/utils/email.ts (1)
assertEmailAllowed(3-13)
apps/webapp/app/routes/auth.github.callback.tsx (1)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
setLastAuthMethodHeader(22-24)
apps/webapp/app/routes/login._index/route.tsx (2)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
getLastAuthMethod(13-20)apps/webapp/app/services/auth.server.ts (1)
isGoogleAuthSupported(31-31)
apps/webapp/app/routes/magic.tsx (1)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
setLastAuthMethodHeader(22-24)
apps/webapp/app/routes/auth.google.ts (2)
apps/webapp/app/routes/auth.google.callback.tsx (1)
loader(11-60)apps/webapp/app/routes/login._index/route.tsx (1)
loader(74-120)
⏰ 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). (23)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (17)
apps/webapp/app/components/UserProfilePhoto.tsx (1)
25-25: LGTM! Good privacy practice.Adding
referrerPolicy="no-referrer"prevents the Referer header from being sent when fetching avatar images. This is particularly important for OAuth providers like Google, as it prevents leaking the user's current page URL to external servers when loading avatars.apps/webapp/app/env.server.ts (1)
97-98: LGTM! Consistent with existing OAuth pattern.The Google OAuth environment variables follow the same optional pattern as the GitHub credentials, allowing the feature to be conditionally enabled based on configuration.
internal-packages/database/prisma/migrations/20251204143136_add_google_auth_method/migration.sql (1)
1-2: LGTM! Correct enum extension.The migration correctly adds the GOOGLE value to the AuthenticationMethod enum. Note that PostgreSQL's
ALTER TYPE ... ADD VALUEcannot run inside a transaction, but since this is the only statement in the migration, it should execute safely.apps/webapp/app/routes/magic.tsx (1)
42-46: LGTM! Consistent header management pattern.The implementation correctly uses the Headers API to append multiple Set-Cookie headers (session and last-auth-method). This pattern is consistently applied in both the MFA redirect path and the final redirect path.
internal-packages/database/prisma/schema.prisma (1)
94-94: LGTM! Enum updated consistently.The GOOGLE authentication method is correctly added to the AuthenticationMethod enum, aligning with the database migration.
apps/webapp/app/services/auth.server.ts (1)
5-5: LGTM! Consistent with existing OAuth pattern.The Google authentication integration follows the same pattern as the existing GitHub authentication:
- Runtime check for credential availability
- Conditional strategy registration
- Exported support flag for UI conditional rendering
This maintains consistency across OAuth providers.
Also applies to: 17-19, 25-27, 31-31
apps/webapp/app/services/googleAuth.server.ts (1)
9-54: LGTM! Consistent OAuth strategy implementation.The Google authentication strategy follows the established pattern from the GitHub strategy:
- Email validation with clear error messages
- Proper user creation/lookup flow
- Post-authentication processing
- Error logging before re-throwing
The implementation correctly integrates with the existing authentication infrastructure.
apps/webapp/package.json (1)
194-194: No action needed—remix-auth-google v2.0.0 is the latest stable version with no known security vulnerabilities.Version 2.0.0 is the latest available release on npm, and no CVEs are reported for this package. The caret constraint (^2.0.0) is appropriate and will allow patch and minor version updates. Monitor related Remix auth libraries (e.g., authkit-remix) for vulnerabilities.
apps/webapp/app/routes/auth.github.callback.tsx (1)
45-49: LGTM!The refactoring to use
Headerswith multipleappendcalls for setting both the session and last-auth-method cookies is correct and follows the proper pattern for multipleSet-Cookieheaders in Remix.Also applies to: 55-59
apps/webapp/app/routes/login._index/route.tsx (2)
74-120: LGTM!The loader correctly fetches
lastAuthMethodfrom the request cookie and includes bothshowGoogleAuthandlastAuthMethodin both response paths. The data flow is consistent.
136-188: LGTM!The login UI correctly renders provider buttons conditionally and displays the "Last used" badge based on the
lastAuthMethodvalue. The form actions properly include theredirectToquery parameter.apps/webapp/app/routes/auth.google.callback.tsx (1)
1-60: LGTM!The Google OAuth callback follows the established pattern from the GitHub callback. The implementation correctly handles:
- Redirect cookie parsing and sanitization
- Authentication with the "google" strategy
- MFA flow detection and redirect
- Multiple
Set-Cookieheaders for session and last-auth-methodapps/webapp/app/services/lastAuthMethod.server.ts (1)
13-24: LGTM!The
getLastAuthMethodandsetLastAuthMethodHeaderfunctions are well-implemented with proper type safety and explicit validation of cookie values.apps/webapp/app/models/user.server.ts (4)
24-31: LGTM!The
FindOrCreateGoogletype follows the established pattern fromFindOrCreateGithuband correctly uses a type instead of an interface per coding guidelines. The union type is properly extended.
210-229: Inconsistent behavior with GitHub user linking.When linking an existing email user to Google auth, this code updates
authenticationMethodto"GOOGLE". However,findOrCreateGithubUser(lines 120-137) does not updateauthenticationMethodwhen linking. This inconsistency could cause confusion about the user's primary auth method.Is this intentional? If so, consider adding a comment explaining why the behavior differs. If not, align the behavior:
// Link existing email account to Google auth const user = await prisma.user.update({ where: { email, }, data: { - authenticationMethod: "GOOGLE", authenticationProfile: authProfile, authenticationExtraParams: authExtraParams, avatarUrl, authIdentifier, }, });
250-270: LGTM!The upsert logic for new Google users correctly sets up the user with Google authentication method and profile data. The pattern is consistent with the GitHub implementation.
183-188: All accessed fields exist onGoogleProfiletype and are correctly typed.The web search confirms that
GoogleProfilefromremix-auth-googleincludes all accessed fields:
_json.name: string ✓photos: array of objects withvalueproperty ✓displayName: string ✓id: string ✓The code safely accesses these fields. The
if (authenticationProfile.photos[0])guard on line 185 prevents null/undefined access issues.
There was a problem hiding this 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/webapp/app/assets/logos/GoogleLogo.tsx (1)
1-22: LGTM! Consider adding accessibility attributes.The GoogleLogo component is well-implemented with proper SVG structure and styling. The named export follows the coding guidelines.
For improved accessibility, consider adding an
aria-labelor wrapping the SVG in a way that provides context for screen reader users, especially if this logo is used in interactive elements like buttons.Example enhancement:
-export function GoogleLogo({ className }: { className?: string }) { +export function GoogleLogo({ className, ariaLabel }: { className?: string; ariaLabel?: string }) { return ( - <svg className={className} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <svg + className={className} + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + aria-label={ariaLabel} + role={ariaLabel ? "img" : undefined} + > <pathapps/webapp/app/routes/login._index/route.tsx (3)
22-40: LastUsedBadge implementation looks solid; consider minor a11y / UX tweaksThe motion +
useReducedMotionusage is clean and respects reduced-motion preferences, and the visual treatment is clear.Two small optional refinements:
- To avoid screen readers announcing a detached “Last used” label without context, consider either:
- Marking the badge container as decorative:
aria-hidden="true", or- Wiring it via
aria-describedbyfrom the corresponding button, so it’s semantically tied to that control.- If you find the badge sometimes intercepts clicks near the right edge of the button, you could add
pointer-events-noneon the outer wrapper (and re-enable pointer events only on the button if needed).These are polish-level changes; current behavior is acceptable if you’re okay with the existing semantics.
118-181: Multi‑provider login UI and “last used” badge behavior look coherentThe new layout with stacked GitHub, Google, and Email options is consistent:
- Conditional rendering via
data.showGithubAuth/data.showGoogleAuthis straightforward.- Action URLs correctly preserve
redirectTowhere present.LastUsedBadgeis correctly scoped viadata.lastAuthMethod === "<provider>"and only displayed when the provider is visible.data.authError && <FormError>continues to behave as expected across loader branches.If this grows further (e.g., more providers), you might eventually want a small
<AuthProviderButton>abstraction to avoid duplicating the container +Form+Buttonpattern, but for the current three providers the duplication is manageable.
183-191: Addrelattribute to external links that usetarget="_blank"Both legal links open in a new tab via
target="_blank", but lack arelattribute. To avoid reverse‑tabnabbing and follow common security best practices, consider:- <TextLink href="https://trigger.dev/legal" target="_blank"> + <TextLink href="https://trigger.dev/legal" target="_blank" rel="noreferrer noopener"> … - <TextLink href="https://trigger.dev/legal/privacy" target="_blank"> + <TextLink href="https://trigger.dev/legal/privacy" target="_blank" rel="noreferrer noopener">Even though these are same‑origin links, using
rel="noopener noreferrer"on alltarget="_blank"links is a good default.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/webapp/app/assets/logos/GoogleLogo.tsx(1 hunks)apps/webapp/app/routes/login._index/route.tsx(6 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
Files:
apps/webapp/app/routes/login._index/route.tsxapps/webapp/app/assets/logos/GoogleLogo.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/routes/login._index/route.tsxapps/webapp/app/assets/logos/GoogleLogo.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
apps/webapp/app/routes/login._index/route.tsxapps/webapp/app/assets/logos/GoogleLogo.tsx
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/routes/login._index/route.tsxapps/webapp/app/assets/logos/GoogleLogo.tsx
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Files:
apps/webapp/app/routes/login._index/route.tsxapps/webapp/app/assets/logos/GoogleLogo.tsx
**/*.{js,ts,jsx,tsx,json,md,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier
Files:
apps/webapp/app/routes/login._index/route.tsxapps/webapp/app/assets/logos/GoogleLogo.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
apps/webapp/app/routes/login._index/route.tsx (1)
71-82: Loader wiring forlastAuthMethodand Google support looks correct; verify value domainThe loader changes cleanly plumb
lastAuthMethodandshowGoogleAuththrough both branches of the response, and the UI only branches on strict string matches ("github" | "google" | "email"), so unknown values gracefully result in no badge.One thing to double‑check: ensure
getLastAuthMethod(request)is constrained to a narrow union (e.g."github" | "google" | "email" | null) and safely handles missing/invalid cookies, ideally with validation at the helper level (e.g. zod narrowing). That keeps the loader anduseTypedLoaderDatatypes tight and prevents accidental propagation of arbitrary values.Also applies to: 103-108
| where: { | ||
| authIdentifier, | ||
| }, | ||
| update: {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the google suite, there is a way to change your email. There is an edge case when the idp user entity exists (existingUser) but the existingEmailUser doesn't. In such situation I think we want to update the user's email?
Another edge case is when user changes their email, and both existingUser and existingEmailUser exist, but they reference different user entities - conflict. Not sure if we can resolve it in code, but maybe it's worth to log it?
…t in the db but their email doesn't
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/webapp/app/models/user.server.ts(4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
Files:
apps/webapp/app/models/user.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/models/user.server.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
apps/webapp/app/models/user.server.ts
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/models/user.server.ts
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Files:
apps/webapp/app/models/user.server.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier
Files:
apps/webapp/app/models/user.server.ts
🧠 Learnings (2)
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL
Applied to files:
apps/webapp/app/models/user.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Leverage the PostgreSQL database through the `trigger.dev/database` Prisma 6.14.0 client in the webapp for all data access patterns
Applied to files:
apps/webapp/app/models/user.server.ts
🧬 Code graph analysis (1)
apps/webapp/app/models/user.server.ts (1)
apps/webapp/app/utils/email.ts (1)
assertEmailAllowed(3-13)
⏰ 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). (23)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/webapp/app/models/user.server.ts (3)
3-3: LGTM! Type definitions follow existing patterns.The GoogleProfile import and FindOrCreateGoogle type definition are consistent with the existing GitHub authentication implementation.
Also applies to: 24-31
46-48: LGTM! Switch case properly integrated.The Google authentication case correctly delegates to the new handler function, maintaining consistency with existing authentication methods.
176-196: LGTM! Profile extraction and validation are correct.The email validation and profile data extraction follow the same pattern as the GitHub authentication implementation.
| if (existingEmailUser && !existingUser) { | ||
| // Link existing email account to Google auth | ||
| const user = await prisma.user.update({ | ||
| where: { | ||
| email, | ||
| }, | ||
| data: { | ||
| authenticationMethod: "GOOGLE", | ||
| authenticationProfile: authProfile, | ||
| authenticationExtraParams: authExtraParams, | ||
| avatarUrl, | ||
| authIdentifier, | ||
| }, | ||
| }); | ||
|
|
||
| return { | ||
| user, | ||
| isNewUser: false, | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove authenticationMethod update when linking existing users.
When linking an existing email-based user to Google authentication, line 217 overwrites the user's authenticationMethod to "GOOGLE". This is inconsistent with the GitHub authentication implementation (lines 120-137), which does not update authenticationMethod when linking accounts.
Overwriting the authentication method could:
- Break existing authentication flows that rely on this field
- Prevent users from using their original authentication method
- Create confusion about the user's original signup method
Apply this diff to maintain consistency:
const user = await prisma.user.update({
where: {
email,
},
data: {
- authenticationMethod: "GOOGLE",
authenticationProfile: authProfile,
authenticationExtraParams: authExtraParams,
avatarUrl,
authIdentifier,
},
});📝 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.
| if (existingEmailUser && !existingUser) { | |
| // Link existing email account to Google auth | |
| const user = await prisma.user.update({ | |
| where: { | |
| email, | |
| }, | |
| data: { | |
| authenticationMethod: "GOOGLE", | |
| authenticationProfile: authProfile, | |
| authenticationExtraParams: authExtraParams, | |
| avatarUrl, | |
| authIdentifier, | |
| }, | |
| }); | |
| return { | |
| user, | |
| isNewUser: false, | |
| }; | |
| } | |
| if (existingEmailUser && !existingUser) { | |
| // Link existing email account to Google auth | |
| const user = await prisma.user.update({ | |
| where: { | |
| email, | |
| }, | |
| data: { | |
| authenticationProfile: authProfile, | |
| authenticationExtraParams: authExtraParams, | |
| avatarUrl, | |
| authIdentifier, | |
| }, | |
| }); | |
| return { | |
| user, | |
| isNewUser: false, | |
| }; | |
| } |
🤖 Prompt for AI Agents
In apps/webapp/app/models/user.server.ts around lines 210 to 229, the code that
links an existing email user to Google currently overwrites authenticationMethod
to "GOOGLE"; remove that field from the prisma.user.update data so the existing
authenticationMethod is preserved (keep updating authenticationProfile,
authenticationExtraParams, avatarUrl and authIdentifier as before) to match the
GitHub linking behavior and avoid changing the user's original signup method.
| if (existingEmailUser && existingUser) { | ||
| // User already linked to Google, update profile info | ||
| const user = await prisma.user.update({ | ||
| where: { | ||
| id: existingUser.id, | ||
| }, | ||
| data: { | ||
| avatarUrl, | ||
| authenticationProfile: authProfile, | ||
| authenticationExtraParams: authExtraParams, | ||
| }, | ||
| }); | ||
|
|
||
| return { | ||
| user, | ||
| isNewUser: false, | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle the edge case when different users have conflicting email and auth identifiers.
The condition on line 231 doesn't verify that existingEmailUser and existingUser reference the same user. This edge case can occur when a user changes their Google email to an address already taken by a different user in your system.
Current behavior:
- Updates the Google-authenticated user's profile (lines 233-242)
- Does not update the email to match Google's current email
- Leaves the email mismatch unresolved
- Does not log or alert about the conflict
Inconsistency: The update (lines 237-241) only modifies avatarUrl and auth profiles, while the upsert update path (lines 257-262) also updates email, displayName, and name. This creates inconsistent behavior.
Based on learnings, as per the past review comment, this edge case should be addressed.
Apply this diff to detect the conflict and update all relevant fields:
if (existingEmailUser && existingUser) {
- // User already linked to Google, update profile info
+ if (existingEmailUser.id !== existingUser.id) {
+ // Conflict: Google account and email belong to different users
+ // This can happen if user changes their Google email to one already in use
+ console.error(
+ `Google auth conflict: Google ID ${authenticationProfile.id} belongs to user ${existingUser.id}, ` +
+ `but email ${email} belongs to user ${existingEmailUser.id}`
+ );
+ // Return the existing Google-authenticated user without updating email
+ return {
+ user: existingUser,
+ isNewUser: false,
+ };
+ }
+
+ // User already linked to Google, update profile info
const user = await prisma.user.update({
where: {
id: existingUser.id,
},
data: {
+ email,
+ displayName,
+ name,
avatarUrl,
authenticationProfile: authProfile,
authenticationExtraParams: authExtraParams,
},
});📝 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.
| if (existingEmailUser && existingUser) { | |
| // User already linked to Google, update profile info | |
| const user = await prisma.user.update({ | |
| where: { | |
| id: existingUser.id, | |
| }, | |
| data: { | |
| avatarUrl, | |
| authenticationProfile: authProfile, | |
| authenticationExtraParams: authExtraParams, | |
| }, | |
| }); | |
| return { | |
| user, | |
| isNewUser: false, | |
| }; | |
| } | |
| if (existingEmailUser && existingUser) { | |
| if (existingEmailUser.id !== existingUser.id) { | |
| // Conflict: Google account and email belong to different users | |
| // This can happen if user changes their Google email to one already in use | |
| console.error( | |
| `Google auth conflict: Google ID ${authenticationProfile.id} belongs to user ${existingUser.id}, ` + | |
| `but email ${email} belongs to user ${existingEmailUser.id}` | |
| ); | |
| // Return the existing Google-authenticated user without updating email | |
| return { | |
| user: existingUser, | |
| isNewUser: false, | |
| }; | |
| } | |
| // User already linked to Google, update profile info | |
| const user = await prisma.user.update({ | |
| where: { | |
| id: existingUser.id, | |
| }, | |
| data: { | |
| email, | |
| displayName, | |
| name, | |
| avatarUrl, | |
| authenticationProfile: authProfile, | |
| authenticationExtraParams: authExtraParams, | |
| }, | |
| }); | |
| return { | |
| user, | |
| isNewUser: false, | |
| }; | |
| } |
🤖 Prompt for AI Agents
In apps/webapp/app/models/user.server.ts around lines 231 to 248, detect if
existingEmailUser and existingUser refer to different users
(existingEmailUser.id !== existingUser.id): if they are the same user proceed to
update all profile fields (email, displayName, name, avatarUrl,
authenticationProfile, authenticationExtraParams) to match the upsert path; if
they differ, log a clear warning about the email/auth conflict and return a
conflict result (or throw a specific error) instead of silently updating, so the
caller can surface the conflict to the user for resolution.
There was a problem hiding this 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/webapp/app/routes/login._index/route.tsx (1)
22-40: Consider adding an accessible label for screen readers.The
LastUsedBadgecomponent respects motion preferences (good!), but it lacks semantic information for assistive technologies. Screen reader users won't know which authentication method was last used.Consider adding an
aria-labelto the motion.div:<motion.div className="relative rounded border border-charcoal-700 bg-charcoal-800 px-2 py-1 text-center text-xxs font-medium uppercase text-blue-500" + aria-label="Last used authentication method" initial={shouldReduceMotion ? undefined : { opacity: 0, x: 4 }} animate={shouldReduceMotion ? undefined : { opacity: 1, x: 0 }} transition={shouldReduceMotion ? undefined : { duration: 0.8, ease: "easeOut" }} >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/webapp/app/routes/login._index/route.tsx(6 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
Files:
apps/webapp/app/routes/login._index/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/routes/login._index/route.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
apps/webapp/app/routes/login._index/route.tsx
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/routes/login._index/route.tsx
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Files:
apps/webapp/app/routes/login._index/route.tsx
**/*.{js,ts,jsx,tsx,json,md,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier
Files:
apps/webapp/app/routes/login._index/route.tsx
🧬 Code graph analysis (1)
apps/webapp/app/routes/login._index/route.tsx (6)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
getLastAuthMethod(14-21)apps/webapp/app/services/auth.server.ts (1)
isGoogleAuthSupported(31-31)apps/webapp/app/components/primitives/Headers.tsx (1)
Header1(32-50)apps/webapp/app/components/primitives/Paragraph.tsx (1)
Paragraph(88-107)apps/webapp/app/components/primitives/Buttons.tsx (1)
Button(296-329)apps/webapp/app/assets/logos/GoogleLogo.tsx (1)
GoogleLogo(1-22)
⏰ 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). (23)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
apps/webapp/app/routes/login._index/route.tsx (4)
5-5: LGTM!The new imports correctly support Google authentication and the last-used indicator feature. The framer-motion library is appropriately used for the animated badge component.
Also applies to: 7-7, 15-16
71-71: LGTM!The loader correctly fetches the last-used authentication method and Google auth support flag, passing them consistently to the UI in both conditional branches.
Also applies to: 80-81, 106-107
127-179: Well-structured multi-provider authentication UI.The conditional rendering of
LastUsedBadgefor each authentication method is correctly implemented. Each provider is properly wrapped in a relative container, and the form actions correctly include the redirectTo parameter.
118-194: Clean and well-organized layout structure.The login page structure is logically organized with clear sections for the header, authentication options, error display, and legal notices. The terms and privacy links properly open in new tabs.
Uh oh!
There was an error while loading. Please reload this page.