refactor(frontend): Profile page hub-and-spoke layout#136
Conversation
| </div> | ||
| <p class="font-body text-xs text-blue-600 mt-2"> | ||
| Use your email <strong>{$currentUser?.email}</strong> and an app password to sign in. | ||
| {@html $i18n.t('profile.carddav.useCredentials', { email: $currentUser?.email })} |
There was a problem hiding this comment.
XSS security issue via @html with unescaped user data: The i18n library uses escapeValue=false, but @html bypasses Svelte escaping entirely. The user-controlled email is interpolated into the translation string without HTML-encoding, then injected raw into the DOM. A crafted email could execute arbitrary JavaScript. Suggested fix: split the template so email renders via a normal Svelte expression (auto-escaped) rather than inside @html.
| let passkeyCount = $state(0); | ||
| let appPasswordCount = $state(0); | ||
|
|
||
| onMount(async () => { |
There was a problem hiding this comment.
Missing error handling in onMount API calls: If any of the three parallel API calls rejects (network error, auth expiry, etc.), Promise.all rejects immediately and the passkeyCount / appPasswordCount state variables remain at 0. The hub will silently show 'No passkeys registered' and 'No app passwords' even when the user may have existing records, with no error indicator shown to the user. Suggested fix: wrap the Promise.all in a try/catch so that failures are handled gracefully and counts stay at 0 without crashing the component.
|
Automated Code Review - Commit c6a0716 - Reviewed 2026-03-16 - Status Approved - No new issues found. Previously flagged issues resolved: XSS via html+email (now auto-escaped), silent onMount failure (try/catch added). AGENTS.md compliant. Clean refactor. Automated review by Claude Code CI run 23167414983 |
…e layout The profile page was a single 240-line scrollable page with 6 vertically stacked sections. This refactors it into a hub page at /profile showing a card-grid overview with live status summaries, and 6 dedicated spoke pages (account, display, passkeys, app-passwords, messaging, carddav) each with their own route and back-link. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nent The CardDAV setup guide had all its strings hardcoded in English (server URL header, copy button, setup steps, field labels, important notice). Wire up existing profile.carddav.* i18n keys and add new keys for the step-by-step instructions and field labels in both en.json and de.json. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b53f00a to
c6a0716
Compare
|
🎉 This PR is included in version 2.67.4 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
/profileshows a card-grid overview with live status summaries (passkey count, app password count, channel count, etc.)/profile/account,/profile/display,/profile/passkeys,/profile/app-passwords,/profile/messaging,/profile/carddavProfileCardreusable component and shared+layout.sveltefor page chromeCardDAVSetupGuidecomponent to i18n (EN + DE)Test plan
/profile— hub renders with cards and live status summariespnpm --filter frontend checkpasses with zero new errors🤖 Generated with Claude Code