- Consolidate PAIR_CODE_TTL_SECONDS to single source in utils
- Add min_length=1 validation on scopes field
- Remove unused pairExpiresIn ref, rawToken ref, dead emitter listener
- Fix formattedCode fallback to return normalized value
- Spread allPlatforms before sorting to avoid mutating Pinia store
- Move _METADATA_SOURCE_COLUMNS to module level
- Add optional chain on sourceInfo v-img src
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use i18n key for "games" label instead of hardcoded "Roms"
- Remove min-width on size bar fill so zero-size platforms show no bar
- Align Python TypedDict keys to str to match JSON wire format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add rom count as detail table row aligned with metadata/region chips
- Use standard chip style for fs_slug matching PlatformListItem
- Size and percentage on two lines for readability
- Adjust platform icon vertical alignment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JSON serializes object keys as strings, so explicitly convert platform
IDs to strings when accessing metadataCoverage and regionBreakdown maps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reuse rom.metadata and platform.region instead of adding new keys.
Remove orphaned platforms-size key from all 16 locale files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Derive metadata source columns from Rom model instead of hardcoded list
- Replace getOrderedCoverage() function calls with a computed map to avoid
redundant sorting on each render
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of emitting scan:scanning_firmware once per firmware file, emit
a single event per platform after all firmware is processed, carrying
only the firmware_count. Frontend tracks firmware_count (int) on each
ScanningPlatform instead of a full firmware list.
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
Enhances the server stats page with two new per-platform statistics:
- Metadata coverage: shows which sources matched ROMs (ordered by user's scan priority config)
- Region breakdown: shows ROM counts per region with flag emojis
Backend adds two new efficient queries (single GROUP BY for metadata, Python-side aggregation for regions).
Frontend redesigns platform cards with a tabular detail layout, size bar visualization, and expandable region chips.
> This PR was developed with AI assistance (Claude Code) per CONTRIBUTING.md disclosure requirements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
During a scan with large collections, the scan page becomes slow or
unresponsive. The watch on scanningPlatforms with { deep: true } was
firing on every ROM addition, causing Vue to deeply traverse all nested
platform and ROM data each time.
The watch's only job is deciding which panels are open. A panel should
open when a platform first receives ROMs — after that, its open/closed
state doesn't need to change regardless of how many more ROMs arrive.
Replace with a computed that maps each platform to a boolean
(roms.length > 0), so the watch only fires on that one meaningful
transition per platform. The ROM list inside each panel continues to
update reactively as normal — this change only affects the panel
open/close logic.
Note: This PR was written with AI assistance (Claude Code).