feat: share saves & states with other users#3569
Conversation
…ections - Introduced new API endpoints for updating visibility of saves and states. - Added `is_public` property to `SaveSchema` and `StateSchema`. - Created new models for user saves and states with visibility attributes. - Updated the `SaveDataTab` component to differentiate between "Mine" and "Community" sections. - Implemented visibility toggle functionality for user saves and states. - Enhanced localization files to include new strings for visibility actions.
…states - Introduced AssetList.vue for displaying a vertical list of saves with detailed information. - Added AssetStrip.vue for a horizontal strip of state tiles, supporting selection and management modes. - Created stories for AssetStrip to demonstrate various states and scenarios. - Enhanced RSliderBtnGroup to include a badge for displaying counts next to labels. - Updated EmulatorJS.vue to utilize the new AssetList and AssetStrip components, including badge counts for saves and states.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Test Results (mariadb) 1 files 1 suites 2m 26s ⏱️ Results for commit 91640c3. ♻️ This comment has been updated with latest results. |
☂️ Python Coverage
Overall Coverage
New FilesNo new covered files... Modified Files
|
Test Results (postgresql) 1 files 1 suites 2m 28s ⏱️ Results for commit 91640c3. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Pull request overview
Adds per-save/per-state public sharing (mirroring v2 screenshots/notes) and refactors the v2 UI so saves/states can be managed in “Mine” vs “Community” sections using shared list/strip components.
Changes:
- Backend: introduce
is_publicfor saves/states, add visibility toggle endpoints, and expose combinedall_user_saves/all_user_statesonDetailedRomSchema. - Frontend: update Save Data tab into Mine/Community, add visibility toggle actions, and regenerate OpenAPI types.
- UI primitives: add
badgesupport toRSliderBtnGroupand migrate AssetList/AssetStrip intocomponents/shared/.
Reviewed changes
Copilot reviewed 36 out of 45 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/v2/views/Player/EmulatorJS.vue | Switches to shared AssetList/AssetStrip and uses new badge field for tab counts. |
| frontend/src/v2/lib/primitives/RSliderBtnGroup/types.ts | Adds badge field to slider button items. |
| frontend/src/v2/lib/primitives/RSliderBtnGroup/RSliderBtnGroup.vue | Renders the new badge pill and adds styling. |
| frontend/src/v2/components/shared/AssetStrip.vue | Generalizes state/save strip into shared selectable/manage modes with owner chip + actions slot. |
| frontend/src/v2/components/shared/AssetStrip.stories.ts | Moves Storybook namespace from Player to Shared. |
| frontend/src/v2/components/shared/AssetList.vue | Generalizes save list into shared selectable/manage modes with owner chip + actions slot. |
| frontend/src/v2/components/shared/AssetList.stories.ts | Moves Storybook namespace from Player to Shared. |
| frontend/src/v2/components/Player/ResumePanel.stories.ts | Updates story imports to use shared AssetList/AssetStrip. |
| frontend/src/v2/components/GameDetails/SaveDataTab.vue | Splits saves/states into Mine vs Community, adds visibility toggles, and uses shared components. |
| frontend/src/services/api/state.ts | Adds setStateVisibility API call. |
| frontend/src/services/api/save.ts | Adds setSaveVisibility API call. |
| frontend/src/locales/zh_TW/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/zh_CN/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/ru_RU/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/ro_RO/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/pt_BR/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/pl_PL/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/ko_KR/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/ja_JP/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/it_IT/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/hu_HU/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/fr_FR/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/es_ES/rom.json | Adds new Mine/Community section labels + toggle-visibility error key (Spanish translated). |
| frontend/src/locales/en_US/rom.json | Adds new Mine/Community section labels + toggle-visibility error key (source locale). |
| frontend/src/locales/en_GB/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/de_DE/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/cs_CZ/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/locales/bg_BG/rom.json | Adds new Mine/Community section labels + toggle-visibility error key. |
| frontend/src/generated/models/UserStateSchema.ts | Adds generated “community” state schema enriched with owner info. |
| frontend/src/generated/models/UserSaveSchema.ts | Adds generated “community” save schema enriched with owner info. |
| frontend/src/generated/models/StateSchema.ts | Adds is_public field to generated state schema. |
| frontend/src/generated/models/SaveSchema.ts | Adds is_public field to generated save schema. |
| frontend/src/generated/models/LogEntrySchema.ts | Adds generated log entry schema (from OpenAPI regen). |
| frontend/src/generated/models/DetailedRomSchema.ts | Adds all_user_saves/all_user_states fields to generated detailed ROM schema. |
| frontend/src/generated/models/Body_update_state_visibility_api_states__id__visibility_put.ts | Adds generated request body type for state visibility endpoint. |
| frontend/src/generated/models/Body_update_save_visibility_api_saves__id__visibility_put.ts | Adds generated request body type for save visibility endpoint. |
| frontend/src/generated/index.ts | Exports newly generated models/types. |
| backend/models/assets.py | Adds is_public columns to Save and State models. |
| backend/handler/database/states_handler.py | Adds get_state_by_id and get_rom_shared_states queries. |
| backend/handler/database/saves_handler.py | Adds get_save_by_id and get_rom_shared_saves queries. |
| backend/endpoints/states.py | Adds owner-only PUT /states/{id}/visibility. |
| backend/endpoints/saves.py | Allows public download for non-owners and adds PUT /saves/{id}/visibility. |
| backend/endpoints/responses/rom.py | Populates all_user_saves/all_user_states on detailed ROM responses. |
| backend/endpoints/responses/assets.py | Adds is_public to Save/State schemas and introduces UserSaveSchema/UserStateSchema. |
| backend/alembic/versions/0087_save_state_visibility.py | Migration to add is_public + indexes on saves/states tables. |
Files not reviewed (9)
- frontend/src/generated/index.ts: Generated file
- frontend/src/generated/models/Body_update_save_visibility_api_saves__id__visibility_put.ts: Generated file
- frontend/src/generated/models/Body_update_state_visibility_api_states__id__visibility_put.ts: Generated file
- frontend/src/generated/models/DetailedRomSchema.ts: Generated file
- frontend/src/generated/models/LogEntrySchema.ts: Generated file
- frontend/src/generated/models/SaveSchema.ts: Generated file
- frontend/src/generated/models/StateSchema.ts: Generated file
- frontend/src/generated/models/UserSaveSchema.ts: Generated file
- frontend/src/generated/models/UserStateSchema.ts: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Notes already paints the lock button primary when private and muted when public; bring screenshots and the new saves/states toggles to the same binding so the three visibility surfaces read consistently. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* i18n `rom.cant-toggle-visibility` is interpolated with `{error}` in
SaveDataTab but the strings dropped the placeholder, hiding the
backend error detail from the snackbar. Add `{error}` to every locale
(en_US source + es_ES translated, others English placeholder).
* `RSliderBtnGroup` badge visibility check did not handle the string
`"0"` / `""` cases allowed by the `string | number | null` type.
Extract a `showBadge` helper and use it in both the router-link and
RBtn branches.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Description
Explain the changes or enhancements you are proposing with this pull request.
Brings the share-with-other-users behavior that v2 notes and screenshots already have to saves and states — owners flip a per-item public/private toggle and everyone else sees the public items in a read-only Community section alongside their own Mine section. Saves/states are
RomAssets like screenshots, so the implementation reuses the exact same end-to-end pattern instead of inventing anything new.The Save data subtab is also unified with the Play view by extracting
AssetList(saves) andAssetStrip(states) intocomponents/shared/and generalising them so both contexts render the same visuals — saves as an info-dense list, states as 16:9 cards. A small Play-view nit was bundled in: the Saves/States slider tab count is now a pill instead of a· Ntext concatenation.Backend (sharing)
Save.is_public/State.is_publiccolumns + migration0087_save_state_visibility.UserSaveSchema/UserStateSchemaenriched withusername/user_avatar_path/user_updated_at(mirrorsUserScreenshotSchema).get_rom_shared_{saves,states}(rom_id, user_id, public_only=False)→ own (public + private) ∪ others' public, mirroringget_rom_gallery_screenshots.PUT /saves/{id}/visibilityandPUT /states/{id}/visibility(owner-only). Save download relaxed to allow public items from other users; device-sync side effects stay gated to the owner.DetailedRomSchemagainsall_user_saves/all_user_states, populated alongsideall_user_screenshots.Frontend (v2)
saveApi.setSaveVisibility/stateApi.setStateVisibility.SaveDataTabrestructured into Mine / Community sections per subtab: own items show toggle (mdi-lock/mdi-lock-open-variant) + download + delete; community items show author chip + download.AssetListandAssetStripmoved tocomponents/shared/and generalised withselectable/selectedId/showOwner/scrollable(list) /wrap(strip) +#actionsslot. EmulatorJS still uses them in select mode; SaveDataTab uses them in manage mode.SliderBtnGroupItem.badgefield; RSliderBtnGroup renders it as an inline count pill, replacing the previous${label} · ${count}string.saves-section-mine/saves-section-community/states-section-mine/states-section-community/cant-toggle-visibility) added to every locale dir;en_USsource of truth + Spanish translated, rest copy English as placeholder per CLAUDE.md §VII.12.Checklist
Please check all that apply.
Screenshots (if applicable)