Report failures where the operator can still see them
The 55 alert() calls carried the same suppression as the confirms, and go wrong in the worse direction: a silenced confirm makes a button do nothing, while a silenced alert lets the action run and says nothing about it failing. vvAlert returns a promise nobody has to await, so these converted by rename with no caller becoming async. The icon is inferred from the message rather than asked of fifty call sites, and an explicit type still wins.
This commit is contained in:
@@ -147,7 +147,19 @@ function vvConfirm(text, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Telling the operator something, with no question attached. Returns a promise so a caller can
|
// Telling the operator something, with no question attached. Returns a promise so a caller can
|
||||||
// sequence on it, but nothing has to await it.
|
// sequence on it, but nothing has to await it — which is what let the fifty-odd alert() sites
|
||||||
|
// become this by rename alone, with no function above them turning async.
|
||||||
|
//
|
||||||
|
// The icon is read off the message when the caller does not say. Almost every one of these
|
||||||
|
// reports a failure — "Save failed: …", "Error: …" — and asking fifty call sites to each classify
|
||||||
|
// themselves would mean fifty chances to disagree about what counts as an error. The caller can
|
||||||
|
// still pass type explicitly and that always wins.
|
||||||
|
function vvAlertType(text) {
|
||||||
|
const s = String(text ?? '');
|
||||||
|
if (/\b(fail|failed|error|denied|invalid|refused|cannot|could not|unable)\b/i.test(s)) return 'error';
|
||||||
|
if (/\b(warn|warning|already|must be)\b/i.test(s)) return 'warning';
|
||||||
|
return 'info';
|
||||||
|
}
|
||||||
function vvAlert(text, opts) {
|
function vvAlert(text, opts) {
|
||||||
const o = opts || {};
|
const o = opts || {};
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
@@ -155,7 +167,7 @@ function vvAlert(text, opts) {
|
|||||||
swal({
|
swal({
|
||||||
title: o.title || '',
|
title: o.title || '',
|
||||||
text: String(text ?? ''),
|
text: String(text ?? ''),
|
||||||
type: o.type || 'info',
|
type: o.type || vvAlertType(text),
|
||||||
confirmButtonText: o.confirmText || 'OK',
|
confirmButtonText: o.confirmText || 'OK',
|
||||||
}, function (ok) { resolve(true); });
|
}, function (ok) { resolve(true); });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -649,7 +649,7 @@ function _addToGroupModal(uid) {
|
|||||||
const user = _users.find(u => u.id === uid);
|
const user = _users.find(u => u.id === uid);
|
||||||
const userGids= new Set((user?.groups||[]).map(g => g.id));
|
const userGids= new Set((user?.groups||[]).map(g => g.id));
|
||||||
const available = _groups.filter(g => !userGids.has(g.id));
|
const available = _groups.filter(g => !userGids.has(g.id));
|
||||||
if (!available.length) { alert('User is already in all groups.'); return; }
|
if (!available.length) { vvAlert('User is already in all groups.'); return; }
|
||||||
const opts = available.map(g => `<option value="${g.id}">${_esc(g.displayName)}</option>`).join('');
|
const opts = available.map(g => `<option value="${g.id}">${_esc(g.displayName)}</option>`).join('');
|
||||||
_modal(`<h3>Add to Group</h3>
|
_modal(`<h3>Add to Group</h3>
|
||||||
<div class="vv-au-field">
|
<div class="vv-au-field">
|
||||||
@@ -936,7 +936,7 @@ document.getElementById('vv-au-panel-acl').addEventListener('click', async e =>
|
|||||||
btn.disabled = true; btn.textContent = 'Saving…';
|
btn.disabled = true; btn.textContent = 'Saving…';
|
||||||
_post({ action:'authelia_save', rules: JSON.stringify(_rules), default_policy: dp }, r => {
|
_post({ action:'authelia_save', rules: JSON.stringify(_rules), default_policy: dp }, r => {
|
||||||
btn.disabled = false; btn.textContent = 'Save & Restart Authelia';
|
btn.disabled = false; btn.textContent = 'Save & Restart Authelia';
|
||||||
if (!r.ok) { alert('Save failed: ' + (r.error||'unknown error')); return; }
|
if (!r.ok) { vvAlert('Save failed: ' + (r.error||'unknown error')); return; }
|
||||||
// brief visual confirmation
|
// brief visual confirmation
|
||||||
btn.textContent = 'Saved ✓';
|
btn.textContent = 'Saved ✓';
|
||||||
setTimeout(() => { btn.textContent = 'Save & Restart Authelia'; }, 2000);
|
setTimeout(() => { btn.textContent = 'Save & Restart Authelia'; }, 2000);
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ function _doRestart(name) {
|
|||||||
function _doStartStop(name, start) {
|
function _doStartStop(name, start) {
|
||||||
_actApi({action: start ? 'start' : 'stop', name}, data => {
|
_actApi({action: start ? 'start' : 'stop', name}, data => {
|
||||||
if (data.ok) setTimeout(_reload, 800);
|
if (data.ok) setTimeout(_reload, 800);
|
||||||
else alert((start ? 'Start' : 'Stop') + ' failed: ' + (data.output || data.error || '?'));
|
else vvAlert((start ? 'Start' : 'Stop') + ' failed: ' + (data.output || data.error || '?'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +378,7 @@ function _doPullRebuild(name) {
|
|||||||
if (data.ok && data.job_id) {
|
if (data.ok && data.job_id) {
|
||||||
_startJob(name, data.job_id);
|
_startJob(name, data.job_id);
|
||||||
} else {
|
} else {
|
||||||
alert('Update failed: ' + (data.error || '?'));
|
vvAlert('Update failed: ' + (data.error || '?'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -478,7 +478,7 @@ function _bindEvents() {
|
|||||||
el.disabled = true; el.style.opacity = '0.5';
|
el.disabled = true; el.style.opacity = '0.5';
|
||||||
_api({action:'rename_folder',folder_id:fid,name}, r => {
|
_api({action:'rename_folder',folder_id:fid,name}, r => {
|
||||||
el.disabled = false; el.style.opacity = '';
|
el.disabled = false; el.style.opacity = '';
|
||||||
if (r.ok) _reload(); else { alert('Rename failed: '+(r.error||'?')); el.value = f?.name ?? name; }
|
if (r.ok) _reload(); else { vvAlert('Rename failed: '+(r.error||'?')); el.value = f?.name ?? name; }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -490,14 +490,14 @@ function _bindEvents() {
|
|||||||
const fid = el.dataset.deleteFolder;
|
const fid = el.dataset.deleteFolder;
|
||||||
const f = (_data.folders||[]).find(x=>x.id===fid);
|
const f = (_data.folders||[]).find(x=>x.id===fid);
|
||||||
if (!f || !await vvConfirm(`Delete "${f.name}"? Containers will be ungrouped.`)) return;
|
if (!f || !await vvConfirm(`Delete "${f.name}"? Containers will be ungrouped.`)) return;
|
||||||
_api({action:'delete_folder',folder_id:fid}, r => { if(r.ok) _reload(); else alert('Delete failed: '+(r.error||'?')); });
|
_api({action:'delete_folder',folder_id:fid}, r => { if(r.ok) _reload(); else vvAlert('Delete failed: '+(r.error||'?')); });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// New folder
|
// New folder
|
||||||
document.getElementById('vv-dk-add-folder')?.addEventListener('click', async () => {
|
document.getElementById('vv-dk-add-folder')?.addEventListener('click', async () => {
|
||||||
const name = await vvPrompt('New folder name:');
|
const name = await vvPrompt('New folder name:');
|
||||||
if (name?.trim()) _api({action:'create_folder',name:name.trim()}, r => { if(r.ok) _reload(); else alert(r.error); });
|
if (name?.trim()) _api({action:'create_folder',name:name.trim()}, r => { if(r.ok) _reload(); else vvAlert(r.error); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,11 +527,11 @@ function _showPopover(x, y) {
|
|||||||
const name = await vvPrompt('New folder name:');
|
const name = await vvPrompt('New folder name:');
|
||||||
if (!name?.trim()) return;
|
if (!name?.trim()) return;
|
||||||
_api({action:'create_folder',name:name.trim()}, r => {
|
_api({action:'create_folder',name:name.trim()}, r => {
|
||||||
if (!r.ok) { alert(r.error); return; }
|
if (!r.ok) { vvAlert(r.error); return; }
|
||||||
_api({action:'move_container',container:_popTarget.container,folder_id:r.id}, r2 => { if(r2.ok) _reload(); });
|
_api({action:'move_container',container:_popTarget.container,folder_id:r.id}, r2 => { if(r2.ok) _reload(); });
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_api({action:'move_container',container:_popTarget.container,folder_id:fid}, r => { if(r.ok) _reload(); else alert(r.error); });
|
_api({action:'move_container',container:_popTarget.container,folder_id:fid}, r => { if(r.ok) _reload(); else vvAlert(r.error); });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -555,12 +555,12 @@ document.getElementById('vv-dk-edit-toggle').addEventListener('click', function(
|
|||||||
});
|
});
|
||||||
|
|
||||||
function _syncC2J() {
|
function _syncC2J() {
|
||||||
_api({action:'sync_conf_to_json'}, r => { if(r.ok) _reload(); else alert(r.error); });
|
_api({action:'sync_conf_to_json'}, r => { if(r.ok) _reload(); else vvAlert(r.error); });
|
||||||
}
|
}
|
||||||
document.getElementById('vv-dk-sync-c2j').addEventListener('click', _syncC2J);
|
document.getElementById('vv-dk-sync-c2j').addEventListener('click', _syncC2J);
|
||||||
document.getElementById('vv-dk-sync-j2c').addEventListener('click', async () => {
|
document.getElementById('vv-dk-sync-j2c').addEventListener('click', async () => {
|
||||||
if (!await vvConfirm('Overwrite conf map with current JSON state?')) return;
|
if (!await vvConfirm('Overwrite conf map with current JSON state?')) return;
|
||||||
_api({action:'sync_json_to_conf'}, r => { if(r.ok) _reload(); else alert(r.error); });
|
_api({action:'sync_json_to_conf'}, r => { if(r.ok) _reload(); else vvAlert(r.error); });
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Load ──────────────────────────────────────────────────────────────────────
|
// ── Load ──────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -2636,14 +2636,14 @@ async function vvDockerAction(action, name, webui) {
|
|||||||
// The endpoint reports refusals as ok:false with a reason — container not found, a non-zero
|
// The endpoint reports refusals as ok:false with a reason — container not found, a non-zero
|
||||||
// docker exit. Discarding that made a failed stop look exactly like a successful one, since
|
// docker exit. Discarding that made a failed stop look exactly like a successful one, since
|
||||||
// the card it would have changed is redrawn from a payload either way.
|
// the card it would have changed is redrawn from a payload either way.
|
||||||
if (!d || !d.ok) alert('Container ' + action + ' failed: ' + ((d && (d.error || d.output)) || 'unknown error'));
|
if (!d || !d.ok) vvAlert('Container ' + action + ' failed: ' + ((d && (d.error || d.output)) || 'unknown error'));
|
||||||
vvDfActive = null;
|
vvDfActive = null;
|
||||||
// The endpoint drops the monitor cache on success, and this poll asks for a live collection
|
// The endpoint drops the monitor cache on success, and this poll asks for a live collection
|
||||||
// besides — either alone is enough, but between them the card cannot redraw itself from a
|
// besides — either alone is enough, but between them the card cannot redraw itself from a
|
||||||
// payload assembled before the action happened.
|
// payload assembled before the action happened.
|
||||||
setTimeout(() => vvPollMonitor(true), 1500);
|
setTimeout(() => vvPollMonitor(true), 1500);
|
||||||
})
|
})
|
||||||
.catch(() => alert('Container ' + action + ' failed: request error'));
|
.catch(() => vvAlert('Container ' + action + ' failed: request error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function vvRenderDockerFolders(data) {
|
function vvRenderDockerFolders(data) {
|
||||||
|
|||||||
@@ -215,12 +215,12 @@ function vvApiKey(btn) {
|
|||||||
if (d.ok) {
|
if (d.ok) {
|
||||||
if (_vvPtReload) _vvPtReload();
|
if (_vvPtReload) _vvPtReload();
|
||||||
} else {
|
} else {
|
||||||
alert('Failed: ' + (d.error ?? 'Unknown error'));
|
vvAlert('Failed: ' + (d.error ?? 'Unknown error'));
|
||||||
btn.disabled = false; btn.textContent = origText;
|
btn.disabled = false; btn.textContent = origText;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
alert('Error: ' + e);
|
vvAlert('Error: ' + e);
|
||||||
btn.disabled = false; btn.textContent = origText;
|
btn.disabled = false; btn.textContent = origText;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -230,8 +230,8 @@ async function vvPtPhase2(btn, hostId) {
|
|||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Starting…';
|
btn.textContent = '⟳ Starting…';
|
||||||
_vvPtRun('Partnership/partnership_onboard.sh', '--phase2-only')
|
_vvPtRun('Partnership/partnership_onboard.sh', '--phase2-only')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Run Phase 2 Manually'; }, 3000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Run Phase 2 Manually'; }, 3000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,8 +240,8 @@ async function vvPtOnboard(btn) {
|
|||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Starting…';
|
btn.textContent = '⟳ Starting…';
|
||||||
_vvPtRun('Partnership/partnership_onboard.sh')
|
_vvPtRun('Partnership/partnership_onboard.sh')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Onboard (Mirror)'; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Onboard (Mirror)'; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,8 +250,8 @@ async function vvPtPushConf(btn, hostId) {
|
|||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Pushing…';
|
btn.textContent = '⟳ Pushing…';
|
||||||
_vvPtRun('Partnership/partnership_onboard.sh', '--phase1-only --skip-ssh')
|
_vvPtRun('Partnership/partnership_onboard.sh', '--phase1-only --skip-ssh')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Push Conf (key installed)'; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Push Conf (key installed)'; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,8 +260,8 @@ async function vvPtLocalSetup(btn) {
|
|||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Running…';
|
btn.textContent = '⟳ Running…';
|
||||||
_vvPtRun('Partnership/partnership_manager.sh', '--onboard --local-only')
|
_vvPtRun('Partnership/partnership_manager.sh', '--onboard --local-only')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Complete HOST1 Setup'; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Complete HOST1 Setup'; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,8 +270,8 @@ async function vvPtCancel(btn, hostId) {
|
|||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Cancelling…';
|
btn.textContent = '⟳ Cancelling…';
|
||||||
_vvPtRun('Partnership/onboard_cancel.sh', '--direction=both')
|
_vvPtRun('Partnership/onboard_cancel.sh', '--direction=both')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '✕ Cancel'; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '✕ Cancel'; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,8 +279,8 @@ async function vvPtDeleteH1(btn, hostId) {
|
|||||||
if (!await vvConfirm(`Remove HOST1's key from ${hostId}?\n\n• Deletes local SSH key pair\n• Removes it from ${hostId}'s authorized_keys\n• Clears phase state`)) return;
|
if (!await vvConfirm(`Remove HOST1's key from ${hostId}?\n\n• Deletes local SSH key pair\n• Removes it from ${hostId}'s authorized_keys\n• Clears phase state`)) return;
|
||||||
btn.disabled = true; btn.textContent = '⟳ Removing…';
|
btn.disabled = true; btn.textContent = '⟳ Removing…';
|
||||||
_vvPtRun('Partnership/onboard_cancel.sh', '--direction=h1')
|
_vvPtRun('Partnership/onboard_cancel.sh', '--direction=h1')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '✕ Remove HOST1 key'; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '✕ Remove HOST1 key'; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,8 +288,8 @@ async function vvPtDeleteH2(btn, hostId) {
|
|||||||
if (!await vvConfirm(`Remove ${hostId}'s key from HOST1?\n\n• Removes ${hostId}'s public key from HOST1's authorized_keys\n• ${hostId} will no longer be able to SSH into HOST1`)) return;
|
if (!await vvConfirm(`Remove ${hostId}'s key from HOST1?\n\n• Removes ${hostId}'s public key from HOST1's authorized_keys\n• ${hostId} will no longer be able to SSH into HOST1`)) return;
|
||||||
btn.disabled = true; btn.textContent = '⟳ Removing…';
|
btn.disabled = true; btn.textContent = '⟳ Removing…';
|
||||||
_vvPtRun('Partnership/onboard_cancel.sh', '--direction=h2')
|
_vvPtRun('Partnership/onboard_cancel.sh', '--direction=h2')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = `✕ Remove ${hostId} key`; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = `✕ Remove ${hostId} key`; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,8 +299,8 @@ async function vvPtOffboard(btn) {
|
|||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Starting…';
|
btn.textContent = '⟳ Starting…';
|
||||||
_vvPtRun('Partnership/partnership_offboard.sh')
|
_vvPtRun('Partnership/partnership_offboard.sh')
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Offboard'; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '▶ Offboard'; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,8 +311,8 @@ async function vvPtTransfer(btn, token) {
|
|||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Transferring…';
|
btn.textContent = '⟳ Transferring…';
|
||||||
_vvPtRun('Partnership/partnership_transfer.sh', '--confirm=' + token)
|
_vvPtRun('Partnership/partnership_transfer.sh', '--confirm=' + token)
|
||||||
.then(d => { if (!d.ok) alert('Failed: ' + (d.error ?? 'Unknown error')); })
|
.then(d => { if (!d.ok) vvAlert('Failed: ' + (d.error ?? 'Unknown error')); })
|
||||||
.catch(e => alert('Error: ' + e))
|
.catch(e => vvAlert('Error: ' + e))
|
||||||
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '⇄ Transfer Ownership'; }, 4000));
|
.finally(() => setTimeout(() => { btn.disabled = false; btn.textContent = '⇄ Transfer Ownership'; }, 4000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,9 +349,9 @@ function vvPtToggleSync(el, varName, enabled) {
|
|||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(d => {
|
.then(d => {
|
||||||
if (d.ok) { if (_vvPtReload) _vvPtReload(); }
|
if (d.ok) { if (_vvPtReload) _vvPtReload(); }
|
||||||
else { alert('Failed: ' + (d.error ?? 'Unknown error')); el.style.pointerEvents = ''; el.style.opacity = ''; }
|
else { vvAlert('Failed: ' + (d.error ?? 'Unknown error')); el.style.pointerEvents = ''; el.style.opacity = ''; }
|
||||||
})
|
})
|
||||||
.catch(e => { alert('Error: ' + e); el.style.pointerEvents = ''; el.style.opacity = ''; });
|
.catch(e => { vvAlert('Error: ' + e); el.style.pointerEvents = ''; el.style.opacity = ''; });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Host Settings ─────────────────────────────────────────────────────────────
|
// ── Host Settings ─────────────────────────────────────────────────────────────
|
||||||
@@ -407,10 +407,10 @@ async function vvPtSaveHosts(btn) {
|
|||||||
setTimeout(() => { btn.textContent = 'Save'; btn.style.display = 'none'; }, 2000);
|
setTimeout(() => { btn.textContent = 'Save'; btn.style.display = 'none'; }, 2000);
|
||||||
} else {
|
} else {
|
||||||
btn.textContent = 'Save';
|
btn.textContent = 'Save';
|
||||||
alert('Save failed: ' + (d.error ?? 'Unknown error'));
|
vvAlert('Save failed: ' + (d.error ?? 'Unknown error'));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(e => { btn.disabled = false; btn.textContent = 'Save'; alert('Error: ' + e); });
|
.catch(e => { btn.disabled = false; btn.textContent = 'Save'; vvAlert('Error: ' + e); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Array settings cards ───────────────────────────────────────────────────────
|
// ── Array settings cards ───────────────────────────────────────────────────────
|
||||||
@@ -507,10 +507,10 @@ async function vvPtSaveArrays(btn) {
|
|||||||
setTimeout(() => _vvInitArrayCards(), 600);
|
setTimeout(() => _vvInitArrayCards(), 600);
|
||||||
} else {
|
} else {
|
||||||
btn.textContent = 'Save Changes';
|
btn.textContent = 'Save Changes';
|
||||||
alert('Save failed: ' + (d.error ?? 'Unknown error'));
|
vvAlert('Save failed: ' + (d.error ?? 'Unknown error'));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(e => { btn.disabled = false; btn.textContent = 'Save Changes'; alert('Error: ' + e); });
|
.catch(e => { btn.disabled = false; btn.textContent = 'Save Changes'; vvAlert('Error: ' + e); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Settings panel ─────────────────────────────────────────────────────────────
|
// ── Settings panel ─────────────────────────────────────────────────────────────
|
||||||
@@ -620,10 +620,10 @@ async function vvPtSaveSettings(btn) {
|
|||||||
setTimeout(() => { btn.textContent = 'Save Changes'; btn.style.display = 'none'; }, 2000);
|
setTimeout(() => { btn.textContent = 'Save Changes'; btn.style.display = 'none'; }, 2000);
|
||||||
} else {
|
} else {
|
||||||
btn.textContent = 'Save Changes';
|
btn.textContent = 'Save Changes';
|
||||||
alert('Save failed: ' + (d.error ?? 'Unknown error'));
|
vvAlert('Save failed: ' + (d.error ?? 'Unknown error'));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(e => { btn.disabled = false; btn.textContent = 'Save Changes'; alert('Error: ' + e); });
|
.catch(e => { btn.disabled = false; btn.textContent = 'Save Changes'; vvAlert('Error: ' + e); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Private page logic ─────────────────────────────────────────────────────────
|
// ── Private page logic ─────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -1755,9 +1755,9 @@ function vvMsRun() {
|
|||||||
const flags = Array.from(document.querySelectorAll('#vv-ms-card input[data-flag]:checked'))
|
const flags = Array.from(document.querySelectorAll('#vv-ms-card input[data-flag]:checked'))
|
||||||
.map(el => el.dataset.flag).join(' ');
|
.map(el => el.dataset.flag).join(' ');
|
||||||
|
|
||||||
if (!local) { alert('Enter a local source path.'); return; }
|
if (!local) { vvAlert('Enter a local source path.'); return; }
|
||||||
if (!slot) { alert('Select a remote server.'); return; }
|
if (!slot) { vvAlert('Select a remote server.'); return; }
|
||||||
if (!rpath) { alert('Enter a remote destination path.'); return; }
|
if (!rpath) { vvAlert('Enter a remote destination path.'); return; }
|
||||||
|
|
||||||
const btn = document.getElementById('vv-ms-run-btn');
|
const btn = document.getElementById('vv-ms-run-btn');
|
||||||
const stat = document.getElementById('vv-ms-run-status');
|
const stat = document.getElementById('vv-ms-run-status');
|
||||||
|
|||||||
@@ -1917,7 +1917,7 @@ async function vvSaveScript() {
|
|||||||
const name = document.getElementById('vv-editor-name').value.trim();
|
const name = document.getElementById('vv-editor-name').value.trim();
|
||||||
const content = document.getElementById('vv-editor-body').value;
|
const content = document.getElementById('vv-editor-body').value;
|
||||||
if (!name || !/^[a-zA-Z0-9_\-]+$/.test(name)) {
|
if (!name || !/^[a-zA-Z0-9_\-]+$/.test(name)) {
|
||||||
alert('Name must be letters, numbers, _ or - only (no spaces, no .sh)');
|
vvAlert('Name must be letters, numbers, _ or - only (no spaces, no .sh)');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!await vvConfirm('Save changes to "' + name + '.sh"?')) return;
|
if (!await vvConfirm('Save changes to "' + name + '.sh"?')) return;
|
||||||
@@ -1926,7 +1926,7 @@ async function vvSaveScript() {
|
|||||||
btn.textContent = 'Saving…';
|
btn.textContent = 'Saving…';
|
||||||
vvPost('/plugins/varaverk/api/script.php', {name, content})
|
vvPost('/plugins/varaverk/api/script.php', {name, content})
|
||||||
.then(d => {
|
.then(d => {
|
||||||
if (!d.ok) { alert('Save failed: ' + (d.error ?? 'Unknown error')); btn.disabled = false; btn.textContent = 'Save Script'; return; }
|
if (!d.ok) { vvAlert('Save failed: ' + (d.error ?? 'Unknown error')); btn.disabled = false; btn.textContent = 'Save Script'; return; }
|
||||||
localStorage.setItem('vv-last-job', d.id);
|
localStorage.setItem('vv-last-job', d.id);
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
})
|
})
|
||||||
@@ -1942,7 +1942,7 @@ async function vvDeleteScript() {
|
|||||||
btn.textContent = 'Deleting…';
|
btn.textContent = 'Deleting…';
|
||||||
vvPost('/plugins/varaverk/api/script.php', {action: 'delete', name})
|
vvPost('/plugins/varaverk/api/script.php', {action: 'delete', name})
|
||||||
.then(d => {
|
.then(d => {
|
||||||
if (!d.ok) { alert('Delete failed: ' + (d.error ?? 'Unknown error')); btn.disabled = false; btn.textContent = '\u{1F5D1} Delete'; return; }
|
if (!d.ok) { vvAlert('Delete failed: ' + (d.error ?? 'Unknown error')); btn.disabled = false; btn.textContent = '\u{1F5D1} Delete'; return; }
|
||||||
localStorage.removeItem('vv-last-job');
|
localStorage.removeItem('vv-last-job');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
})
|
})
|
||||||
@@ -2119,16 +2119,16 @@ async function _vvImpDoImport() {
|
|||||||
vvPost('/plugins/varaverk/api/import_script.php', {action: 'import', path: _vvImpSelected})
|
vvPost('/plugins/varaverk/api/import_script.php', {action: 'import', path: _vvImpSelected})
|
||||||
.then(d => {
|
.then(d => {
|
||||||
if (!d.ok) {
|
if (!d.ok) {
|
||||||
alert('Import failed: ' + (d.error || 'Unknown error'));
|
vvAlert('Import failed: ' + (d.error || 'Unknown error'));
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
btn.textContent = 'Import';
|
btn.textContent = 'Import';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (d.warning) alert(d.warning);
|
if (d.warning) vvAlert(d.warning);
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
alert('Import failed: ' + e);
|
vvAlert('Import failed: ' + e);
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
btn.textContent = 'Import';
|
btn.textContent = 'Import';
|
||||||
});
|
});
|
||||||
@@ -2270,7 +2270,7 @@ async function vvSaveConf() {
|
|||||||
setTimeout(() => { btn.textContent = 'Save Config'; }, 2500);
|
setTimeout(() => { btn.textContent = 'Save Config'; }, 2500);
|
||||||
} else {
|
} else {
|
||||||
btn.textContent = 'Save Config';
|
btn.textContent = 'Save Config';
|
||||||
alert('Save failed: ' + (d.error ?? 'Unknown error'));
|
vvAlert('Save failed: ' + (d.error ?? 'Unknown error'));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => { btn.disabled = false; btn.textContent = 'Save Config'; });
|
.catch(() => { btn.disabled = false; btn.textContent = 'Save Config'; });
|
||||||
@@ -3503,7 +3503,7 @@ async function vvSaveRawConf() {
|
|||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
if (!d.ok) {
|
if (!d.ok) {
|
||||||
btn.textContent = 'Save Conf';
|
btn.textContent = 'Save Conf';
|
||||||
alert('Save failed: ' + (d.error ?? 'Unknown error'));
|
vvAlert('Save failed: ' + (d.error ?? 'Unknown error'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4772,7 +4772,7 @@ async function _vvFolderDrop(e) {
|
|||||||
|
|
||||||
if (!r.ok) {
|
if (!r.ok) {
|
||||||
oldParent.appendChild(srcEl);
|
oldParent.appendChild(srcEl);
|
||||||
alert('Failed to save folder assignment.');
|
vvAlert('Failed to save folder assignment.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4921,12 +4921,12 @@ function vvNewFolder() {
|
|||||||
async function _vvDoCreateFolder(name, wrap) {
|
async function _vvDoCreateFolder(name, wrap) {
|
||||||
if (!name) return;
|
if (!name) return;
|
||||||
const folders = vvGetCurrentFolders();
|
const folders = vvGetCurrentFolders();
|
||||||
if (folders[name] !== undefined) { alert(`Folder "${name}" already exists.`); return; }
|
if (folders[name] !== undefined) { vvAlert(`Folder "${name}" already exists.`); return; }
|
||||||
folders[name] = [];
|
folders[name] = [];
|
||||||
const r = await vvPost('/plugins/varaverk/api/savefolders.php', {
|
const r = await vvPost('/plugins/varaverk/api/savefolders.php', {
|
||||||
folders: JSON.stringify(folders)
|
folders: JSON.stringify(folders)
|
||||||
}).then(r => r.json()).catch(() => ({ ok: false }));
|
}).then(r => r.json()).catch(() => ({ ok: false }));
|
||||||
if (!r.ok) { alert('Failed to create folder.'); return; }
|
if (!r.ok) { vvAlert('Failed to create folder.'); return; }
|
||||||
wrap.remove();
|
wrap.remove();
|
||||||
// Add folder group to DOM
|
// Add folder group to DOM
|
||||||
const customChildren = document.getElementById('vv-custom-children');
|
const customChildren = document.getElementById('vv-custom-children');
|
||||||
|
|||||||
Reference in New Issue
Block a user