feat(settings): lock container path fields with unlock toggle

Prevent accidental misconfiguration of Docker container-internal paths
(Slskd Download Dir, Matched Transfer Dir, Import Staging Dir) by making
them read-only by default.

Repurposes the non-functional Browse button into a per-field Unlock/Lock
toggle. Adds a warning blurb below the Download Settings header so users
understand these are container paths, not host paths.
This commit is contained in:
snuffomega 2026-02-23 12:54:55 -05:00
parent 129f69fce9
commit e7ff1b2081
3 changed files with 39 additions and 9 deletions

View file

@ -2960,28 +2960,31 @@
<!-- Download Settings -->
<div class="settings-group">
<h3>Download Settings</h3>
<div class="setting-help-text">
These are container-internal paths. Only modify them if you know what you're doing — incorrect values will break downloads.
</div>
<div class="form-group">
<label>Slskd Download Dir:</label>
<div class="path-input-group">
<input type="text" id="download-path" placeholder="./downloads">
<button class="browse-button" onclick="browsePath('download')">Browse</button>
<input type="text" id="download-path" placeholder="./downloads" readonly>
<button class="browse-button locked" onclick="togglePathLock('download', this)">Unlock</button>
</div>
</div>
<div class="form-group">
<label>Matched Transfer Dir (Plex Music Dir?):</label>
<div class="path-input-group">
<input type="text" id="transfer-path" placeholder="./Transfer">
<button class="browse-button" onclick="browsePath('transfer')">Browse</button>
<input type="text" id="transfer-path" placeholder="./Transfer" readonly>
<button class="browse-button locked" onclick="togglePathLock('transfer', this)">Unlock</button>
</div>
</div>
<div class="form-group">
<label>Import Staging Dir:</label>
<div class="path-input-group">
<input type="text" id="staging-path" placeholder="./Staging">
<button class="browse-button" onclick="browsePath('staging')">Browse</button>
<input type="text" id="staging-path" placeholder="./Staging" readonly>
<button class="browse-button locked" onclick="togglePathLock('staging', this)">Unlock</button>
</div>
</div>

View file

@ -2733,8 +2733,26 @@ async function authenticateTidal() {
}
}
function browsePath(pathType) {
showToast(`Path browser not available in web interface. Please enter path manually.`, 'error');
const PATH_INPUT_IDS = {
download: 'download-path',
transfer: 'transfer-path',
staging: 'staging-path'
};
function togglePathLock(pathType, btn) {
const input = document.getElementById(PATH_INPUT_IDS[pathType]);
if (!input) return;
const isLocked = input.hasAttribute('readonly');
if (isLocked) {
input.removeAttribute('readonly');
input.focus();
btn.textContent = 'Lock';
btn.classList.remove('locked');
} else {
input.setAttribute('readonly', '');
btn.textContent = 'Unlock';
btn.classList.add('locked');
}
}
@ -10917,7 +10935,7 @@ window.autoDetectSlskd = autoDetectSlskd;
window.toggleServer = toggleServer;
window.authenticateSpotify = authenticateSpotify;
window.authenticateTidal = authenticateTidal;
window.browsePath = browsePath;
window.togglePathLock = togglePathLock;
window.selectResult = selectResult;
window.startStream = startStream;
window.streamTrack = streamTrack;

View file

@ -1744,6 +1744,15 @@ body {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.path-input-group input[readonly] {
opacity: 0.55;
cursor: not-allowed;
}
.browse-button.locked {
opacity: 0.7;
}
/* Auth Button - gradient */
.auth-button {
background: linear-gradient(135deg, #1db954, #1ed760);