fix: admin buttons persist on profile after import/use
The showUser() function was setting detailActions to empty string instead of rendering the admin buttons (Change Password, Load Seed Protocols, Import YAML Files). Now properly renders buttons every time the profile loads, so they persist after import operations. Also restores the missing JS functions: importYamlToForm, bulkImportYaml, showChangePassword, handleChangePassword, loadSeedProtocols, closePwModal.
This commit is contained in:
+93
-2
@@ -107,7 +107,7 @@ function navigate(view) {
|
||||
// --- Mobile menu ---
|
||||
function updateBreadcrumb(view) {
|
||||
const path = document.getElementById('crumbPath');
|
||||
const map = { library: 'protocols/', create: 'protocols/create', collections: 'collections/', 'create-collection': 'collections/create', about: 'about' };
|
||||
const map = { library: '', create: 'create', collections: 'collections/', 'create-collection': 'collections/create', about: 'about' };
|
||||
path.textContent = map[view] || '';
|
||||
}
|
||||
|
||||
@@ -815,12 +815,103 @@ async function showUser(username) {
|
||||
'<div class="info"><h3>' + escapeHtml(col.title) + '</h3><p>' + escapeHtml(col.description||'') + '</p></div></div>';
|
||||
}).join('') +
|
||||
'</div>' : '');
|
||||
document.getElementById('detailActions').innerHTML = '';
|
||||
// Add actions if viewing own profile
|
||||
var actionsHtml = '';
|
||||
if (currentUser && currentUser.username === username) {
|
||||
actionsHtml = '<button class="btn" onclick="showChangePassword()">Change Password</button>';
|
||||
if (currentUser.role === 'admin') {
|
||||
actionsHtml += '<button class="btn primary" id="seedBtn" onclick="loadSeedProtocols()">Load Seed Protocols</button>';
|
||||
actionsHtml += '<button class="btn" onclick="document.getElementById(\'bulkImportFile\').click()">Import YAML Files</button>';
|
||||
actionsHtml += '<input type="file" id="bulkImportFile" accept=".yaml,.yml" multiple style="display:none" onchange="bulkImportYaml(event)">';
|
||||
}
|
||||
}
|
||||
document.getElementById('detailActions').innerHTML = actionsHtml;
|
||||
} catch (e) {
|
||||
document.getElementById('detailContent').innerHTML = '<div class="empty">User not found</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// --- Import YAML to form ---
|
||||
async function importYamlToForm(event) {
|
||||
var file = event.target.files[0];
|
||||
if (!file) return;
|
||||
event.target.value = '';
|
||||
try {
|
||||
var text = await file.text();
|
||||
var result = await api('/import', { method: 'POST', body: JSON.stringify({ yaml: text }) });
|
||||
toast('Imported: ' + result.slug + ' — review and save');
|
||||
editProtocol(result.slug);
|
||||
} catch (err) {
|
||||
toast('Import failed: ' + err.message, true);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Bulk import YAML files (admin) ---
|
||||
async function bulkImportYaml(event) {
|
||||
var files = event.target.files;
|
||||
if (!files || !files.length) return;
|
||||
event.target.value = '';
|
||||
var imported = 0;
|
||||
var failed = 0;
|
||||
var errors = [];
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
try {
|
||||
var text = await files[i].text();
|
||||
await api('/import', { method: 'POST', body: JSON.stringify({ yaml: text }) });
|
||||
imported++;
|
||||
} catch (err) {
|
||||
failed++;
|
||||
errors.push(files[i].name + ': ' + err.message);
|
||||
}
|
||||
}
|
||||
var msg = 'Imported ' + imported + ' protocol' + (imported !== 1 ? 's' : '');
|
||||
if (failed > 0) {
|
||||
msg += ', ' + failed + ' failed: ' + errors.join('; ');
|
||||
toast(msg, true);
|
||||
} else {
|
||||
toast(msg);
|
||||
}
|
||||
if (currentUser) showUser(currentUser.username);
|
||||
}
|
||||
|
||||
// --- Password change ---
|
||||
function showChangePassword() {
|
||||
document.getElementById('pwModal').style.display = 'flex';
|
||||
}
|
||||
function closePwModal() { document.getElementById('pwModal').style.display = 'none'; }
|
||||
|
||||
async function handleChangePassword(e) {
|
||||
e.preventDefault();
|
||||
var current = document.getElementById('pwCurrent').value;
|
||||
var newPassword = document.getElementById('pwNew').value;
|
||||
var confirmPw = document.getElementById('pwConfirm').value;
|
||||
if (newPassword !== confirmPw) { toast('Passwords do not match', true); return; }
|
||||
if (newPassword.length < 8) { toast('Password must be at least 8 characters', true); return; }
|
||||
try {
|
||||
await api('/auth/password', { method: 'POST', body: JSON.stringify({ current_password: current, new_password: newPassword }) });
|
||||
toast('Password changed');
|
||||
closePwModal();
|
||||
document.getElementById('pwForm').reset();
|
||||
} catch (err) {
|
||||
toast(err.message, true);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Seed protocols ---
|
||||
async function loadSeedProtocols() {
|
||||
var btn = document.getElementById('seedBtn');
|
||||
if (btn) { btn.disabled = true; btn.textContent = 'Loading...'; }
|
||||
try {
|
||||
var result = await api('/seed', { method: 'POST' });
|
||||
toast('Loaded ' + result.imported + ' seed protocols');
|
||||
if (btn) { btn.textContent = 'Load Seed Protocols'; btn.disabled = false; }
|
||||
showUser(currentUser.username);
|
||||
} catch (e) {
|
||||
toast(e.message, true);
|
||||
if (btn) { btn.textContent = 'Load Seed Protocols'; btn.disabled = false; }
|
||||
}
|
||||
}
|
||||
|
||||
// --- Toast ---
|
||||
let toastTimer = null;
|
||||
function toast(msg, isError) {
|
||||
|
||||
Reference in New Issue
Block a user