Compare commits
2 Commits
release-1.
...
dev-1.2
| Author | SHA1 | Date | |
|---|---|---|---|
| d045dd0b07 | |||
| 138069590b |
@@ -1 +1 @@
|
|||||||
271261539
|
0202261541
|
||||||
|
|||||||
53
Dockerfile
Normal file
53
Dockerfile
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
FROM node:20-slim AS frontend-builder
|
||||||
|
|
||||||
|
WORKDIR /frontend
|
||||||
|
|
||||||
|
ENV NODE_ENV=production \
|
||||||
|
BACKEND_INTERNAL_URL=http://127.0.0.1:8000 \
|
||||||
|
NEXT_PUBLIC_API_BASE=/api
|
||||||
|
|
||||||
|
COPY frontend/package.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY frontend/app ./app
|
||||||
|
COPY frontend/public ./public
|
||||||
|
COPY frontend/next-env.d.ts ./next-env.d.ts
|
||||||
|
COPY frontend/next.config.js ./next.config.js
|
||||||
|
COPY frontend/tsconfig.json ./tsconfig.json
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends curl gnupg supervisor \
|
||||||
|
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||||
|
&& apt-get install -y --no-install-recommends nodejs \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY backend/requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY backend/app ./app
|
||||||
|
COPY data/branding /app/data/branding
|
||||||
|
|
||||||
|
COPY --from=frontend-builder /frontend/.next /app/frontend/.next
|
||||||
|
COPY --from=frontend-builder /frontend/public /app/frontend/public
|
||||||
|
COPY --from=frontend-builder /frontend/node_modules /app/frontend/node_modules
|
||||||
|
COPY --from=frontend-builder /frontend/package.json /app/frontend/package.json
|
||||||
|
COPY --from=frontend-builder /frontend/next.config.js /app/frontend/next.config.js
|
||||||
|
COPY --from=frontend-builder /frontend/next-env.d.ts /app/frontend/next-env.d.ts
|
||||||
|
COPY --from=frontend-builder /frontend/tsconfig.json /app/frontend/tsconfig.json
|
||||||
|
|
||||||
|
COPY docker/supervisord.conf /etc/supervisor/conf.d/magent.conf
|
||||||
|
|
||||||
|
EXPOSE 3000 8000
|
||||||
|
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/magent.conf"]
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
BUILD_NUMBER = "2901262244"
|
BUILD_NUMBER = "0202261541"
|
||||||
CHANGELOG = '2026-01-22\\n- Initial commit\\n- Ignore build artifacts\\n- Update README\\n- Update README with Docker-first guide\\n\\n2026-01-23\\n- Fix cache titles via Jellyseerr media lookup\\n- Split search actions and improve download options\\n- Fallback manual grab to qBittorrent\\n- Hide header actions when signed out\\n- Add feedback form and webhook\\n- Fix cache titles and move feedback link\\n- Show available status on landing when in Jellyfin\\n- Add default branding assets when missing\\n- Use bundled branding assets\\n- Remove password fields from users page\\n- Add Docker Hub compose override\\n- Fix backend Dockerfile paths for root context\\n- Copy public assets into frontend image\\n- Use backend branding assets for logo and favicon\\n\\n2026-01-24\\n- Route grabs through Sonarr/Radarr only\\n- Document fix buttons in how-it-works\\n- Clarify how-it-works steps and fixes\\n- Map Prowlarr releases to Arr indexers for manual grab\\n- Improve request handling and qBittorrent categories\\n\\n2026-01-25\\n- Add site banner, build number, and changelog\\n- Automate build number tagging and sync\\n- Improve mobile header layout\\n- Move account actions into avatar menu\\n- Add user stats and activity tracking\\n- Add Jellyfin login cache and admin-only stats\\n- Tidy request sync controls\\n- Seed branding logo from bundled assets\\n- Serve bundled branding assets by default\\n- Harden request cache titles and cache-only reads\\n- Build 2501262041\\n\\n2026-01-26\\n- Fix cache title hydration\\n- Fix sync progress bar animation\\n\\n2026-01-27\\n- Add cache control artwork stats\\n- Improve cache stats performance (build 271261145)\\n- Fix backend cache stats import (build 271261149)\\n- Clarify request sync settings (build 271261159)\\n- Bump build number to 271261202\\n- Fix request titles in snapshots (build 271261219)\\n- Fix snapshot title fallback (build 271261228)\\n- Add cache load spinner (build 271261238)\\n- Bump build number (process 2) 271261322\\n- Add service test buttons (build 271261335)\\n- Fallback to TMDB when artwork cache fails (build 271261524)\\n- Hydrate missing artwork from Jellyseerr (build 271261539)\\n\\n2026-01-29\\n- release: 2901262036\\n- release: 2901262044\\n- release: 2901262102\\n- Hardcode build number in backend\\n- Bake build number and changelog\\n- Update full changelog\\n- Tidy full changelog\\n- Build 2901262240: cache users'
|
CHANGELOG = '2026-01-22\\n- Initial commit\\n- Ignore build artifacts\\n- Update README\\n- Update README with Docker-first guide\\n\\n2026-01-23\\n- Fix cache titles via Jellyseerr media lookup\\n- Split search actions and improve download options\\n- Fallback manual grab to qBittorrent\\n- Hide header actions when signed out\\n- Add feedback form and webhook\\n- Fix cache titles and move feedback link\\n- Show available status on landing when in Jellyfin\\n- Add default branding assets when missing\\n- Use bundled branding assets\\n- Remove password fields from users page\\n- Add Docker Hub compose override\\n- Fix backend Dockerfile paths for root context\\n- Copy public assets into frontend image\\n- Use backend branding assets for logo and favicon\\n\\n2026-01-24\\n- Route grabs through Sonarr/Radarr only\\n- Document fix buttons in how-it-works\\n- Clarify how-it-works steps and fixes\\n- Map Prowlarr releases to Arr indexers for manual grab\\n- Improve request handling and qBittorrent categories\\n\\n2026-01-25\\n- Add site banner, build number, and changelog\\n- Automate build number tagging and sync\\n- Improve mobile header layout\\n- Move account actions into avatar menu\\n- Add user stats and activity tracking\\n- Add Jellyfin login cache and admin-only stats\\n- Tidy request sync controls\\n- Seed branding logo from bundled assets\\n- Serve bundled branding assets by default\\n- Harden request cache titles and cache-only reads\\n- Build 2501262041\\n\\n2026-01-26\\n- Fix cache title hydration\\n- Fix sync progress bar animation\\n\\n2026-01-27\\n- Add cache control artwork stats\\n- Improve cache stats performance (build 271261145)\\n- Fix backend cache stats import (build 271261149)\\n- Clarify request sync settings (build 271261159)\\n- Bump build number to 271261202\\n- Fix request titles in snapshots (build 271261219)\\n- Fix snapshot title fallback (build 271261228)\\n- Add cache load spinner (build 271261238)\\n- Bump build number (process 2) 271261322\\n- Add service test buttons (build 271261335)\\n- Fallback to TMDB when artwork cache fails (build 271261524)\\n- Hydrate missing artwork from Jellyseerr (build 271261539)\\n\\n2026-01-29\\n- release: 2901262036\\n- release: 2901262044\\n- release: 2901262102\\n- Hardcode build number in backend\\n- Bake build number and changelog\\n- Update full changelog\\n- Tidy full changelog\\n- Build 2901262240: cache users\n\n2026-01-30\n- Merge backend and frontend into one container'
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
import ipaddress
|
||||||
import os
|
import os
|
||||||
|
from urllib.parse import urlparse, urlunparse
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
|
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
|
||||||
|
|
||||||
@@ -64,6 +66,16 @@ SENSITIVE_KEYS = {
|
|||||||
"qbittorrent_password",
|
"qbittorrent_password",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
URL_SETTING_KEYS = {
|
||||||
|
"jellyseerr_base_url",
|
||||||
|
"jellyfin_base_url",
|
||||||
|
"jellyfin_public_url",
|
||||||
|
"sonarr_base_url",
|
||||||
|
"radarr_base_url",
|
||||||
|
"prowlarr_base_url",
|
||||||
|
"qbittorrent_base_url",
|
||||||
|
}
|
||||||
|
|
||||||
SETTING_KEYS: List[str] = [
|
SETTING_KEYS: List[str] = [
|
||||||
"jellyseerr_base_url",
|
"jellyseerr_base_url",
|
||||||
"jellyseerr_api_key",
|
"jellyseerr_api_key",
|
||||||
@@ -107,6 +119,49 @@ def _normalize_username(value: str) -> str:
|
|||||||
normalized = normalized.split("@", 1)[0]
|
normalized = normalized.split("@", 1)[0]
|
||||||
return normalized
|
return normalized
|
||||||
|
|
||||||
|
|
||||||
|
def _is_ip_host(host: str) -> bool:
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(host)
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_service_url(value: str) -> str:
|
||||||
|
raw = value.strip()
|
||||||
|
if not raw:
|
||||||
|
raise ValueError("URL cannot be empty.")
|
||||||
|
|
||||||
|
candidate = raw
|
||||||
|
if "://" not in candidate:
|
||||||
|
authority = candidate.split("/", 1)[0].strip()
|
||||||
|
if authority.startswith("["):
|
||||||
|
closing = authority.find("]")
|
||||||
|
host = authority[1:closing] if closing > 0 else authority.strip("[]")
|
||||||
|
else:
|
||||||
|
host = authority.split(":", 1)[0]
|
||||||
|
host = host.strip().lower()
|
||||||
|
default_scheme = "http" if host in {"localhost"} or _is_ip_host(host) or "." not in host else "https"
|
||||||
|
candidate = f"{default_scheme}://{candidate}"
|
||||||
|
|
||||||
|
parsed = urlparse(candidate)
|
||||||
|
if parsed.scheme not in {"http", "https"}:
|
||||||
|
raise ValueError("URL must use http:// or https://.")
|
||||||
|
if not parsed.netloc:
|
||||||
|
raise ValueError("URL must include a host.")
|
||||||
|
if parsed.query or parsed.fragment:
|
||||||
|
raise ValueError("URL must not include query params or fragments.")
|
||||||
|
if not parsed.hostname:
|
||||||
|
raise ValueError("URL must include a valid host.")
|
||||||
|
|
||||||
|
normalized_path = parsed.path.rstrip("/")
|
||||||
|
normalized = parsed._replace(path=normalized_path, params="", query="", fragment="")
|
||||||
|
result = urlunparse(normalized).rstrip("/")
|
||||||
|
if not result:
|
||||||
|
raise ValueError("URL is invalid.")
|
||||||
|
return result
|
||||||
|
|
||||||
def _normalize_root_folders(folders: Any) -> List[Dict[str, Any]]:
|
def _normalize_root_folders(folders: Any) -> List[Dict[str, Any]]:
|
||||||
if not isinstance(folders, list):
|
if not isinstance(folders, list):
|
||||||
return []
|
return []
|
||||||
@@ -203,7 +258,14 @@ async def update_settings(payload: Dict[str, Any]) -> Dict[str, Any]:
|
|||||||
delete_setting(key)
|
delete_setting(key)
|
||||||
updates += 1
|
updates += 1
|
||||||
continue
|
continue
|
||||||
set_setting(key, str(value))
|
value_to_store = str(value).strip() if isinstance(value, str) else str(value)
|
||||||
|
if key in URL_SETTING_KEYS and value_to_store:
|
||||||
|
try:
|
||||||
|
value_to_store = _normalize_service_url(value_to_store)
|
||||||
|
except ValueError as exc:
|
||||||
|
friendly_key = key.replace("_", " ")
|
||||||
|
raise HTTPException(status_code=400, detail=f"{friendly_key}: {exc}") from exc
|
||||||
|
set_setting(key, value_to_store)
|
||||||
updates += 1
|
updates += 1
|
||||||
if key in {"log_level", "log_file"}:
|
if key in {"log_level", "log_file"}:
|
||||||
touched_logging = True
|
touched_logging = True
|
||||||
|
|||||||
@@ -1,19 +1,10 @@
|
|||||||
services:
|
services:
|
||||||
backend:
|
magent:
|
||||||
image: rephl3xnz/magent-backend:latest
|
image: rephl3xnz/magent:latest
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env
|
- ./.env
|
||||||
ports:
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
|
|
||||||
frontend:
|
|
||||||
image: rephl3xnz/magent-frontend:latest
|
|
||||||
environment:
|
|
||||||
- NEXT_PUBLIC_API_BASE=/api
|
|
||||||
- BACKEND_INTERNAL_URL=http://backend:8000
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
|
|||||||
@@ -1,25 +1,12 @@
|
|||||||
services:
|
services:
|
||||||
backend:
|
magent:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: backend/Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
|
||||||
BUILD_NUMBER: ${BUILD_NUMBER}
|
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env
|
- ./.env
|
||||||
ports:
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: ./frontend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
environment:
|
|
||||||
- NEXT_PUBLIC_API_BASE=/api
|
|
||||||
- BACKEND_INTERNAL_URL=http://backend:8000
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
|
|||||||
28
docker/supervisord.conf
Normal file
28
docker/supervisord.conf
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/dev/null
|
||||||
|
logfile_maxbytes=0
|
||||||
|
pidfile=/tmp/supervisord.pid
|
||||||
|
|
||||||
|
[program:backend]
|
||||||
|
directory=/app
|
||||||
|
command=uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=10
|
||||||
|
|
||||||
|
[program:frontend]
|
||||||
|
directory=/app/frontend
|
||||||
|
command=/usr/bin/npm start -- --hostname 0.0.0.0 --port 3000
|
||||||
|
environment=NEXT_PUBLIC_API_BASE="/api",BACKEND_INTERNAL_URL="http://127.0.0.1:8000",NODE_ENV="production"
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
priority=20
|
||||||
@@ -34,6 +34,15 @@ const SECTION_LABELS: Record<string, string> = {
|
|||||||
|
|
||||||
const BOOL_SETTINGS = new Set(['jellyfin_sync_to_arr', 'site_banner_enabled'])
|
const BOOL_SETTINGS = new Set(['jellyfin_sync_to_arr', 'site_banner_enabled'])
|
||||||
const TEXTAREA_SETTINGS = new Set(['site_banner_message', 'site_changelog'])
|
const TEXTAREA_SETTINGS = new Set(['site_banner_message', 'site_changelog'])
|
||||||
|
const URL_SETTINGS = new Set([
|
||||||
|
'jellyseerr_base_url',
|
||||||
|
'jellyfin_base_url',
|
||||||
|
'jellyfin_public_url',
|
||||||
|
'sonarr_base_url',
|
||||||
|
'radarr_base_url',
|
||||||
|
'prowlarr_base_url',
|
||||||
|
'qbittorrent_base_url',
|
||||||
|
])
|
||||||
const BANNER_TONES = ['info', 'warning', 'error', 'maintenance']
|
const BANNER_TONES = ['info', 'warning', 'error', 'maintenance']
|
||||||
|
|
||||||
const SECTION_DESCRIPTIONS: Record<string, string> = {
|
const SECTION_DESCRIPTIONS: Record<string, string> = {
|
||||||
@@ -330,26 +339,31 @@ export default function SettingsPage({ section }: SettingsPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const settingDescriptions: Record<string, string> = {
|
const settingDescriptions: Record<string, string> = {
|
||||||
jellyseerr_base_url: 'Base URL for your Jellyseerr server.',
|
jellyseerr_base_url:
|
||||||
|
'Base URL for your Jellyseerr server (FQDN or IP). Scheme is optional.',
|
||||||
jellyseerr_api_key: 'API key used to read requests and status.',
|
jellyseerr_api_key: 'API key used to read requests and status.',
|
||||||
jellyfin_base_url: 'Local Jellyfin server URL for logins and lookups.',
|
jellyfin_base_url:
|
||||||
|
'Jellyfin server URL for logins and lookups (FQDN or IP). Scheme is optional.',
|
||||||
jellyfin_api_key: 'Admin API key for syncing users and availability.',
|
jellyfin_api_key: 'Admin API key for syncing users and availability.',
|
||||||
jellyfin_public_url: 'Public Jellyfin URL used for the “Open in Jellyfin” button.',
|
jellyfin_public_url:
|
||||||
|
'Public Jellyfin URL for the “Open in Jellyfin” button (FQDN or IP).',
|
||||||
jellyfin_sync_to_arr: 'Auto-add items to Sonarr/Radarr when they already exist in Jellyfin.',
|
jellyfin_sync_to_arr: 'Auto-add items to Sonarr/Radarr when they already exist in Jellyfin.',
|
||||||
artwork_cache_mode: 'Choose whether posters are cached locally or loaded from the web.',
|
artwork_cache_mode: 'Choose whether posters are cached locally or loaded from the web.',
|
||||||
sonarr_base_url: 'Sonarr server URL for TV tracking.',
|
sonarr_base_url: 'Sonarr server URL for TV tracking (FQDN or IP). Scheme is optional.',
|
||||||
sonarr_api_key: 'API key for Sonarr.',
|
sonarr_api_key: 'API key for Sonarr.',
|
||||||
sonarr_quality_profile_id: 'Quality profile used when adding TV shows.',
|
sonarr_quality_profile_id: 'Quality profile used when adding TV shows.',
|
||||||
sonarr_root_folder: 'Root folder where Sonarr stores TV shows.',
|
sonarr_root_folder: 'Root folder where Sonarr stores TV shows.',
|
||||||
sonarr_qbittorrent_category: 'qBittorrent category for manual Sonarr downloads.',
|
sonarr_qbittorrent_category: 'qBittorrent category for manual Sonarr downloads.',
|
||||||
radarr_base_url: 'Radarr server URL for movies.',
|
radarr_base_url: 'Radarr server URL for movies (FQDN or IP). Scheme is optional.',
|
||||||
radarr_api_key: 'API key for Radarr.',
|
radarr_api_key: 'API key for Radarr.',
|
||||||
radarr_quality_profile_id: 'Quality profile used when adding movies.',
|
radarr_quality_profile_id: 'Quality profile used when adding movies.',
|
||||||
radarr_root_folder: 'Root folder where Radarr stores movies.',
|
radarr_root_folder: 'Root folder where Radarr stores movies.',
|
||||||
radarr_qbittorrent_category: 'qBittorrent category for manual Radarr downloads.',
|
radarr_qbittorrent_category: 'qBittorrent category for manual Radarr downloads.',
|
||||||
prowlarr_base_url: 'Prowlarr server URL for indexer searches.',
|
prowlarr_base_url:
|
||||||
|
'Prowlarr server URL for indexer searches (FQDN or IP). Scheme is optional.',
|
||||||
prowlarr_api_key: 'API key for Prowlarr.',
|
prowlarr_api_key: 'API key for Prowlarr.',
|
||||||
qbittorrent_base_url: 'qBittorrent server URL for download status.',
|
qbittorrent_base_url:
|
||||||
|
'qBittorrent server URL for download status (FQDN or IP). Scheme is optional.',
|
||||||
qbittorrent_username: 'qBittorrent login username.',
|
qbittorrent_username: 'qBittorrent login username.',
|
||||||
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.',
|
||||||
@@ -371,6 +385,16 @@ export default function SettingsPage({ section }: SettingsPageProps) {
|
|||||||
site_changelog: 'One update per line for the public changelog.',
|
site_changelog: 'One update per line for the public changelog.',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const settingPlaceholders: Record<string, string> = {
|
||||||
|
jellyseerr_base_url: 'https://requests.example.com or 10.30.1.81:5055',
|
||||||
|
jellyfin_base_url: 'https://jelly.example.com or 10.40.0.80:8096',
|
||||||
|
jellyfin_public_url: 'https://jelly.example.com',
|
||||||
|
sonarr_base_url: 'https://sonarr.example.com or 10.30.1.81:8989',
|
||||||
|
radarr_base_url: 'https://radarr.example.com or 10.30.1.81:7878',
|
||||||
|
prowlarr_base_url: 'https://prowlarr.example.com or 10.30.1.81:9696',
|
||||||
|
qbittorrent_base_url: 'https://qb.example.com or 10.30.1.81:8080',
|
||||||
|
}
|
||||||
|
|
||||||
const buildSelectOptions = (
|
const buildSelectOptions = (
|
||||||
currentValue: string,
|
currentValue: string,
|
||||||
options: { id: number; label: string; path?: string }[],
|
options: { id: number; label: string; path?: string }[],
|
||||||
@@ -982,6 +1006,10 @@ export default function SettingsPage({ section }: SettingsPageProps) {
|
|||||||
const isRadarrProfile = setting.key === 'radarr_quality_profile_id'
|
const isRadarrProfile = setting.key === 'radarr_quality_profile_id'
|
||||||
const isRadarrRoot = setting.key === 'radarr_root_folder'
|
const isRadarrRoot = setting.key === 'radarr_root_folder'
|
||||||
const isBoolSetting = BOOL_SETTINGS.has(setting.key)
|
const isBoolSetting = BOOL_SETTINGS.has(setting.key)
|
||||||
|
const isUrlSetting = URL_SETTINGS.has(setting.key)
|
||||||
|
const inputPlaceholder = setting.sensitive && setting.isSet
|
||||||
|
? 'Configured (enter to replace)'
|
||||||
|
: settingPlaceholders[setting.key] ?? ''
|
||||||
if (isBoolSetting) {
|
if (isBoolSetting) {
|
||||||
return (
|
return (
|
||||||
<label key={setting.key} data-helper={helperText || undefined}>
|
<label key={setting.key} data-helper={helperText || undefined}>
|
||||||
@@ -1312,9 +1340,8 @@ export default function SettingsPage({ section }: SettingsPageProps) {
|
|||||||
<input
|
<input
|
||||||
name={setting.key}
|
name={setting.key}
|
||||||
type={setting.sensitive ? 'password' : 'text'}
|
type={setting.sensitive ? 'password' : 'text'}
|
||||||
placeholder={
|
placeholder={inputPlaceholder}
|
||||||
setting.sensitive && setting.isSet ? 'Configured (enter to replace)' : ''
|
autoComplete={isUrlSetting ? 'url' : undefined}
|
||||||
}
|
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setFormValues((current) => ({
|
setFormValues((current) => ({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "magent-frontend",
|
"name": "magent-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2901262244",
|
"version": "0202261541",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
|||||||
Reference in New Issue
Block a user