feat(early-access): implement EA filtering and UI improvements

Add Early Access version support with filtering and improved UI:

Backend:
- Add is_early_access and early_access_ends_at fields to ModelVersionRecord
- Implement two-phase EA detection (bulk API + single API enrichment)
- Add hide_early_access_updates setting to filter EA updates
- Update has_update() and has_updates_bulk() to respect EA filter setting
- Add _enrich_early_access_details() for precise EA time fetching
- Fix setting propagation through base_model_service and model_update_service

Frontend:
- Add smart relative time display for EA (in Xh, in Xd, or date)
- Replace EA label with clock icon in metadata (fa-clock)
- Show Download button with bolt icon for EA versions (fa-bolt)
- Change EA badge color to #F59F00 (CivitAI Buzz theme)
- Fix toggle UI for hide_early_access_updates setting
- Add translation keys for EA time formatting

Tests:
- Update all tests to pass with new EA functionality
- Add test coverage for EA filtering logic

Closes #815
This commit is contained in:
Will Miao
2026-02-20 10:32:51 +08:00
parent e8b37365a6
commit 67869f19ff
22 changed files with 506 additions and 31 deletions

View File

@@ -426,6 +426,10 @@
"any": "Jede verfügbare Aktualisierung markieren"
}
},
"hideEarlyAccessUpdates": {
"label": "[TODO: Translate] Hide Early Access Updates",
"help": "[TODO: Translate] When enabled, models with only early access updates will not show 'Update available' badge"
},
"misc": {
"includeTriggerWords": "Trigger Words in LoRA-Syntax einschließen",
"includeTriggerWordsHelp": "Trainierte Trigger Words beim Kopieren der LoRA-Syntax in die Zwischenablage einschließen"
@@ -1031,12 +1035,19 @@
},
"labels": {
"unnamed": "Unbenannte Version",
"noDetails": "Keine zusätzlichen Details"
"noDetails": "Keine zusätzlichen Details",
"earlyAccess": "[TODO: Translate] Early Access"
},
"eaTime": {
"endingSoon": "[TODO: Translate] ending soon",
"hours": "[TODO: Translate] in {count}h",
"days": "[TODO: Translate] in {count}d"
},
"badges": {
"current": "Aktuelle Version",
"inLibrary": "In der Bibliothek",
"newer": "Neuere Version",
"earlyAccess": "[TODO: Translate] Early Access",
"ignored": "Ignoriert"
},
"actions": {
@@ -1044,6 +1055,7 @@
"delete": "Löschen",
"ignore": "Ignorieren",
"unignore": "Ignorierung aufheben",
"earlyAccessTooltip": "[TODO: Translate] Requires early access purchase",
"resumeModelUpdates": "Aktualisierungen für dieses Modell fortsetzen",
"ignoreModelUpdates": "Aktualisierungen für dieses Modell ignorieren",
"viewLocalVersions": "Alle lokalen Versionen anzeigen",