diff --git a/lxc-frontend/app/static/app.js b/lxc-frontend/app/static/app.js
index 719bd9d..d4e9d55 100644
--- a/lxc-frontend/app/static/app.js
+++ b/lxc-frontend/app/static/app.js
@@ -37,6 +37,10 @@ const defaultProfileName = document.getElementById("default-profile-name");
const headerProfileWrap = document.getElementById("header-profile-wrap");
const headerProfile = document.getElementById("header-profile");
+const jobsCards = document.getElementById("jobs-cards");
+const adminToggle = document.getElementById("admin-toggle");
+const adminCollapsible = document.getElementById("admin-card");
+
const recordToggle = document.getElementById("record-toggle");
const recordToggleLabel = document.getElementById("record-toggle-label");
const recordPane = document.getElementById("record-pane");
@@ -302,6 +306,43 @@ function row(job) {
return tr;
}
+function card(job) {
+ const div = document.createElement("div");
+ div.className = "jc";
+ const title = job.title || job.original_name;
+ const showProfileTag = availableProfiles.length > 1 || (job.profile && job.profile !== "meeting");
+ const profileTag = showProfileTag
+ ? `${escapeHtml(profileLabelOf(job.profile || "meeting"))}`
+ : "";
+ const ownerLine = currentUser?.is_admin && job.owner_username
+ ? `
von ${escapeHtml(job.owner_username)}
` : "";
+
+ const dlButtons = DOWNLOADS.map(({ kind, label, title: tip }) => {
+ const dis = !job.has[kind];
+ const href = dis ? "" : `href="/api/jobs/${job.id}/download/${kind}"`;
+ return `${label}`;
+ }).join("");
+
+ div.innerHTML = `
+
+
+
${escapeHtml(title)} ${profileTag}
+
${escapeHtml(job.original_name)} · #${job.id}
+ ${ownerLine}
+
+
${escapeHtml(job.status)}
+
+
+ ${job.error ? `${escapeHtml(job.error)}
` : ""}
+ aktualisiert: ${escapeHtml(fmtDate(job.updated_at))}
+ ${dlButtons}
+ `;
+ return div;
+}
+
async function loadJobs() {
if (!currentUser) return;
try {
@@ -309,11 +350,16 @@ async function loadJobs() {
if (r.status === 401) { showAuth("login"); return; }
const jobs = await r.json();
jobsBody.innerHTML = "";
+ jobsCards.innerHTML = "";
if (!jobs.length) {
jobsBody.innerHTML = '| Noch keine Jobs. |
';
+ jobsCards.innerHTML = 'Noch keine Jobs.
';
return;
}
- jobs.forEach((j) => jobsBody.appendChild(row(j)));
+ jobs.forEach((j) => {
+ jobsBody.appendChild(row(j));
+ jobsCards.appendChild(card(j));
+ });
} catch (e) {
console.error(e);
}
@@ -613,6 +659,13 @@ recPauseBtn.addEventListener("click", pauseRecording);
recStopBtn.addEventListener("click", stopRecording);
recordDiscardBtn.addEventListener("click", discardRecording);
+// Admin-Toggle (klappbar auf Mobile, immer offen auf Desktop)
+adminToggle.addEventListener("click", () => {
+ if (window.matchMedia("(max-width: 700px)").matches) {
+ adminCollapsible.classList.toggle("open");
+ }
+});
+
// ─── Init ──────────────────────────────────────────────────────────────────
bootstrap();
checkMac();
diff --git a/lxc-frontend/app/static/index.html b/lxc-frontend/app/static/index.html
index 58eeb39..0bf8f40 100644
--- a/lxc-frontend/app/static/index.html
+++ b/lxc-frontend/app/static/index.html
@@ -19,17 +19,17 @@