fix(settings): stop clobbering WebDAV edits and save without a successful test
Two coupled issues in workspace settings: 1. The credentials-loading effect re-ran whenever ws.webdav_url changed, so any config mutation (e.g. changing sync interval) would trigger a re-load of the stored username/password, overwriting whatever the user was typing into those fields. Gate with a one-shot credsLoaded flag. 2. Save would persist whatever was in the URL input even if the user had never tested it — a typo'd host silently pointed the workspace at a dead server. Now saveWebdav auto-runs the connection test and bails if it fails; any edit to the three inputs clears the "ok" status via markDirty() so the next Save is forced to re-verify. Also replaces the ASCII "Failed -- Retry" with an em dash.
This commit is contained in:
parent
b437b0b7b2
commit
d01bd9d280
|
|
@ -15,14 +15,19 @@
|
||||||
let webdavUser = $state("");
|
let webdavUser = $state("");
|
||||||
let webdavPass = $state("");
|
let webdavPass = $state("");
|
||||||
let testStatus = $state<"idle" | "testing" | "ok" | "fail">("idle");
|
let testStatus = $state<"idle" | "testing" | "ok" | "fail">("idle");
|
||||||
|
let credsLoaded = $state(false);
|
||||||
|
|
||||||
let renaming = $state(false);
|
let renaming = $state(false);
|
||||||
let renameValue = $state("");
|
let renameValue = $state("");
|
||||||
let showKebab = $state(false);
|
let showKebab = $state(false);
|
||||||
let confirmRename = $state(false);
|
let confirmRename = $state(false);
|
||||||
|
|
||||||
|
// Load stored credentials exactly once for this workspace. Previously this
|
||||||
|
// ran on every `ws.webdav_url` change, which silently clobbered in-progress
|
||||||
|
// user edits whenever any other setting updated the config.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (!ws?.webdav_url) return;
|
if (credsLoaded || !ws?.webdav_url) return;
|
||||||
|
credsLoaded = true;
|
||||||
webdavUrl = ws.webdav_url;
|
webdavUrl = ws.webdav_url;
|
||||||
try {
|
try {
|
||||||
const domain = new URL(ws.webdav_url).hostname;
|
const domain = new URL(ws.webdav_url).hostname;
|
||||||
|
|
@ -35,6 +40,12 @@
|
||||||
} catch {}
|
} catch {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Any edit invalidates a prior test so users can't Save a config they
|
||||||
|
// haven't validated since changing it.
|
||||||
|
function markDirty() {
|
||||||
|
if (testStatus !== "idle") testStatus = "idle";
|
||||||
|
}
|
||||||
|
|
||||||
async function testConnection() {
|
async function testConnection() {
|
||||||
testStatus = "testing";
|
testStatus = "testing";
|
||||||
try {
|
try {
|
||||||
|
|
@ -51,6 +62,12 @@
|
||||||
|
|
||||||
async function saveWebdav() {
|
async function saveWebdav() {
|
||||||
if (!webdavUrl.trim()) return;
|
if (!webdavUrl.trim()) return;
|
||||||
|
// Require a successful test so a typo'd URL can't silently point the
|
||||||
|
// workspace at a dead server.
|
||||||
|
if (testStatus !== "ok") {
|
||||||
|
await testConnection();
|
||||||
|
if (testStatus !== "ok") return;
|
||||||
|
}
|
||||||
await invoke("set_webdav_config", {
|
await invoke("set_webdav_config", {
|
||||||
workspaceId,
|
workspaceId,
|
||||||
webdavUrl: webdavUrl.trim(),
|
webdavUrl: webdavUrl.trim(),
|
||||||
|
|
@ -172,6 +189,7 @@
|
||||||
<input
|
<input
|
||||||
type="url"
|
type="url"
|
||||||
bind:value={webdavUrl}
|
bind:value={webdavUrl}
|
||||||
|
oninput={markDirty}
|
||||||
placeholder="https://dav.example.com/tasks/"
|
placeholder="https://dav.example.com/tasks/"
|
||||||
class="mb-3 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm outline-none focus:border-primary dark:border-border-dark"
|
class="mb-3 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm outline-none focus:border-primary dark:border-border-dark"
|
||||||
/>
|
/>
|
||||||
|
|
@ -180,6 +198,7 @@
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={webdavUser}
|
bind:value={webdavUser}
|
||||||
|
oninput={markDirty}
|
||||||
class="mb-3 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm outline-none focus:border-primary dark:border-border-dark"
|
class="mb-3 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm outline-none focus:border-primary dark:border-border-dark"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -187,6 +206,7 @@
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
bind:value={webdavPass}
|
bind:value={webdavPass}
|
||||||
|
oninput={markDirty}
|
||||||
class="mb-4 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm outline-none focus:border-primary dark:border-border-dark"
|
class="mb-4 w-full rounded-lg border border-border-light bg-transparent px-3 py-2 text-sm outline-none focus:border-primary dark:border-border-dark"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -196,7 +216,7 @@
|
||||||
disabled={!webdavUrl.trim()}
|
disabled={!webdavUrl.trim()}
|
||||||
class="rounded-lg border border-border-light px-4 py-2 text-sm font-medium hover:bg-black/5 disabled:opacity-40 dark:border-border-dark dark:hover:bg-white/10"
|
class="rounded-lg border border-border-light px-4 py-2 text-sm font-medium hover:bg-black/5 disabled:opacity-40 dark:border-border-dark dark:hover:bg-white/10"
|
||||||
>
|
>
|
||||||
{testStatus === "testing" ? "Testing..." : testStatus === "ok" ? "Connected" : testStatus === "fail" ? "Failed -- Retry" : "Test Connection"}
|
{testStatus === "testing" ? "Testing…" : testStatus === "ok" ? "Connected" : testStatus === "fail" ? "Failed — Retry" : "Test Connection"}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onclick={saveWebdav}
|
onclick={saveWebdav}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue