feat(web): Monitor settings tab
This commit is contained in:
@@ -12,8 +12,8 @@ type Loaded = {
|
||||
slskdApiKeySet: boolean;
|
||||
};
|
||||
|
||||
type Tab = "Qobuz" | "Soulseek" | "Library" | "Discovery";
|
||||
const TABS: Tab[] = ["Qobuz", "Soulseek", "Library", "Discovery"];
|
||||
type Tab = "Qobuz" | "Soulseek" | "Library" | "Monitor" | "Discovery";
|
||||
const TABS: Tab[] = ["Qobuz", "Soulseek", "Library", "Monitor", "Discovery"];
|
||||
|
||||
const DISCOVERY_FIELDS: [string, string][] = [
|
||||
["discover.intervalHours", "Interval (hours)"],
|
||||
@@ -23,6 +23,13 @@ const DISCOVERY_FIELDS: [string, string][] = [
|
||||
["discover.minScore", "Min score"],
|
||||
];
|
||||
|
||||
const MONITOR_FIELDS: [string, string][] = [
|
||||
["monitor.pollIntervalHours", "Poll interval (hours)"],
|
||||
["monitor.retryIntervalHours", "Retry interval (hours)"],
|
||||
["monitor.qualityCutoff", "Quality cutoff"],
|
||||
["monitor.upgradeWindowDays", "Upgrade window (days)"],
|
||||
];
|
||||
|
||||
export function SettingsForm() {
|
||||
const [tab, setTab] = useState<Tab>("Qobuz");
|
||||
const [qobuzEmail, setQobuzEmail] = useState("");
|
||||
@@ -39,6 +46,8 @@ export function SettingsForm() {
|
||||
const [scanRequested, setScanRequested] = useState(false);
|
||||
const [discoverCfg, setDiscoverCfg] = useState<Record<string, string>>({});
|
||||
const [discoverSaved, setDiscoverSaved] = useState(false);
|
||||
const [monitorCfg, setMonitorCfg] = useState<Record<string, string>>({});
|
||||
const [monitorSaved, setMonitorSaved] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/scan")
|
||||
@@ -83,6 +92,12 @@ export function SettingsForm() {
|
||||
.then((c: Record<string, string>) => setDiscoverCfg(c));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/monitor/config")
|
||||
.then((r) => r.json())
|
||||
.then((c: Record<string, string>) => setMonitorCfg(c));
|
||||
}, []);
|
||||
|
||||
async function saveCredentials(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
await fetch("/api/config", {
|
||||
@@ -115,6 +130,21 @@ export function SettingsForm() {
|
||||
setTimeout(() => setDiscoverSaved(false), 1500);
|
||||
}
|
||||
|
||||
function setMon(key: string, value: string) {
|
||||
setMonitorCfg((c) => ({ ...c, [key]: value }));
|
||||
}
|
||||
|
||||
async function saveMonitor(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
await fetch("/api/monitor/config", {
|
||||
method: "PATCH",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(monitorCfg),
|
||||
});
|
||||
setMonitorSaved(true);
|
||||
setTimeout(() => setMonitorSaved(false), 1500);
|
||||
}
|
||||
|
||||
const secretHint = (set: boolean) => (set ? <span className="set"> · set</span> : null);
|
||||
|
||||
return (
|
||||
@@ -205,6 +235,43 @@ export function SettingsForm() {
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{tab === "Monitor" ? (
|
||||
<form className="settings-section" onSubmit={saveMonitor}>
|
||||
<div className="save-row" style={{ margin: "6px 0 4px" }}>
|
||||
<label className="toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={monitorCfg["monitor.enabled"] === "true"}
|
||||
onChange={(e) => setMon("monitor.enabled", e.target.checked ? "true" : "false")}
|
||||
/>
|
||||
Automatic monitoring (grab & upgrade)
|
||||
</label>
|
||||
</div>
|
||||
<div className="save-row" style={{ margin: "2px 0 8px" }}>
|
||||
<label className="toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={monitorCfg["monitor.autoMonitorFuture"] === "true"}
|
||||
onChange={(e) => setMon("monitor.autoMonitorFuture", e.target.checked ? "true" : "false")}
|
||||
/>
|
||||
Auto-monitor future releases from watched artists
|
||||
</label>
|
||||
</div>
|
||||
<div className="field-grid">
|
||||
{MONITOR_FIELDS.map(([key, label]) => (
|
||||
<label key={key} className="field">
|
||||
<span>{label}</span>
|
||||
<input type="number" step="any" value={monitorCfg[key] ?? ""} onChange={(e) => setMon(key, e.target.value)} />
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<div className="save-row">
|
||||
<button type="submit" className="btn">Save monitor settings</button>
|
||||
{monitorSaved ? <span className="saved-note">Saved</span> : null}
|
||||
</div>
|
||||
</form>
|
||||
) : null}
|
||||
|
||||
{tab === "Discovery" ? (
|
||||
<form className="settings-section" onSubmit={saveDiscovery}>
|
||||
<div className="save-row" style={{ margin: "6px 0 4px" }}>
|
||||
|
||||
Reference in New Issue
Block a user