Promote develop → main (2026-07-25 22:22 UTC) #16
@@ -118,7 +118,6 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Slug</th>
|
||||
<th>Nutzer</th>
|
||||
<th>Lizenz</th>
|
||||
<th>Kontingent</th>
|
||||
@@ -523,10 +522,7 @@
|
||||
<label for="newOrgName">Name</label>
|
||||
<input type="text" id="newOrgName" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="newOrgSlug">Slug (URL-freundlich)</label>
|
||||
<input type="text" id="newOrgSlug" required pattern="[a-z0-9-]+" placeholder="z.B. bundespolizei">
|
||||
</div>
|
||||
<input type="hidden" id="newOrgSlug">
|
||||
<div class="form-group">
|
||||
<label for="newOrgLanguage">Pipeline-Sprache</label>
|
||||
<select id="newOrgLanguage">
|
||||
@@ -1109,7 +1105,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/static/js/a11y.js?v=20260725a"></script>
|
||||
<script src="/static/js/app.js?v=20260725q"></script>
|
||||
<script src="/static/js/app.js?v=20260725r"></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>
|
||||
|
||||
@@ -253,13 +253,12 @@ function orgUsageCell(orgId) {
|
||||
function renderOrgTable(orgs) {
|
||||
const tbody = document.getElementById("orgTable");
|
||||
if (orgs.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" class="text-muted">Keine Organisationen</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="6" class="text-muted">Keine Organisationen</td></tr>';
|
||||
return;
|
||||
}
|
||||
tbody.innerHTML = orgs.map(o => `
|
||||
<tr class="org-row" onclick="openOrg(${o.id})" title="Organisation öffnen">
|
||||
<td><a href="#" class="text-accent" style="text-decoration: none;" onclick="openOrg(${o.id}); return false;">${esc(o.name)}</a></td>
|
||||
<td class="text-secondary">${esc(o.slug)}</td>
|
||||
<td>${o.user_count}</td>
|
||||
<td><span class="badge badge-${o.license_type || 'none'}">${o.license_type || "Keine"}</span></td>
|
||||
<td>${orgUsageCell(o.id)}</td>
|
||||
@@ -289,8 +288,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
let currentOrgData = null; // zuletzt geladene Org (fuer Inline-Einstellungen)
|
||||
|
||||
function renderOrgHeader(org) {
|
||||
const kpiAlt = document.getElementById("orgKpiCredits");
|
||||
const kpiText = kpiAlt ? kpiAlt.textContent : "wird geladen …";
|
||||
document.getElementById("orgDetailHeader").innerHTML = `
|
||||
<div style="display:flex; align-items:flex-start; gap:10px; flex-wrap:wrap;">
|
||||
<div style="flex:1; min-width:260px;">
|
||||
@@ -306,7 +303,6 @@ function renderOrgHeader(org) {
|
||||
</button>
|
||||
</div>
|
||||
</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">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg>
|
||||
@@ -668,9 +664,13 @@ function setupForms() {
|
||||
e.preventDefault();
|
||||
const errEl = document.getElementById("newOrgError");
|
||||
errEl.style.display = "none";
|
||||
// Slug wird unsichtbar aus dem Namen erzeugt, bei Kollision haengt der
|
||||
// Submit-Handler unten selbststaendig eine Nummer an.
|
||||
const baseSlug = (document.getElementById("newOrgSlug").value ||
|
||||
document.getElementById("newOrgName").value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")) || "organisation";
|
||||
const body = {
|
||||
name: document.getElementById("newOrgName").value,
|
||||
slug: document.getElementById("newOrgSlug").value,
|
||||
slug: baseSlug,
|
||||
output_language: document.getElementById("newOrgLanguage").value || "de",
|
||||
};
|
||||
// Optional direkt eine Lizenz mit Credits-Kontingent mitgeben
|
||||
@@ -698,7 +698,16 @@ function setupForms() {
|
||||
body.license = lic;
|
||||
}
|
||||
try {
|
||||
await API.post("/api/orgs", body);
|
||||
let angelegt = false;
|
||||
for (let i = 0; i < 8 && !angelegt; i++) {
|
||||
body.slug = i === 0 ? baseSlug : baseSlug + "-" + (i + 1);
|
||||
try {
|
||||
await API.post("/api/orgs", body);
|
||||
angelegt = true;
|
||||
} catch (err) {
|
||||
if (!(err.message || "").includes("Slug bereits vergeben") || i === 7) throw err;
|
||||
}
|
||||
}
|
||||
closeModal("modalNewOrg");
|
||||
document.getElementById("newOrgForm").reset();
|
||||
onNewOrgLicenseToggle();
|
||||
@@ -1100,16 +1109,6 @@ async function loadOrgTokenUsage(orgId) {
|
||||
|
||||
fillBudgetForm(budget);
|
||||
|
||||
// Kontingent-Kurzinfo im Org-Kopf
|
||||
const kpi = document.getElementById("orgKpiCredits");
|
||||
if (kpi) {
|
||||
if (unlimited) kpi.textContent = "unbegrenzt";
|
||||
else if (budget.credits_available) {
|
||||
const pct = budget.credits_percent_used != null ? ` (${budget.credits_percent_used.toFixed(0)}% verbraucht)` : "";
|
||||
kpi.textContent = `${Math.round(budget.credits_used || 0).toLocaleString("de-DE")} von ${Math.round(budget.credits_available).toLocaleString("de-DE")} Credits${pct}`;
|
||||
} else kpi.textContent = "kein Kontingent";
|
||||
}
|
||||
|
||||
const tbody = document.getElementById('tokenMonthlyTable');
|
||||
if (tbody) {
|
||||
tbody.innerHTML = monthly.map(function(m) {
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren