From f03d46afb519a82e67fa61eb94c0871e0868bb50 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 16 May 2026 20:34:54 +0000 Subject: [PATCH] =?UTF-8?q?ui:=20Upload-Form=20&=20Jobs-Liste=20aufger?= =?UTF-8?q?=C3=A4umt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upload-Form: - Title-Label nicht mehr mit "(optional)" suffix — Hinweis wandert in den Placeholder. Labels haben jetzt einheitliches Spalten-Layout (flex-column + align-items: end), Inputs sind bündig - "Standard: X" Hinweis unter dem Profil entfernt (Dropdown ist selbst-erklärend, das Header-Dropdown zeigt's eh schon) Jobs-Liste: - Wenn kein Titel gesetzt ist, wird der Dateiname nur 1× als Titel gezeigt (vorher: groß als Titel + nochmal klein darunter) - Profile/Modell-Tags in eigene flex-Zeile statt margin-left-Hack - Dateiname-Zeile mit Ellipsis bei zu langen Namen - Tags 1px kleiner, weniger Padding - Datumsformat: heute → nur HH:MM, sonst dd.mm HH:MM (statt langem dd.mm.yyyy HH:MM:SS) — col-updated von 120px auf 78px geschrumpft - col-status von 110px auf 170px → Aktions-Buttons stapeln weniger Co-Authored-By: Claude Opus 4.7 (1M context) --- lxc-frontend/app/static/app.js | 27 ++++++++++--- lxc-frontend/app/static/index.html | 5 +-- lxc-frontend/app/static/style.css | 62 +++++++++++++++++++++++------- 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/lxc-frontend/app/static/app.js b/lxc-frontend/app/static/app.js index bf6ff3e..e5a2cd9 100644 --- a/lxc-frontend/app/static/app.js +++ b/lxc-frontend/app/static/app.js @@ -33,7 +33,6 @@ const usersBody = document.getElementById("users-body"); const profileLabel = document.getElementById("profile-label"); const profileSelect = document.getElementById("profile-select"); -const defaultProfileName = document.getElementById("default-profile-name"); const headerProfileWrap = document.getElementById("header-profile-wrap"); const headerProfile = document.getElementById("header-profile"); const headerModelWrap = document.getElementById("header-model-wrap"); @@ -77,7 +76,12 @@ function escapeHtml(s) { function fmtDate(s) { const d = new Date(s); - return d.toLocaleString("de-DE", { dateStyle: "short", timeStyle: "medium" }); + const now = new Date(); + const sameDay = d.toDateString() === now.toDateString(); + if (sameDay) { + return d.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }); + } + return d.toLocaleString("de-DE", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" }); } function fmtSecs(sec) { @@ -228,7 +232,6 @@ function applyProfileUI() { const def = currentUser.default_profile || "meeting"; profileSelect.value = def; headerProfile.value = def; - defaultProfileName.textContent = profileLabelOf(def); } async function loadModels() { @@ -306,7 +309,6 @@ headerProfile.addEventListener("change", async () => { currentUser = await r.json(); // Upload-Dropdown synchron mitziehen profileSelect.value = currentUser.default_profile; - defaultProfileName.textContent = profileLabelOf(currentUser.default_profile); } catch (e) { alert("Konnte Standard-Profil nicht speichern."); headerProfile.value = currentUser.default_profile || "meeting"; @@ -376,6 +378,9 @@ async function checkMac() { // ─── Jobs ────────────────────────────────────────────────────────────────── function row(job) { const tr = document.createElement("tr"); + // Wenn kein Titel gesetzt ist, zeigen wir den Dateinamen nur EINMAL als Titel — + // sonst doppelt (großer Titel + kleine muted-Zeile) und unnötig hässlich. + const hasRealTitle = !!job.title; const title = job.title || job.original_name; const dlCell = document.createElement("td"); @@ -395,7 +400,7 @@ function row(job) { }); const ownerLine = currentUser?.is_admin && job.owner_username - ? `
von ${escapeHtml(job.owner_username)}` + ? `
von ${escapeHtml(job.owner_username)}
` : ""; // Profile-Tag nur sichtbar wenn ≥2 Profile in der Auswahl ODER es ein anderes als "meeting" ist. @@ -423,9 +428,19 @@ function row(job) { ${runsButtonHtml(job)} `; + // Dateiname nur dann als zweite Zeile, wenn er sich vom angezeigten Titel unterscheidet. + const fileLine = hasRealTitle + ? `
${escapeHtml(job.original_name)}
` + : ""; + tr.innerHTML = ` #${job.id} - ${escapeHtml(title)} ${profileTag} ${modelTag}
${escapeHtml(job.original_name)}${ownerLine} + +
${escapeHtml(title)}
+
${profileTag}${modelTag}
+ ${fileLine} + ${ownerLine} + ${statusCell}
${job.progress}% ${fmtDate(job.updated_at)} diff --git a/lxc-frontend/app/static/index.html b/lxc-frontend/app/static/index.html index 7aa4b78..1d9d57c 100644 --- a/lxc-frontend/app/static/index.html +++ b/lxc-frontend/app/static/index.html @@ -95,11 +95,10 @@ diff --git a/lxc-frontend/app/static/style.css b/lxc-frontend/app/static/style.css index 1acbfd6..325ede5 100644 --- a/lxc-frontend/app/static/style.css +++ b/lxc-frontend/app/static/style.css @@ -96,15 +96,38 @@ table { width: 100%; border-collapse: collapse; font-size: 14px; table-layout: f th, td { padding: 10px 8px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; } th { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .5px; } -/* Spaltenbreiten — Status bleibt schmal, Downloads bekommen Platz */ -.col-id { width: 56px; } -.col-status { width: 110px; } -.col-progress { width: 120px; } -.col-updated { width: 120px; } +/* Spaltenbreiten — Status bekommt Platz für die Aktions-Buttons, + Updated wird schmaler weil das neue Format kürzer ist (Uhrzeit/dd.mm hh:mm) */ +.col-id { width: 52px; } +.col-status { width: 170px; } +.col-progress { width: 110px; } +.col-updated { width: 78px; } .col-dl { width: 320px; } /* col-title nimmt den Rest */ .col-title { word-break: break-word; } +.col-title .job-title { + font-weight: 500; + line-height: 1.35; + font-size: 14px; +} +.col-title .job-tags { + margin-top: 3px; + display: flex; + flex-wrap: wrap; + gap: 4px; +} +.col-title .job-tags:empty { display: none; } +.col-title .job-filename { + margin-top: 4px; + font-size: 11.5px; + font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 100%; +} +.col-title .job-owner { margin-top: 2px; font-size: 11.5px; } .status-pill { display: inline-block; @@ -368,6 +391,12 @@ select { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; + align-items: end; /* Labels unten bündig → Inputs auf gleicher Höhe */ +} +.upload-meta > label { + display: flex; + flex-direction: column; + gap: 4px; /* einheitlicher Abstand zwischen Label-Text und Control */ } .audio-file-details summary { cursor: pointer; @@ -547,34 +576,39 @@ select { .btn-retry:hover { background: rgba(241,196,15,.22); text-decoration: none; } .btn-retry:disabled { opacity: .55; cursor: not-allowed; } -/* Profile-Tag in der Job-Zeile */ +/* Profile-Tag in der Job-Zeile — kleiner & ohne Außenabstand, + weil sie jetzt in einem eigenen .job-tags-Container mit gap leben */ .tag-profile { display: inline-block; - padding: 1px 8px; - margin-left: 6px; + padding: 1px 7px; border-radius: 4px; background: rgba(46,204,113,.12); border: 1px solid rgba(46,204,113,.4); color: var(--ok); - font-size: 11px; + font-size: 10.5px; text-transform: lowercase; - vertical-align: middle; + line-height: 1.5; } /* Modell-Tag — gleicher Stil wie Profile-Tag, andere Farbe (lila) */ .tag-model { display: inline-block; - padding: 1px 8px; - margin-left: 4px; + padding: 1px 7px; border-radius: 4px; background: rgba(155,89,182,.10); border: 1px solid rgba(155,89,182,.4); color: #b07cd6; - font-size: 11px; + font-size: 10.5px; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; - vertical-align: middle; + line-height: 1.5; } +/* In der mobilen Karte (jc-title) sitzen Tags inline neben dem Titeltext — + dort brauchen sie etwas Luft nach links. In der Desktop-Tabelle stehen sie + im eigenen .job-tags-Container mit gap, dort kein margin nötig. */ +.jc-title .tag-profile, +.jc-title .tag-model { margin-left: 6px; } + /* Modal für Modell-Auswahl beim Reprocess */ dialog.model-picker { border: 1px solid rgba(255,255,255,.15);