feat(mascot): accept PNG/GIF/JPEG/WebP custom avatars with file upload - #5420
Conversation
- Widen custom avatar validation from `.gif`-only to any safe raster image (PNG/JPEG/WebP/GIF/BMP) for URLs, plus base64 `data:image/*` sources for uploads. SVG stays rejected (inline-script risk). - Add an "Upload image" button in the Mascot settings panel that inlines a local file as a data URL, gated on MIME allowlist and a 1.5 MB size cap so an oversize blob can't blow the localStorage quota and drop the whole mascot slice. - Relabel the setting to "Custom image avatar" across all 15 locales. Closes tinyhumansai#5360
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 14 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (18)
📝 WalkthroughWalkthroughMascot settings now accept raster image URLs and local PNG, GIF, JPEG, and WebP uploads. Files are validated for type and size, converted to data URIs, persisted as custom avatar URLs, and covered by localized errors and tests. ChangesCustom mascot avatar support
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant MascotPanel
participant fileToDataUri
participant mascotSlice
User->>MascotPanel: Select image file
MascotPanel->>MascotPanel: Validate MIME type and size
MascotPanel->>fileToDataUri: Convert valid file
fileToDataUri-->>MascotPanel: Return data URI
MascotPanel->>mascotSlice: Store custom mascot URL
Possibly related PRs
Suggested labels: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
YellowSnnowmann has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9c818c1eb4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 19
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/components/settings/panels/MascotPanel.tsx`:
- Around line 203-207: Add an analyticsId to the upload Button associated with
the custom mascot GIF flow, then call trackAnalyticsEvent immediately after
dispatch(setCustomMascotGifUrl(dataUri)) for successful uploads. Include only
privacy-safe, stable dimensions such as upload outcome or file category, and do
not send file contents, names, or other identifying data.
- Line 645: Add BMP support consistently across local avatar uploads: in
app/src/components/settings/panels/MascotPanel.tsx lines 645-645, update the
upload control’s accept value to include image/bmp; in
app/src/components/settings/panels/__tests__/MascotPanel.test.tsx lines 320-358,
add a BMP upload test verifying conversion and persistence; in
app/src/lib/i18n/ar.ts lines 5720-5729, update the supported-image guidance and
validation text to mention BMP.
- Around line 208-210: Remove the error object from the console.debug call in
the FileReader failure catch within the custom GIF upload flow, keeping only a
fixed non-identifying failure message or event before setting customGifError.
Preserve the existing user-facing error handling.
In `@app/src/lib/i18n/bn.ts`:
- Line 5853: Update the Bengali avatar URL guidance and upload type error
messages near the shown translation entry so both enumerate every accepted
source and format: HTTPS, loopback HTTP, file://, local paths, base64
data:image/* sources, and PNG, GIF, JPEG, WebP, and BMP. Keep the wording
consistent across both messages.
In `@app/src/lib/i18n/de.ts`:
- Around line 6014-6020: Update the German strings for the avatar URL guidance
and invalid file type, identified by the
settings.mascot.customGifDescription/customGifInvalidType keys, to mention
HTTPS, loopback HTTP, file://, local paths, data:image/* sources, and PNG, GIF,
JPEG, WebP, and BMP formats. Preserve the existing German wording style while
ensuring both messages list the complete supported sources and formats.
In `@app/src/lib/i18n/en.ts`:
- Line 6452: Update the settings.persona.appearanceDesc translation to replace
the GIF-specific “custom GIF avatar” wording with the consistent “custom image
avatar” terminology, matching settings.mascot.customGifHeading.
- Around line 6451-6457: Update the avatar URL guidance and customGifInvalidType
message to list all supported sources—HTTPS, loopback HTTP, file://, local URLs,
and data:image/*—and all supported formats, including PNG, GIF, JPEG, WebP, and
BMP. Remove the HTTPS-only wording while keeping SVG excluded from both
messages.
In `@app/src/lib/i18n/es.ts`:
- Line 5962: Update the Spanish avatar guidance strings at the shown message and
its related entries to mention every accepted source and format: HTTPS, loopback
HTTP, file:// and local paths, base64 data:image/* URLs, and PNG, GIF, JPEG,
WebP, and BMP. Keep the wording consistent across all applicable translations
and aligned with the avatar input contract.
In `@app/src/lib/i18n/fr.ts`:
- Around line 5993-5999: Update the French strings for the custom mascot image
guidance, specifically settings.mascot.customGifHeading and
settings.mascot.customGifInvalidType, to include loopback HTTP and data:image/*
among supported sources and BMP among supported formats, while preserving the
existing French wording and supported PNG, GIF, JPEG, and WebP entries.
In `@app/src/lib/i18n/hi.ts`:
- Around line 5850-5856: Update the Hindi mascot image guidance strings,
including settings.mascot.customGifError and the adjacent custom URL/upload
validation message, to list every supported source: HTTPS, loopback HTTP,
file://, local paths, and data:image/*; list PNG, JPEG, WebP, GIF, and BMP
formats consistently.
In `@app/src/lib/i18n/id.ts`:
- Around line 5879-5888: Update the Indonesian strings
settings.mascot.customGifError and settings.mascot.customGifInvalidType to
include BMP as a supported image format, matching the formats accepted by
isCustomMascotGifUrl; preserve the existing guidance for PNG, GIF, JPEG, and
WebP.
In `@app/src/lib/i18n/it.ts`:
- Around line 5949-5958: Update the Italian messages
settings.mascot.customGifError and settings.mascot.customGifInvalidType to
reflect the full supported image contract: HTTPS, loopback HTTP, file://, local
paths, data:image/*, and PNG, JPEG, WebP, GIF, and BMP formats.
In `@app/src/lib/i18n/ko.ts`:
- Around line 5783-5789: Update the Korean mascot custom image help and
invalid-type messages associated with settings.mascot.customGifHeading and
settings.mascot.customGifInvalidType to include BMP alongside PNG, GIF, JPEG,
and WebP. Ensure the manual-entry guidance also enumerates the
validator-supported loopback HTTP, local path, and data:image/* sources when
applicable, keeping both messages consistent with the complete accepted source
set.
In `@app/src/lib/i18n/pl.ts`:
- Line 5940: Update the translation string near the image-source validation
error to list every URL-validator-supported source: loopback HTTP, HTTPS,
file://, local images, and data:image/*, including BMP where applicable. Keep
the upload-specific format list separate if BMP is not accepted for uploads, and
align the wording with the validator’s actual accepted formats.
In `@app/src/lib/i18n/pt.ts`:
- Around line 5943-5951: Update the Portuguese strings for
settings.mascot.customGifInvalidType and the preceding image URL/upload guidance
to include BMP among the supported formats, keeping the existing PNG, GIF, JPEG,
and WebP formats unchanged.
In `@app/src/lib/i18n/ru.ts`:
- Around line 5910-5918: Update the Russian validation strings near
settings.mascot.customGifInvalidType and the preceding URL guidance to reflect
the complete supported image matrix: include BMP, loopback HTTP, local paths,
and raster data URLs alongside PNG, GIF, JPEG, and WebP. Keep the wording
consistent across the input guidance and invalid-type message.
In `@app/src/lib/i18n/zh-CN.ts`:
- Line 5543: Update the related guidance strings at the shown entries to
accurately list every validator-supported source: HTTPS, loopback HTTP, file://,
local paths, base64 data:image/* sources, and uploaded files. Include all
accepted image formats—PNG, GIF, JPEG, WebP, and BMP—and describe local paths as
paths rather than links.
In `@app/src/store/mascotSlice.ts`:
- Around line 125-143: The isCustomMascotGifUrl validation flow lacks
privacy-safe diagnostics for its outcomes. Add verbose, grep-friendly
[mascot-avatar] logs at entry, each validation branch/rejection, and success,
recording only a source category and input length; never include the URL, local
path, data URL, or decoded content.
- Around line 102-115: Update isCustomMascotAvatarDataUrl and
CUSTOM_MASCOT_AVATAR_DATA_URL_RE in app/src/store/mascotSlice.ts (lines 102-115)
to require complete base64 quartets with valid optional padding, rejecting
malformed payloads such as A=. Extend the malformed-padding coverage in
app/src/store/__tests__/mascotSlice.test.ts (lines 247-256) and assert both
validation and reducer rejection for those inputs.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0d3fcc13-5eef-46e5-b5bd-4ccb6eaf4a5d
📒 Files selected for processing (18)
app/src/components/settings/panels/MascotPanel.tsxapp/src/components/settings/panels/__tests__/MascotPanel.test.tsxapp/src/lib/i18n/ar.tsapp/src/lib/i18n/bn.tsapp/src/lib/i18n/de.tsapp/src/lib/i18n/en.tsapp/src/lib/i18n/es.tsapp/src/lib/i18n/fr.tsapp/src/lib/i18n/hi.tsapp/src/lib/i18n/id.tsapp/src/lib/i18n/it.tsapp/src/lib/i18n/ko.tsapp/src/lib/i18n/pl.tsapp/src/lib/i18n/pt.tsapp/src/lib/i18n/ru.tsapp/src/lib/i18n/zh-CN.tsapp/src/store/__tests__/mascotSlice.test.tsapp/src/store/mascotSlice.ts
The CEF native file panel only greyed-in PNG — a bare `image/jpeg`, `image/gif` or `image/webp` MIME can end up unmapped, leaving those files unselectable. Pair each MIME with its extension (the same convention the JSON importers use) and add BMP, which the reducer and the MIME allowlist already accept. `isAllowedMimeType` still gates the read, so this widens the picker without widening what we accept.
There was a problem hiding this comment.
YellowSnnowmann has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
- Discard an avatar upload whose file read resolves after the user picked a
different mascot, hit Save, or hit Reset. The slower read used to land last
and resurrect the upload while wiping the selection the reducer had applied.
Uses the same monotonic request-id pattern as the voice preview above it.
- Require structurally valid base64 in the data-URL pattern (whole quartets,
at most one padded tail). The old `[A-Za-z0-9+/]+={0,2}` accepted payloads
like `A=` that no image decoder can render, so the reducer persisted a
silently broken avatar.
- Drop the FileReader error object from diagnostics — its message embeds
`File.name`, which can be personal. Log the type and size instead.
- Add privacy-safe `[mascot-avatar] store:` diagnostics at the reducer
boundary; a rejected value is otherwise invisible because the failure mode
is a cleared avatar rather than an error. Source category plus length only.
- List BMP in the avatar error copy across all 15 locales (the reducer, the
MIME allowlist, and the file picker already accepted it), and retire the
leftover "custom GIF avatar" wording in settings.persona.appearanceDesc.
There was a problem hiding this comment.
YellowSnnowmann has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
…image The shell installs no CefDialogHandler, so `accept` conversion falls to CEF's built-in file-dialog runner, which does not expand an enumerated accept list into selectable macOS file types. Both `image/png,image/jpeg,…` and those MIMEs paired with `.png,.jpg,…` left every non-PNG image greyed out and unselectable in the native panel. The wildcard goes through CEF's mime-table expansion and offers every known image type; verified in a running dev build. The picker widens but the contract does not: `isAllowedMimeType` still gates the read, so SVG (inline-script risk) and any other type outside the allowlist is rejected with a visible error rather than reaching the store.
|
Follow-up after manual verification in a running dev build (5556b0a). The upload button's file picker only offered PNG — every JPEG/GIF/WebP file was greyed out and unselectable in the native macOS panel. Two enumerated Root cause: the Tauri shell installs no Worth noting the picker is now wider than the allowlist: SVG is offered by the dialog. The accepted set is unchanged, because |
There was a problem hiding this comment.
YellowSnnowmann has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
Summary
.gifURLs. Widened validation to any safe raster image — PNG/JPEG/WebP/GIF/BMP — forhttps/loopback-http/file:///local-path URLs, and added base64data:image/*as an accepted source. SVG stays rejected (an SVG can carry inline scripts, and the render path is a plain<img>).customMascotGifUrlfield, so the render path (CustomGifMascot→<img>) is unchanged and GIF animation is preserved for free.mascotslice, anduserScopedStorage.setItemswallowsQuotaExceededError— an oversize write would silently drop the entire slice (colour, voice, selection). A reducer-boundary length backstop (~2.2 MB, base64's ~4/3 inflation) catches a hand-pasted or tampered data URL that skipped the UI check.Test plan
pnpm compile)mascotSlice/MascotPanel/CustomGifMascot, plus 71 i18n coverage tests confirming no locale is missing the new keysCloses #5360
Summary by CodeRabbit
New Features
file://image sources for mascot avatars.Bug Fixes