Per-platform metadata coverage and region breakdown to server stats#3110
Conversation
…er stats 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 <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Greptile SummaryThis PR adds per-platform metadata coverage and region breakdown statistics to the server stats page, alongside a visual redesign of the platform cards (tabular detail layout, size bar, expandable region chips). The backend adds two efficient queries — a single Key changes and observations:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Browser
participant ServerStats.vue
participant PlatformsStats.vue
participant StatsAPI as GET /stats
participant DBStatsHandler
participant DB as Database (Rom table)
Browser->>ServerStats.vue: onBeforeMount
ServerStats.vue->>StatsAPI: api.get("/stats")
StatsAPI->>DBStatsHandler: get_metadata_coverage_by_platform()
DBStatsHandler->>DB: SELECT platform_id, COUNT(igdb_id), COUNT(ss_id), ... GROUP BY platform_id
DB-->>DBStatsHandler: rows[]
DBStatsHandler-->>StatsAPI: dict[int, list[MetadataCoverageItem]]
StatsAPI->>DBStatsHandler: get_region_breakdown_by_platform()
DBStatsHandler->>DB: SELECT platform_id, regions WHERE regions IS NOT NULL
DB-->>DBStatsHandler: rows[]
Note over DBStatsHandler: Python-side aggregation per region per platform
DBStatsHandler-->>StatsAPI: dict[int, list[RegionBreakdownItem]]
StatsAPI-->>ServerStats.vue: StatsReturn (JSON, int keys serialized as strings)
ServerStats.vue->>PlatformsStats.vue: :metadata-coverage="stats.METADATA_COVERAGE"
ServerStats.vue->>PlatformsStats.vue: :region-breakdown="stats.REGION_BREAKDOWN"
Note over PlatformsStats.vue: orderedCoverageByPlatform computed<br/>sorts by SCAN_METADATA_PRIORITY
PlatformsStats.vue-->>Browser: Render platform cards with coverage chips + region chips
|
frontend/src/components/Settings/ServerStats/PlatformsStats.vue
Outdated
Show resolved
Hide resolved
- 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 <[email protected]>
Fallback locale (en_US) covers the two new keys for other languages. Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
i18n should be fixed 🤞 |
frontend/src/components/Settings/ServerStats/PlatformsStats.vue
Outdated
Show resolved
Hide resolved
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 <[email protected]>
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 <[email protected]>
frontend/src/components/Settings/ServerStats/PlatformsStats.vue
Outdated
Show resolved
Hide resolved
- 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 <[email protected]>
frontend/src/components/Settings/ServerStats/PlatformsStats.vue
Outdated
Show resolved
Hide resolved
frontend/src/components/Settings/ServerStats/PlatformsStats.vue
Outdated
Show resolved
Hide resolved
- 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 <[email protected]>
frontend/src/components/Settings/ServerStats/PlatformsStats.vue
Outdated
Show resolved
Hide resolved
- 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 <[email protected]>
Pydantic enforces response types before JSON serialization, so the Python dict must use int keys to match the actual data. JSON handles the int-to-string conversion automatically. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Summary
Spent some time working on the stats page. Adds two interesting metrics that didn't take any heavy lifting on the backend. And did some additional visual design for the frontend.
GROUP BYfor metadata sources, Python-side aggregation for regions (DB-dialect agnostic)SCAN_METADATA_PRIORITYconfigBefore / After
Test plan
SCAN_METADATA_PRIORITY🤖 Generated with Claude Code