Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9da75d3
feat(admin): accept drag and drop on the VR and sticker upload zones …
sparkyfen Sep 1, 2026
99df4f9
fix(admin): ship round 1 fixes for drag-and-drop upload zones (SONA-216)
sparkyfen Sep 1, 2026
4c9c2c4
fix(admin): ship round 2 fixes for drag-and-drop upload zones (SONA-216)
sparkyfen Sep 1, 2026
497168a
fix(admin): ship round 3 fixes for drag-and-drop upload zones (SONA-216)
sparkyfen Sep 1, 2026
6c88420
fix(admin): ship round 4 fixes for drag-and-drop upload zones (SONA-216)
sparkyfen Sep 1, 2026
69cbd78
fix(admin): ship round 5 fixes for drag-and-drop upload zones (SONA-216)
sparkyfen Sep 1, 2026
33b4d77
test(admin): settle the drop helper deterministically and assert the …
sparkyfen Sep 1, 2026
93bbfbe
fix(admin): swallow drops on the model card and gate the sticker zone…
sparkyfen Sep 1, 2026
2657316
fix(admin): refuse files while a save is in flight and filter picked …
sparkyfen Sep 1, 2026
105e9bf
fix(admin): share the accept partition across pickers and drops, gate…
sparkyfen Sep 1, 2026
e4e2b86
fix(admin): swallow stray file drops page-wide and only light zones f…
sparkyfen Sep 1, 2026
6c00afa
fix(admin): keep zones cancelling non-file drags, pin the status text…
sparkyfen Sep 1, 2026
4a67b83
docs(admin): say why the page-wide drop guard stays narrower than the…
sparkyfen Sep 1, 2026
6539b2f
feat(admin): device-independent zone hints and a persistent sticker e…
sparkyfen Sep 2, 2026
1922419
fix(admin): drop the unreachable no-stickers status branch for parity…
sparkyfen Sep 2, 2026
7d7986d
fix(admin): theme-safe sticker error banner, client-side size check, …
sparkyfen Sep 2, 2026
363128e
fix(admin): announce repeated upload statuses, harden the upload resp…
sparkyfen Sep 2, 2026
6ed2e85
fix(admin): guard the VR media upload response like the sticker form …
sparkyfen Sep 2, 2026
da9fe87
test(admin): assert the drop attachment cancels a file drop (SONA-216)
sparkyfen Sep 2, 2026
01e74d2
fix(admin): type-check the upload response url and assert a busy zone…
sparkyfen Sep 2, 2026
90a63c0
refactor(admin): move the gallery upload page onto the shared drop at…
sparkyfen Sep 3, 2026
502bd9b
fix(admin): disable the gallery upload picker while a save is in flig…
sparkyfen Sep 3, 2026
b19ff29
fix(admin): let text drags reach the tile labels, announce refused fi…
sparkyfen Sep 3, 2026
19f3ad1
fix(admin): pass drags through only to text fields, announce upload o…
sparkyfen Sep 3, 2026
f24ccfc
fix(admin): announce a mixed upload batch with one message per locale…
sparkyfen Sep 3, 2026
dbc178e
fix(admin): announce gallery batches in two writes, close them out ho…
sparkyfen Sep 3, 2026
ffaa3a1
fix(admin): count every refused tile in the gallery announcement, gat…
sparkyfen Sep 3, 2026
9a51a1f
fix(admin): check the gallery upload response url, word the over-limi…
sparkyfen Sep 3, 2026
35f316c
fix(admin): localize a non-JSON upload response, check the duplicate …
sparkyfen Sep 3, 2026
2561111
fix(admin): pin the sticker accept set exactly and localize a bad dup…
sparkyfen Sep 3, 2026
e7c6c0c
test(admin): watch the upload request window on the stray-drop assert…
sparkyfen Sep 3, 2026
e3aaa88
fix(admin): skip the preview for every refused tile so an oversized i…
sparkyfen Sep 3, 2026
2dbecea
Merge remote-tracking branch 'origin/main' into sparky/sona-216-admin…
sparkyfen Sep 3, 2026
1728b8d
docs(storage): describe the sticker form's per-file refusal banner (S…
sparkyfen Sep 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/image-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ Each caller handles the refusal in its own way. An upload through `/api/upload`
returns 422 and asks you to re-export the file. A fursuit import counts that
photo as failed and logs the reason. Avatar re-hosting logs a warning and keeps
the source URL as a hotlink. A sticker import reports the failure for that
sticker. Uploading stickers by hand in the pack form counts the refused files
among the failures and names the refusal in a second message with its own
count, because the operator picked those files and can re-export them. A provider migration lists the object as failed and asks you to replace
sticker. Uploading stickers by hand in the pack form names each refused file
and the fix on its own line under the upload zone, because the operator picked
those files and can re-export them. A provider migration lists the object as failed and asks you to replace
it with a fresh copy. The sticker re-key reports it the same way a migration
does, because the operator has to replace the file either way.

Expand Down
42 changes: 32 additions & 10 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,15 @@
"admin_upload_uploaded": "Uploaded",
"admin_upload_replace_hint": "Click or drag to replace",
"admin_upload_retry_hint": "Click or drag to try again",
"admin_upload_dropzone": "Drag & drop images here, or click to browse",
"admin_upload_dropzone_multi": "Drag & drop up to {max} images here, click to browse, or paste from clipboard",
"admin_upload_dropzone_multi": "Choose up to {max} images, drag them here, or paste from the clipboard",
"admin_upload_images_added": "{count} image(s) added",
"admin_upload_over_limit": "{count} image(s) skipped — max {max}",
"admin_upload_over_limit": "{count} file(s) skipped — max {max}",
"admin_upload_images_rejected": "{count} file(s) couldn't be added",
"admin_upload_images_added_and_rejected": "{added} image(s) added. {rejected} file(s) couldn't be added",
"admin_upload_batch_done": "Upload finished.",
"admin_upload_batch_issues": "Upload finished with errors. Each file that failed shows the reason.",
"admin_upload_error_too_large": "This file is over {max}. Try a smaller image.",
"admin_upload_error_bad_type": "That file type isn't supported. Use PNG, JPEG, GIF, WebP, or AVIF.",
"admin_field_variant_of": "Variant of",
"admin_field_variant_label": "Variant label",
"admin_variant_none": "Not a variant",
Expand All @@ -436,7 +440,7 @@
"admin_variant_group_title": "Group as variants",
"admin_variant_group_pick_parent": "Pick the parent — the other images become its variants.",
"admin_variant_group_confirm": "Group",
"admin_upload_formats": "Supports PNG, JPG, GIF, WEBP up to 64MB",
"admin_upload_formats": "Supports PNG, JPEG, GIF, WebP, and AVIF up to 64MB",
"admin_upload_image_details": "Image Details",
"admin_upload_title_placeholder": "Enter artwork title...",
"admin_upload_select_existing": "Select Existing",
Expand Down Expand Up @@ -855,8 +859,26 @@
"admin_pack_save_failed": "Could not save pack",
"admin_pack_manual_intro": "Upload sticker images (PNG or WebP) and fill in the pack details. Each sticker can have its own artist and emoji. Files are uploaded to storage before saving.",
"admin_pack_edit_heading": "Edit pack: {name}",
"admin_pack_upload_partial": "{ok} of {total} uploaded, {failed} failed",
"admin_pack_upload_unscrubbable": "Couldn't strip hidden metadata from {refused} of the files you picked. Export fresh copies from an image editor and upload those.",
"admin_pack_upload_issues": "Sticker upload finished with errors. Each file that failed shows the reason.",
"admin_pack_error_bad_type": "That file type isn't supported. Use PNG or WebP.",
"admin_pack_error_too_large": "This file is over {max}. Try a smaller image.",
"admin_pack_error_failed": "Upload failed. Check your connection and try again.",
"admin_pack_error_unscrubbable": "Couldn't strip this file's hidden metadata. Export a fresh copy from an image editor and upload that.",
"admin_pack_upload_done": [
{
"declarations": [
"input count",
"local countPlural = count: plural"
],
"selectors": [
"countPlural"
],
"match": {
"countPlural=one": "{count} sticker added",
"countPlural=other": "{count} stickers added"
}
}
],
"admin_pack_details": "Pack details",
"admin_pack_name": "Pack name",
"admin_pack_name_placeholder": "My sticker pack",
Expand All @@ -873,7 +895,7 @@
"admin_pack_publish_off": "Off — saved as draft",
"admin_pack_default_artist": "Default artist",
"admin_pack_edit_hint": "Note: saving replaces all sticker rows. Drag the handle to reorder; order is saved top-to-bottom.",
"admin_pack_dropzone": "Drag & drop PNGs or WebP here, or click to browse",
"admin_pack_dropzone": "Choose PNG or WebP images, or drag them here",
"admin_pack_bulk_tip": "Tip: click a sticker to select (shift-click for a range), then bulk-set the artist or NSFW.",
"admin_pack_select_all": "Select all {count}",
"admin_pack_selected": "{count} selected",
Expand Down Expand Up @@ -1548,7 +1570,7 @@
"admin_vr_field_role_label": "Role name",
"admin_vr_role_label_placeholder": "e.g. Blendshapes",
"admin_vr_field_model": "Model file",
"admin_vr_dropzone": "Choose a .vrm or .fbx file to upload (max {max})",
"admin_vr_dropzone": "Choose a .vrm or .fbx file, or drag it here (max {max})",
"admin_vr_model_hint": "VRM 0.x and 1.0 both work in the 3D viewer. You can still offer FBX files as a download, but the viewer won't display them.",
"admin_vr_upload_progress": "{loaded} of {total} uploaded",
"admin_vr_upload_replace": "Replace",
Expand All @@ -1563,12 +1585,12 @@
"admin_vr_permission_placeholder": "e.g. Telegram DM 2026-08-01 — required to offer downloads",
"admin_vr_section_media": "Showcase media",
"admin_vr_media_hint": "Screenshots and short clips shown under the poster on the public page. Clips can't carry captions, so don't put anything important in speech or audio. They start muted, but visitors can turn the sound on, so you need consent from anyone recorded in the clip.",
"admin_vr_media_dropzone": "Add screenshots or short .webm clips (max {max} each)",
"admin_vr_media_dropzone": "Choose screenshots or short .webm clips, or drag them here (max {max} each)",
"admin_vr_media_kind_image": "Image",
"admin_vr_media_kind_video": "Clip",
"admin_vr_media_remove": "Remove media {position}",
"admin_vr_media_upload_done": "Media upload finished.",
"admin_vr_media_upload_issues": "Media upload finished with errors — see the messages below the dropzone.",
"admin_vr_media_upload_issues": "Media upload finished with errors. Each file that failed shows the reason.",
"admin_vr_media_error_too_large": "This file is over {max}. Try a smaller image, or a shorter clip at a lower resolution.",
"admin_vr_media_error_bad_type": "That file type isn't supported. Use JPEG, PNG, GIF, WebP, AVIF, or a .webm clip.",
"admin_vr_media_error_failed": "Upload failed. Check your connection and try again.",
Expand Down
28 changes: 18 additions & 10 deletions messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,15 @@
"admin_upload_uploaded": "アップロード完了",
"admin_upload_replace_hint": "クリックまたはドラッグで差し替え",
"admin_upload_retry_hint": "クリックまたはドラッグで再試行",
"admin_upload_dropzone": "ここに画像をドラッグ&ドロップするか、クリックして選択してください",
"admin_upload_dropzone_multi": "ここに最大{max}枚の画像をドラッグ&ドロップするか、クリックして選択、またはクリップボードから貼り付けてください",
"admin_upload_dropzone_multi": "最大{max}枚の画像を選択するか、ここにドラッグするか、クリップボードから貼り付けてください",
"admin_upload_images_added": "{count}枚の画像を追加しました",
"admin_upload_over_limit": "{count}枚をスキップしました(最大{max}枚)",
"admin_upload_over_limit": "{count}件のファイルをスキップしました(最大{max}枚)",
"admin_upload_images_rejected": "{count}件のファイルを追加できませんでした",
"admin_upload_images_added_and_rejected": "{added}枚の画像を追加しました。{rejected}件のファイルを追加できませんでした",
"admin_upload_batch_done": "アップロードが完了しました。",
"admin_upload_batch_issues": "アップロードは完了しましたが、エラーがありました。失敗したファイルにはそれぞれ理由が表示されています。",
"admin_upload_error_too_large": "このファイルは{max}を超えています。もっと小さい画像をお試しください。",
"admin_upload_error_bad_type": "対応していないファイル形式です。PNG・JPEG・GIF・WebP・AVIFをご利用ください。",
"admin_field_variant_of": "バリエーション元",
"admin_field_variant_label": "バリエーションラベル",
"admin_variant_none": "バリエーションではない",
Expand All @@ -380,7 +384,7 @@
"admin_variant_group_title": "バリエーションとしてグループ化",
"admin_variant_group_pick_parent": "親を選択してください — 他の画像はそのバリエーションになります。",
"admin_variant_group_confirm": "グループ化",
"admin_upload_formats": "PNG、JPG、GIF、WEBP(最大64MB)に対応しています",
"admin_upload_formats": "PNG・JPEG・GIF・WebP・AVIF(最大64MB)に対応しています",
"admin_upload_image_details": "画像の詳細",
"admin_upload_title_placeholder": "作品のタイトルを入力...",
"admin_upload_select_existing": "既存から選択",
Expand Down Expand Up @@ -645,8 +649,12 @@
"admin_pack_save_failed": "セットを保存できませんでした",
"admin_pack_manual_intro": "ステッカー画像(PNGまたはWebP)をアップロードし、セットの詳細を入力してください。各ステッカーには個別のアーティストと絵文字を設定できます。ファイルは保存前にストレージへアップロードされます。",
"admin_pack_edit_heading": "セットを編集: {name}",
"admin_pack_upload_partial": "{total}件中{ok}件をアップロードしました({failed}件は失敗)",
"admin_pack_upload_unscrubbable": "選択したファイルのうち{refused}件から埋め込まれたメタデータを削除できませんでした。画像編集ソフトで書き出し直したファイルをアップロードしてください。",
"admin_pack_upload_issues": "ステッカーのアップロードは完了しましたが、エラーがありました。失敗したファイルにはそれぞれ理由が表示されています。",
"admin_pack_error_bad_type": "対応していないファイル形式です。PNGまたはWebPをご利用ください。",
"admin_pack_error_too_large": "このファイルは{max}を超えています。もっと小さい画像をお試しください。",
"admin_pack_error_failed": "アップロードに失敗しました。接続を確認してもう一度お試しください。",
"admin_pack_error_unscrubbable": "このファイルに埋め込まれたメタデータを削除できませんでした。画像編集ソフトで書き出し直したファイルをアップロードしてください。",
"admin_pack_upload_done": "ステッカーを{count}枚追加しました",
"admin_pack_details": "セットの詳細",
"admin_pack_name": "セット名",
"admin_pack_name_placeholder": "マイステッカーセット",
Expand All @@ -663,7 +671,7 @@
"admin_pack_publish_off": "オフ — 下書きとして保存されます",
"admin_pack_default_artist": "デフォルトのアーティスト",
"admin_pack_edit_hint": "注意: 保存するとすべてのステッカー行が置き換えられます。ハンドルをドラッグして並べ替えられます。順序は上から下の順で保存されます。",
"admin_pack_dropzone": "PNGまたはWebPをここにドラッグ&ドロップするか、クリックして選択してください",
"admin_pack_dropzone": "PNGまたはWebPの画像を選択するか、ここにドラッグしてください",
"admin_pack_bulk_tip": "ヒント: ステッカーをクリックで選択(Shift+クリックで範囲選択)し、アーティストやNSFWをまとめて設定できます。",
"admin_pack_select_all": "{count}件すべて選択",
"admin_pack_selected": "{count}件選択中",
Expand Down Expand Up @@ -1240,7 +1248,7 @@
"admin_vr_field_role_label": "役割名",
"admin_vr_role_label_placeholder": "例: ブレンドシェイプ",
"admin_vr_field_model": "モデルファイル",
"admin_vr_dropzone": ".vrmまたは.fbxファイルを選択してアップロード(最大{max})",
"admin_vr_dropzone": ".vrmまたは.fbxファイルを選択するか、ここにドラッグしてください(最大{max})",
"admin_vr_model_hint": "3DビューアはVRM 0.xと1.0の両方に対応しています。FBXファイルはダウンロード用に提供できますが、ビューアには表示されません。",
"admin_vr_upload_progress": "{total}中{loaded}をアップロード済み",
"admin_vr_upload_replace": "差し替え",
Expand All @@ -1255,12 +1263,12 @@
"admin_vr_permission_placeholder": "例: Telegram DM 2026-08-01 — ダウンロード提供に必須",
"admin_vr_section_media": "ショーケースメディア",
"admin_vr_media_hint": "公開ページでポスターの下に表示されるスクリーンショットや短いクリップです。クリップには字幕を付けられないため、重要な内容を音声に頼らないでください。再生はミュートで始まりますが、訪問者は音声をオンにできます — クリップに記録されている人がいる場合は、その人の同意が必要です。",
"admin_vr_media_dropzone": "スクリーンショットや短い.webmクリップを追加(各最大{max})",
"admin_vr_media_dropzone": "スクリーンショットや短い.webmクリップを選択するか、ここにドラッグしてください(各最大{max})",
"admin_vr_media_kind_image": "画像",
"admin_vr_media_kind_video": "クリップ",
"admin_vr_media_remove": "メディア{position}を削除",
"admin_vr_media_upload_done": "メディアのアップロードが完了しました。",
"admin_vr_media_upload_issues": "メディアのアップロードが完了しましたが、エラーがあります — ドロップゾーンの下のメッセージを確認してください。",
"admin_vr_media_upload_issues": "メディアのアップロードは完了しましたが、エラーがありました。失敗したファイルにはそれぞれ理由が表示されています。",
"admin_vr_media_error_too_large": "このファイルは{max}を超えています。画像を小さくするか、クリップを短く低解像度にしてみてください。",
"admin_vr_media_error_bad_type": "対応していないファイル形式です。JPEG・PNG・GIF・WebP・AVIF、または.webmクリップをご利用ください。",
"admin_vr_media_error_failed": "アップロードに失敗しました。接続を確認してもう一度お試しください。",
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export default defineConfig({
{
name: 'upload',
testMatch: UPLOAD_SPEC,
// The five upload specs share one seeded dev server and an admin
// The upload tests share one seeded dev server and an admin
// session flow that flakes under parallel load — run them serially.
workers: 1,
use: { ...devices['Desktop Chrome'], baseURL: `http://localhost:${UPLOAD_PORT}` }
Expand Down
Loading
Loading