diff --git a/frontend/app/admin/SettingField.tsx b/frontend/app/admin/SettingField.tsx new file mode 100644 index 0000000..c0e40a8 --- /dev/null +++ b/frontend/app/admin/SettingField.tsx @@ -0,0 +1,72 @@ +'use client' + +export type AdminSetting = { key: string; value: string | null; isSet: boolean; source: string; sensitive: boolean } +type Option = { value: string; label: string } +type Props = { + setting: AdminSetting + label: string + value: string + help?: string + placeholder?: string + boolean?: boolean + numeric?: boolean + multiline?: boolean + options?: Option[] + optionsUnavailable?: boolean + onChange: (value: string) => void +} + +const SELECTS: Record = { + log_level: ['DEBUG', 'INFO', 'WARNING', 'ERROR'].map((value) => ({ value, label: value })), + issue_confirmation_contact_attempts: Array.from({ length: 11 }, (_, index) => ({ value: String(index), label: index === 0 ? 'None — close when fixed' : String(index) })), + issue_confirmation_interval_unit: ['days', 'weeks', 'months'].map((value) => ({ value, label: value[0].toUpperCase() + value.slice(1) })), + artwork_cache_mode: [{ value: 'remote', label: 'Load from the internet' }, { value: 'cache', label: 'Store locally' }], + site_banner_tone: ['info', 'warning', 'error', 'maintenance'].map((value) => ({ value, label: value[0].toUpperCase() + value.slice(1) })), + magent_notify_push_provider: ['ntfy', 'gotify', 'pushover', 'webhook', 'telegram', 'discord'].map((value) => ({ value, label: value })), + requests_data_source: [{ value: 'always_js', label: 'Read directly from Seerr' }, { value: 'prefer_cache', label: 'Use saved requests' }], +} + +export default function SettingField(props: Props) { + const { setting, label, value, help, placeholder, onChange } = props + const id = `setting-${setting.key}` + const options = props.options ?? SELECTS[setting.key] ?? (setting.key === 'log_http_client_level' || setting.key === 'log_background_sync_level' ? SELECTS.log_level : undefined) + const selectedOptions = options && value && !options.some((option) => option.value === value) + ? [{ value, label: `Current selection (${value})` }, ...options] : options + const isTime = setting.key === 'requests_full_sync_time' || setting.key === 'requests_cleanup_time' + const zeroAllowed = setting.key === 'log_file_backup_count' + const minimum = zeroAllowed ? 0 : 1 + const maximum = setting.key === 'issue_confirmation_interval_value' ? 365 : setting.key.endsWith('_port') ? 65535 : undefined + const aria = { id, name: setting.key, 'aria-describedby': help ? `${id}-help` : undefined } + + if (props.boolean) { + return ( +
+
{help &&

{help}

}
+ onChange(String(event.target.checked))} /> +
+ ) + } + + return ( +
+ + {props.optionsUnavailable ? ( + + ) : selectedOptions ? ( + + ) : props.multiline ? ( +