feat(org-detail): Max Nutzer inline editierbar, Org-Status in die Kopfzeile
Zwei Verbesserungen auf Nutzer-Rückmeldung. - Max Nutzer war nach dem Anlegen einer Lizenz nirgends mehr änderbar. In der aktiven Lizenz-Zeile ist es jetzt ein Zahlenfeld mit Sofort-Speicherung (der generische Lizenz-Updater akzeptiert max_users mit Prüfung 1 bis 1000), die Limit-Anzeige über der Nutzerliste zieht mit. - "Status" (Lizenz) direkt neben "Org-Status" war verwirrend. Der Org-Status sitzt jetzt als Umschalter in der Kopfzeile der Organisation (an der Stelle des bisherigen Abzeichens), die Tabelle behält nur noch Lizenz-Status und Pipeline-Sprache. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -230,7 +230,6 @@
|
||||
<th>Gültig ab</th>
|
||||
<th>Gültig bis</th>
|
||||
<th>Status</th>
|
||||
<th>Org-Status</th>
|
||||
<th>Pipeline-Sprache</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
@@ -1163,7 +1162,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/static/js/a11y.js?v=20260725a"></script>
|
||||
<script src="/static/js/app.js?v=20260725h"></script>
|
||||
<script src="/static/js/app.js?v=20260725i"></script>
|
||||
<script src="/static/js/sources.js?v=20260522x2"></script>
|
||||
<script src="/static/js/x-scraper.js?v=20260522a"></script>
|
||||
<script src="/static/js/source-health.js?v=20260509l"></script>
|
||||
|
||||
@@ -314,7 +314,13 @@ function renderOrgHeader(org) {
|
||||
document.getElementById("orgDetailHeader").innerHTML = `
|
||||
<div style="display:flex; align-items:flex-start; gap:10px; flex-wrap:wrap;">
|
||||
<div style="flex:1; min-width:260px;">
|
||||
<h2>${esc(org.name)} <span class="badge badge-${org.is_active ? 'active' : 'inactive'}" style="font-size: 12px; vertical-align: middle;">${org.is_active ? "Aktiv" : "Inaktiv"}</span></h2>
|
||||
<h2 style="display:flex; align-items:center; gap:10px; flex-wrap:wrap;">${esc(org.name)}
|
||||
<select onchange="setOrgActive(this.value)" title="Status der Organisation, speichert sofort"
|
||||
style="width:auto; font-size:13px; padding:4px 8px;">
|
||||
<option value="true"${org.is_active ? " selected" : ""}>Aktiv</option>
|
||||
<option value="false"${org.is_active ? "" : " selected"}>Deaktiviert</option>
|
||||
</select>
|
||||
</h2>
|
||||
<div class="text-secondary mt-8">Slug: ${esc(org.slug)} | Nutzer: ${org.user_count} | Lizenz: ${org.license_type || "Keine"} | Kontingent: <span id="orgKpiCredits">${esc(kpiText)}</span></div>
|
||||
</div>
|
||||
<button class="btn btn-secondary btn-small" onclick="renameOrg()" title="Organisation umbenennen">
|
||||
@@ -375,6 +381,25 @@ function setOrgLanguage(wert) {
|
||||
_saveOrgSetting({ output_language: wert }, "Pipeline-Sprache gespeichert");
|
||||
}
|
||||
|
||||
// Max Nutzer der aktiven Lizenz direkt in der Tabelle ändern
|
||||
async function setLicenseMaxUsers(licId, wert) {
|
||||
const n = parseInt(wert, 10);
|
||||
if (!n || n < 1 || n > 1000) {
|
||||
showToast("Max Nutzer muss zwischen 1 und 1000 liegen", "error");
|
||||
loadOrgLicenses(currentOrgId);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await API.put(`/api/token-usage/budget/${licId}`, { max_users: n });
|
||||
showToast("Maximale Nutzerzahl gespeichert", "success");
|
||||
loadOrgLicenses(currentOrgId);
|
||||
loadOrgUsers(currentOrgId); // Limit-Anzeige über der Nutzerliste zieht mit
|
||||
} catch (err) {
|
||||
showToast(err.message, "error");
|
||||
loadOrgLicenses(currentOrgId);
|
||||
}
|
||||
}
|
||||
|
||||
function renameOrg() {
|
||||
const input = document.getElementById("renameOrgName");
|
||||
const errEl = document.getElementById("renameOrgError");
|
||||
@@ -506,17 +531,13 @@ async function loadOrgLicenses(orgId) {
|
||||
const licenses = await API.get(`/api/licenses?org_id=${orgId}`);
|
||||
const tbody = document.getElementById("licenseTable");
|
||||
if (licenses.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="text-muted">Keine Lizenzen</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="7" class="text-muted">Keine Lizenzen</td></tr>';
|
||||
return;
|
||||
}
|
||||
// Org-Status und Pipeline-Sprache sind Org-Einstellungen und stehen nur in
|
||||
// der aktiven Zeile, direkt umschaltbar (Sofort-Speicherung).
|
||||
// Pipeline-Sprache ist eine Org-Einstellung und steht nur in der aktiven
|
||||
// Zeile (Sofort-Speicherung). Max Nutzer ist dort direkt editierbar.
|
||||
const org = currentOrgData || {};
|
||||
const orgZellen = `
|
||||
<td><select style="width:auto; min-width:110px;" onchange="setOrgActive(this.value)">
|
||||
<option value="true"${org.is_active ? " selected" : ""}>Aktiv</option>
|
||||
<option value="false"${org.is_active ? "" : " selected"}>Deaktiviert</option>
|
||||
</select></td>
|
||||
const spracheZelle = `
|
||||
<td><select style="width:auto; min-width:100px;" onchange="setOrgLanguage(this.value)" title="Ausgabesprache der KI-Pipeline für alle Nutzer dieser Organisation">
|
||||
<option value="de"${(org.output_language || "de") === "de" ? " selected" : ""}>Deutsch</option>
|
||||
<option value="en"${org.output_language === "en" ? " selected" : ""}>English</option>
|
||||
@@ -524,11 +545,14 @@ async function loadOrgLicenses(orgId) {
|
||||
tbody.innerHTML = licenses.map(l => `
|
||||
<tr>
|
||||
<td><span class="badge badge-${l.license_type}">${l.license_type}</span></td>
|
||||
<td>${l.max_users}</td>
|
||||
<td>${l.status === "active"
|
||||
? `<input type="number" value="${l.max_users}" min="1" max="1000" style="width:70px;"
|
||||
onchange="setLicenseMaxUsers(${l.id}, this.value)" title="Maximale Nutzerzahl, speichert sofort">`
|
||||
: l.max_users}</td>
|
||||
<td>${formatDate(l.valid_from)}</td>
|
||||
<td>${l.valid_until ? formatDate(l.valid_until) : "Unbegrenzt"}</td>
|
||||
<td><span class="badge badge-${l.status}">${l.status}</span></td>
|
||||
${l.status === "active" ? orgZellen : '<td class="text-muted">–</td><td class="text-muted">–</td>'}
|
||||
${l.status === "active" ? spracheZelle : '<td class="text-muted">–</td>'}
|
||||
<td>
|
||||
${l.status === "active" ? `
|
||||
<button class="btn btn-secondary btn-small" onclick="extendLicense(${l.id})">Verlängern</button>
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren