Clarify request sync settings (build 271261159)

This commit is contained in:
2026-01-27 12:00:32 +13:00
parent 7863658a19
commit 9e8d22ba85
3 changed files with 51 additions and 27 deletions

View File

@@ -1 +1 @@
271261149 271261159

View File

@@ -28,7 +28,7 @@ const SECTION_LABELS: Record<string, string> = {
prowlarr: 'Prowlarr', prowlarr: 'Prowlarr',
qbittorrent: 'qBittorrent', qbittorrent: 'qBittorrent',
log: 'Activity log', log: 'Activity log',
requests: 'Request syncing', requests: 'Request sync',
site: 'Site', site: 'Site',
} }
@@ -45,7 +45,7 @@ const SECTION_DESCRIPTIONS: Record<string, string> = {
radarr: 'Movie automation settings.', radarr: 'Movie automation settings.',
prowlarr: 'Indexer search settings.', prowlarr: 'Indexer search settings.',
qbittorrent: 'Downloader connection settings.', qbittorrent: 'Downloader connection settings.',
requests: 'Sync and refresh cadence for requests.', requests: 'Control how often requests are refreshed and cleaned up.',
log: 'Activity log for troubleshooting.', log: 'Activity log for troubleshooting.',
site: 'Sitewide banner, version, and changelog details.', site: 'Sitewide banner, version, and changelog details.',
} }
@@ -73,13 +73,13 @@ const labelFromKey = (key: string) =>
.replace('quality profile id', 'Quality profile ID') .replace('quality profile id', 'Quality profile ID')
.replace('root folder', 'Root folder') .replace('root folder', 'Root folder')
.replace('qbittorrent', 'qBittorrent') .replace('qbittorrent', 'qBittorrent')
.replace('requests sync ttl minutes', 'Refresh saved requests if older than (minutes)') .replace('requests sync ttl minutes', 'Saved request refresh TTL (minutes)')
.replace('requests poll interval seconds', 'Background refresh check (seconds)') .replace('requests poll interval seconds', 'Full refresh check interval (seconds)')
.replace('requests delta sync interval minutes', 'Check for new or updated requests every (minutes)') .replace('requests delta sync interval minutes', 'Delta sync interval (minutes)')
.replace('requests full sync time', 'Full refresh time (24h)') .replace('requests full sync time', 'Daily full refresh time (24h)')
.replace('requests cleanup time', 'Clean up old history time (24h)') .replace('requests cleanup time', 'Daily history cleanup time (24h)')
.replace('requests cleanup days', 'Remove history older than (days)') .replace('requests cleanup days', 'History retention window (days)')
.replace('requests data source', 'Where requests are loaded from') .replace('requests data source', 'Request source (cache vs Jellyseerr)')
.replace('jellyfin public url', 'Jellyfin public URL') .replace('jellyfin public url', 'Jellyfin public URL')
.replace('jellyfin sync to arr', 'Sync Jellyfin to Sonarr/Radarr') .replace('jellyfin sync to arr', 'Sync Jellyfin to Sonarr/Radarr')
.replace('artwork cache mode', 'Artwork cache mode') .replace('artwork cache mode', 'Artwork cache mode')
@@ -277,6 +277,22 @@ export default function SettingsPage({ section }: SettingsPageProps) {
const cacheSettingKeys = new Set(['requests_sync_ttl_minutes', 'requests_data_source']) const cacheSettingKeys = new Set(['requests_sync_ttl_minutes', 'requests_data_source'])
const artworkSettingKeys = new Set(['artwork_cache_mode']) const artworkSettingKeys = new Set(['artwork_cache_mode'])
const hiddenSettingKeys = new Set([...cacheSettingKeys, ...artworkSettingKeys]) const hiddenSettingKeys = new Set([...cacheSettingKeys, ...artworkSettingKeys])
const requestSettingOrder = [
'requests_poll_interval_seconds',
'requests_delta_sync_interval_minutes',
'requests_full_sync_time',
'requests_cleanup_time',
'requests_cleanup_days',
]
const sortByOrder = (items: AdminSetting[], order: string[]) => {
const position = new Map(order.map((key, index) => [key, index]))
return [...items].sort((a, b) => {
const aIndex = position.get(a.key) ?? Number.POSITIVE_INFINITY
const bIndex = position.get(b.key) ?? Number.POSITIVE_INFINITY
if (aIndex !== bIndex) return aIndex - bIndex
return a.key.localeCompare(b.key)
})
}
const cacheSettings = settings.filter((setting) => cacheSettingKeys.has(setting.key)) const cacheSettings = settings.filter((setting) => cacheSettingKeys.has(setting.key))
const artworkSettings = settings.filter((setting) => artworkSettingKeys.has(setting.key)) const artworkSettings = settings.filter((setting) => artworkSettingKeys.has(setting.key))
const settingsSections = isCacheSection const settingsSections = isCacheSection
@@ -287,12 +303,17 @@ export default function SettingsPage({ section }: SettingsPageProps) {
: visibleSections.map((sectionKey) => ({ : visibleSections.map((sectionKey) => ({
key: sectionKey, key: sectionKey,
title: SECTION_LABELS[sectionKey] ?? sectionKey, title: SECTION_LABELS[sectionKey] ?? sectionKey,
items: items: (() => {
sectionKey === 'requests' || sectionKey === 'artwork' const sectionItems = groupedSettings[sectionKey] ?? []
? (groupedSettings[sectionKey] ?? []).filter( const filtered =
(setting) => !hiddenSettingKeys.has(setting.key) sectionKey === 'requests' || sectionKey === 'artwork'
) ? sectionItems.filter((setting) => !hiddenSettingKeys.has(setting.key))
: groupedSettings[sectionKey] ?? [], : sectionItems
if (sectionKey === 'requests') {
return sortByOrder(filtered, requestSettingOrder)
}
return filtered
})(),
})) }))
const showLogs = section === 'logs' const showLogs = section === 'logs'
const showMaintenance = section === 'maintenance' const showMaintenance = section === 'maintenance'
@@ -332,11 +353,11 @@ export default function SettingsPage({ section }: SettingsPageProps) {
qbittorrent_password: 'qBittorrent login password.', qbittorrent_password: 'qBittorrent login password.',
requests_sync_ttl_minutes: 'How long saved requests stay fresh before a refresh is needed.', requests_sync_ttl_minutes: 'How long saved requests stay fresh before a refresh is needed.',
requests_poll_interval_seconds: requests_poll_interval_seconds:
'How often Magent wakes up to check if the cache is stale and needs a full refresh.', 'How often Magent checks if a full refresh should run.',
requests_delta_sync_interval_minutes: requests_delta_sync_interval_minutes:
'How often we actively poll for new or updated requests (delta sync).', 'How often we poll for new or updated requests.',
requests_full_sync_time: 'Daily time to refresh the full request list.', requests_full_sync_time: 'Daily time to rebuild the full request cache.',
requests_cleanup_time: 'Daily time to trim old history.', requests_cleanup_time: 'Daily time to trim old request history.',
requests_cleanup_days: 'History older than this is removed during cleanup.', requests_cleanup_days: 'History older than this is removed during cleanup.',
requests_data_source: requests_data_source:
'Pick where Magent should read requests from. Cache-only avoids Jellyseerr lookups on reads.', 'Pick where Magent should read requests from. Cache-only avoids Jellyseerr lookups on reads.',
@@ -782,7 +803,9 @@ export default function SettingsPage({ section }: SettingsPageProps) {
.map((sectionGroup) => ( .map((sectionGroup) => (
<section key={sectionGroup.key} className="admin-section"> <section key={sectionGroup.key} className="admin-section">
<div className="section-header"> <div className="section-header">
<h2>{sectionGroup.key === 'requests' ? 'Sync controls' : sectionGroup.title}</h2> <h2>
{sectionGroup.key === 'requests' ? 'Request sync controls' : sectionGroup.title}
</h2>
{sectionGroup.key === 'sonarr' && ( {sectionGroup.key === 'sonarr' && (
<button type="button" onClick={() => loadOptions('sonarr')}> <button type="button" onClick={() => loadOptions('sonarr')}>
Refresh Sonarr options Refresh Sonarr options
@@ -816,14 +839,15 @@ export default function SettingsPage({ section }: SettingsPageProps) {
<div className="sync-actions-block"> <div className="sync-actions-block">
<div className="sync-actions"> <div className="sync-actions">
<button type="button" onClick={syncRequests}> <button type="button" onClick={syncRequests}>
Full refresh (all requests) Run full refresh (rebuild cache)
</button> </button>
<button type="button" className="ghost-button" onClick={syncRequestsDelta}> <button type="button" className="ghost-button" onClick={syncRequestsDelta}>
Quick refresh (delta changes) Run delta sync (recent changes)
</button> </button>
</div> </div>
<div className="meta sync-note"> <div className="meta sync-note">
Full refresh reloads the entire list. Quick refresh only checks recent changes. Full refresh rebuilds the entire cache. Delta sync only checks new or updated
requests.
</div> </div>
</div> </div>
)} )}
@@ -877,8 +901,8 @@ export default function SettingsPage({ section }: SettingsPageProps) {
)} )}
{showRequestsExtras && sectionGroup.key === 'requests' && ( {showRequestsExtras && sectionGroup.key === 'requests' && (
<div className="status-banner"> <div className="status-banner">
Background refresh checks only decide when to run a full refresh. The delta sync Full refresh checks only decide when to run a full refresh. The delta sync interval
interval actively polls for new or updated requests. polls for new or updated requests.
</div> </div>
)} )}
{showArtworkExtras && sectionGroup.key === 'artwork' && artworkPrefetch && ( {showArtworkExtras && sectionGroup.key === 'artwork' && artworkPrefetch && (

View File

@@ -17,7 +17,7 @@ const NAV_GROUPS = [
{ {
title: 'Requests', title: 'Requests',
items: [ items: [
{ href: '/admin/requests', label: 'Request syncing' }, { href: '/admin/requests', label: 'Request sync' },
{ href: '/admin/cache', label: 'Cache Control' }, { href: '/admin/cache', label: 'Cache Control' },
], ],
}, },