+
+ {/* Client type: choosable while still a draft, locked once chosen. */}
+
onChange({ ...webui, client: value as Client })}
/>
-
- Name
- onChange({ ...webui, name: e.target.value })}
- style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 180 }}
- />
-
-
- {/* Host + Port + Secure + Relative Path */}
-
-
- Host
- onChange({ ...webui, host: e.target.value })} style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 120 }} />
-
-
- Port
- onChange({ ...webui, port: Number(e.target.value) })} style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 80 }} />
-
-
onChange({ ...webui, secure: v })} label="Secure (HTTPS)" />
-
- Relative Path
- onChange({ ...webui, relativePath: e.target.value })} style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 120 }} />
-
-
Base URL for API calls: {webUiInstance?.createBaseUrl()}
- {/* Username + Password */}
-
-
- Username
- onChange({ ...webui, username: e.target.value })} style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 120 }} />
-
-
- Password
- onChange({ ...webui, password: e.target.value })} style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 120 }} />
-
-
- {/* Only show these fields if supported by the WebUI instance */}
- {webUiInstance?.isAddPausedSupported && (
-
- {/* Torrents Paused Toggle */}
- onChange({ ...webui, addPaused: v })} label="Add torrents paused" />
-
- )}
- {webUiInstance?.isLabelDirChooserSupported && (
-
- {/* Per-torrent config selector toggle */}
-
onChange({ ...webui, showPerTorrentConfigSelector: v })} label="Show per-torrent config selector" />
- {/* Alternative label/dir chooser toggle */}
- onChange({ ...webui, useAlternativeLabelDirChooser: v })} label="Use alternative container (window instead of popup)" />
+
+ {!clientChosen ? (
+
+ Select a client type above to configure this WebUI.
- )}
- {webUiInstance?.isLabelSupported && (
+ ) : (
<>
-
-
Default Label
-
onChange({ ...webui, defaultLabel: e.target.value })}
- style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 180 }}
- placeholder="Default label"
- />
+ {/* Host + Port + Secure + Relative Path */}
+
-
onChange({ ...webui, labels })} placeholder="Add label" />
- >
- )}
- {webUiInstance?.isDirSupported && (
- <>
-
-
Default Directory
-
onChange({ ...webui, defaultDir: e.target.value })}
- style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 180 }}
- placeholder="Default directory"
- />
+
Base URL for API calls: {webUiInstance?.createBaseUrl()}
+ {/* Username + Password */}
+
-
onChange({ ...webui, dirs })} placeholder="Add directory" />
+ {/* Only show these fields if supported by the WebUI instance */}
+ {webUiInstance?.isAddPausedSupported && (
+
+ onChange({ ...webui, addPaused: v })} label="Add torrents paused" />
+
+ )}
+ {webUiInstance?.isLabelDirChooserSupported && (
+
+ onChange({ ...webui, showPerTorrentConfigSelector: v })} label="Show per-torrent config selector" />
+ onChange({ ...webui, useAlternativeLabelDirChooser: v })} label="Use alternative container (window instead of popup)" />
+
+ )}
+ {webUiInstance?.isLabelSupported && (
+ <>
+
+ Default Label
+ onChange({ ...webui, defaultLabel: e.target.value })}
+ style={{ ...fieldInputStyle, minWidth: 180 }}
+ placeholder="Default label"
+ />
+
+ onChange({ ...webui, labels })} placeholder="Add label" />
+ >
+ )}
+ {webUiInstance?.isDirSupported && (
+ <>
+
+ Default Directory
+ onChange({ ...webui, defaultDir: e.target.value })}
+ style={{ ...fieldInputStyle, minWidth: 180 }}
+ placeholder="Default directory"
+ />
+
+ onChange({ ...webui, dirs })} placeholder="Add directory" />
+ >
+ )}
+ {webUiInstance?.isLabelDirChooserSupported && (
+ onChange({ ...webui, autoLabelDirSettings })}
+ showLabel={!!webUiInstance?.isLabelSupported}
+ showDir={!!webUiInstance?.isDirSupported}
+ labels={webui.labels}
+ dirs={webui.dirs}
+ />
+ )}
>
)}
- {webUiInstance?.isLabelDirChooserSupported && (
- onChange({ ...webui, autoLabelDirSettings })}
- showLabel={!!webUiInstance?.isLabelSupported}
- showDir={!!webUiInstance?.isDirSupported}
- labels={webui.labels}
- dirs={webui.dirs}
- />
- )}
- {/*
-
ClientSpecificSettings: TODO: implement
-
*/}
);
}
export default function WebUIsPage() {
const { settings, updateSetting, loading } = useSettings();
- const [adding, setAdding] = useState(false);
- const [newName, setNewName] = useState("");
- const [newClient, setNewClient] = useState("");
+ const [selectedId, setSelectedId] = useState(null);
+
+ const webuis = settings?.webuiSettings ?? [];
+
+ // Default to the primary WebUI so the page never opens to an empty panel,
+ // and keep the selection valid if the selected entry is removed.
+ useEffect(() => {
+ if (webuis.length === 0) {
+ if (selectedId !== null) setSelectedId(null);
+ } else if (!webuis.some(w => w.id === selectedId)) {
+ setSelectedId(webuis[0].id);
+ }
+ }, [webuis, selectedId]);
if (loading || !settings) return Loading...
;
const handleAdd = () => {
- if (!newName || !newClient) return;
- const newWebUI: WebUISettings = { ...getDefaultWebUISettings(), name: newName, client: newClient as Client };
- updateSetting("webuiSettings", [...settings.webuiSettings, newWebUI]);
- setAdding(false);
- setNewName("");
- setNewClient("");
+ const newWebUI = getDefaultWebUISettings();
+ updateSetting("webuiSettings", [...webuis, newWebUI]);
+ setSelectedId(newWebUI.id);
};
- const handleChange = (idx: number, updated: WebUISettings) => {
- const arr = [...settings.webuiSettings];
- arr[idx] = updated;
- updateSetting("webuiSettings", arr);
+ const handleChange = (id: string, updated: WebUISettings) => {
+ updateSetting("webuiSettings", webuis.map(w => (w.id === id ? updated : w)));
};
- const handleRemove = (idx: number) => {
- const arr = [...settings.webuiSettings];
- arr.splice(idx, 1);
- updateSetting("webuiSettings", arr);
+ const handleRemove = (id: string) => {
+ updateSetting("webuiSettings", webuis.filter(w => w.id !== id));
};
- const handlePromote = (idx: number) => {
- if (idx === 0) return; // already primary
- const arr = [...settings.webuiSettings];
+ const handlePromote = (id: string) => {
+ const idx = webuis.findIndex(w => w.id === id);
+ if (idx <= 0) return; // not found or already primary
+ const arr = [...webuis];
const [item] = arr.splice(idx, 1);
arr.unshift(item);
updateSetting("webuiSettings", arr);
};
+ const selected = webuis.find(w => w.id === selectedId) ?? null;
+
return (
-
- {adding ? (
-
-
Add New WebUI
-
+ {/* Left panel: list of configured WebUIs */}
+
+
+ WebUIs
+ +
+
+
+ {webuis.length === 0 ? (
+
+ No WebUIs yet. Click + to add one.
+
+ ) : (
+ webuis.map((webui, idx) => (
+
setSelectedId(webui.id)}
+ onNameChange={name => handleChange(webui.id, { ...webui, name })}
+ />
+ ))
+ )}
+
+
+
+ {/* Right panel: configuration for the selected WebUI */}
+
+ {selected ? (
+
handleChange(selected.id, updated)}
+ onRemove={() => handleRemove(selected.id)}
+ onPromote={() => handlePromote(selected.id)}
+ isPrimary={webuis[0]?.id === selected.id}
/>
-
-
Name
-
setNewName(e.target.value)}
- style={{ fontSize: 15, borderRadius: 8, padding: "6px 12px", border: "1px solid var(--rta-border, #b7c9a7)", background: "var(--rta-input-bg, #fff)", color: "var(--rta-text, #1b241d)", minWidth: 180 }}
- />
+ ) : (
+
+ Select a WebUI on the left, or click + to add a new one.
-
Add
-
setAdding(false)} style={{ background: "var(--rta-danger, #B22222)", color: "#fff", border: "none", borderRadius: 8, padding: "8px 18px", fontWeight: 500, cursor: "pointer" }}>Cancel
-
- ) : (
- setAdding(true)} style={{ background: "var(--rta-success, #228B22)", color: "#fff", border: "none", borderRadius: 8, padding: "8px 18px", fontWeight: 500, cursor: "pointer", marginTop: 12, marginBottom: 12 }}>Add New WebUI
- )}
- {settings.webuiSettings.length === 0 && !adding && (
- No WebUIs configured yet.
- )}
- {settings.webuiSettings.map((webui, idx) => (
- handleChange(idx, updated)}
- onRemove={() => handleRemove(idx)}
- onPromote={() => handlePromote(idx)}
- isPrimary={idx === 0}
- />
- ))}
+ )}
+
);
}