Neue Helper: - _renderCardPreview(): Gemeinsamer Helper für Agent/Session-Card-Vorschau (ersetzt renderAgentInCard + renderSessionSelectCard Duplikate) - withButtonLoading(btn, text, fn): Eliminiert ~15x identisches disable/text/try/finally/reset Pattern in allen Pages - formatDate(): Nach ui-helpers.js verschoben (war in dashboard.js) - createMDE(): maxHeight-Option hinzugefügt Dedupliziert: - handleStreamEvent: 12 Preparer/Review/Finalizer cases → 7 durch case-Grouping (start/text/tool_use shared) - _escCmdAttr() entfernt → nutzt jetzt esc() aus ui-helpers.js - feInitEasyMDE() nutzt jetzt createMDE() statt eigener EasyMDE-Init Betroffene Dateien: ui-helpers.js, chat.js, commands-ui.js, file-explorer.js, dashboard.js, session-page.js, cronjob-page.js, profile-page.js, admin-page.js, server-settings-page.js, settings-page.js
133 lines
4.3 KiB
JavaScript
133 lines
4.3 KiB
JavaScript
// ── Server Settings Page (Admin) ──
|
|
|
|
registerPage('server-settings', {
|
|
async init() {
|
|
if (!currentUser || !currentUser.isAdmin) {
|
|
navigateTo('dashboard');
|
|
return;
|
|
}
|
|
|
|
var container = document.getElementById('serverSettingsFields');
|
|
var saveBtn = document.getElementById('serverSettingsSaveBtn');
|
|
var inputs = {};
|
|
|
|
// Settings laden und Formular aufbauen
|
|
try {
|
|
var result = await apiGetServerSettings();
|
|
var settings = result.settings;
|
|
|
|
for (var i = 0; i < settings.length; i++) {
|
|
var s = settings[i];
|
|
var field = document.createElement('div');
|
|
field.className = 'form-field';
|
|
|
|
var label = document.createElement('label');
|
|
label.textContent = s.label;
|
|
label.setAttribute('for', 'ss-' + s.key);
|
|
field.appendChild(label);
|
|
|
|
if (s.inputType === 'toggle') {
|
|
var toggleLabel = document.createElement('label');
|
|
toggleLabel.className = 'toggle-label';
|
|
|
|
var cb = document.createElement('input');
|
|
cb.type = 'checkbox';
|
|
cb.id = 'ss-' + s.key;
|
|
cb.checked = !!s.value;
|
|
inputs[s.key] = cb;
|
|
|
|
var span = document.createElement('span');
|
|
span.textContent = s.value ? 'Aktiviert' : 'Deaktiviert';
|
|
|
|
cb.addEventListener('change', (function(sp, checkbox) {
|
|
return function() { sp.textContent = checkbox.checked ? 'Aktiviert' : 'Deaktiviert'; };
|
|
})(span, cb));
|
|
|
|
toggleLabel.appendChild(cb);
|
|
toggleLabel.appendChild(span);
|
|
field.appendChild(toggleLabel);
|
|
} else if (s.inputType === 'password') {
|
|
var wrapper = document.createElement('div');
|
|
wrapper.className = 'input-with-btn';
|
|
|
|
var inp = document.createElement('input');
|
|
inp.type = 'password';
|
|
inp.id = 'ss-' + s.key;
|
|
inp.value = s.value || '';
|
|
inp.placeholder = s.label;
|
|
inp.autocomplete = 'off';
|
|
inputs[s.key] = inp;
|
|
|
|
var toggleBtn = document.createElement('button');
|
|
toggleBtn.type = 'button';
|
|
toggleBtn.className = 'icon-btn';
|
|
toggleBtn.innerHTML = '<i class="fa fa-eye"></i>';
|
|
toggleBtn.addEventListener('click', (function(input, btn) {
|
|
return function() {
|
|
if (input.type === 'password') {
|
|
input.type = 'text';
|
|
btn.innerHTML = '<i class="fa fa-eye-slash"></i>';
|
|
} else {
|
|
input.type = 'password';
|
|
btn.innerHTML = '<i class="fa fa-eye"></i>';
|
|
}
|
|
};
|
|
})(inp, toggleBtn));
|
|
|
|
wrapper.appendChild(inp);
|
|
wrapper.appendChild(toggleBtn);
|
|
field.appendChild(wrapper);
|
|
} else if (s.inputType === 'number') {
|
|
var inp = document.createElement('input');
|
|
inp.type = 'number';
|
|
inp.id = 'ss-' + s.key;
|
|
inp.value = s.value != null ? s.value : '';
|
|
inp.placeholder = s.label;
|
|
inputs[s.key] = inp;
|
|
field.appendChild(inp);
|
|
} else {
|
|
var inp = document.createElement('input');
|
|
inp.type = 'text';
|
|
inp.id = 'ss-' + s.key;
|
|
inp.value = s.value || '';
|
|
inp.placeholder = s.label;
|
|
inputs[s.key] = inp;
|
|
field.appendChild(inp);
|
|
}
|
|
|
|
container.appendChild(field);
|
|
}
|
|
|
|
// Speichern
|
|
saveBtn.addEventListener('click', () => withButtonLoading(saveBtn, 'Speichern...', async () => {
|
|
try {
|
|
var data = {};
|
|
for (var j = 0; j < settings.length; j++) {
|
|
var def = settings[j];
|
|
var input = inputs[def.key];
|
|
if (!input) continue;
|
|
|
|
if (def.type === 'bool') {
|
|
data[def.key] = input.checked;
|
|
} else if (def.type === 'int') {
|
|
data[def.key] = parseInt(input.value, 10) || 0;
|
|
} else {
|
|
data[def.key] = input.value;
|
|
}
|
|
}
|
|
|
|
var result = await apiSaveServerSettings(data);
|
|
showToast(result.hint || 'Einstellungen gespeichert');
|
|
} catch (err) {
|
|
showToast(err.message, 'error');
|
|
}
|
|
}));
|
|
|
|
} catch (err) {
|
|
container.innerHTML = '<p class="form-error">Fehler beim Laden: ' + esc(err.message) + '</p>';
|
|
}
|
|
},
|
|
|
|
destroy() {}
|
|
});
|