var pathArray = window.location.pathname.split('/'); var appName = pathArray[2]; var urlParams = new URLSearchParams(window.location.search); var jobId = urlParams.get('jobId'); if (!getCookie("id")) { var randomNumber = Math.random().toString().substring(2); fetch('/CollabCentral/' + appName + '/authUrl') .then(res => res.text()) .then(res => { window.location.href = res + randomNumber; }); } else { bootstrap(); } function bootstrap() { fetch('/CollabCentral/' + appName + '/info') .then(res => res.json()) .then(info => { document.title = info.label + " — Job #" + (jobId || "?"); document.getElementById("appLabel").innerHTML = info.label; document.getElementById("name").innerHTML = getCookie("displayName") || ""; document.getElementById("appName").href = info.faviconUrl; document.getElementById("jobLink").href = "/CollabCentral/" + appName + "/monitorJobs.html"; var appIcon = document.getElementById("appIcon"); appIcon.src = info.iconUrl; appIcon.style.maxHeight = "150px"; appIcon.style.maxWidth = "150px"; if (!info.authorized) { document.getElementById("unauthorizedPanel").classList.remove("hidden"); return; } loadJobDetail(); }) .catch(err => console.error("Failed to load /info:", err)); } function loadJobDetail() { if (!jobId) { document.getElementById("notFoundPanel").classList.remove("hidden"); return; } fetch('/CollabCentral/' + appName + '/jobs/detail/' + encodeURIComponent(jobId)) .then(res => { if (res.status === 404) { document.getElementById("notFoundPanel").classList.remove("hidden"); return null; } if (!res.ok) throw new Error("HTTP " + res.status); return res.json(); }) .then(job => { if (!job) return; renderJob(job); document.getElementById("detailPanel").classList.remove("hidden"); }) .catch(err => { console.error("Failed to load job detail:", err); document.getElementById("notFoundPanel").classList.remove("hidden"); }); } function renderJob(job) { document.getElementById("jobTitle").textContent = "Job #" + (job.jobId || "?"); var subtitle = "Sent by " + (job.senderDisplayName || "unknown"); if (job.startTime) subtitle += " · started " + formatDate(job.startTime); document.getElementById("subtitle").textContent = subtitle; var dl = document.getElementById("summaryGrid"); dl.innerHTML = ""; var stats = job.stats || {}; var rows = [ ["Job ID", job.jobId], ["Submitted by", job.senderDisplayName], ["Scheduled for", job.scheduledFor ? formatDate(job.scheduledFor) : "Sent immediately"], ["Started", formatDate(job.startTime)], ["Completed", job.endTime ? formatDate(job.endTime) : "In progress"], ["Total duration", stats.totalTime], ["Webex time", stats.webexTime], ["Average per message", stats.averageTime], ["Recipients", (job.memberList || []).length], ["Delivered", formatSuccess(stats)] ]; for (var i = 0; i < rows.length; i++) { var key = rows[i][0], val = rows[i][1]; if (val === undefined || val === null || val === "") continue; var dt = document.createElement("dt"); dt.textContent = key; var dd = document.createElement("dd"); dd.textContent = val; dl.appendChild(dt); dl.appendChild(dd); } var preview = document.getElementById("messagePreview"); var msg = (job.message && job.message.english) || job.message || {}; if (msg.html) { preview.innerHTML = msg.html; } else if (msg.markdown) { preview.textContent = msg.markdown; } else if (msg.text) { preview.textContent = msg.text; } else if (typeof msg.raw === "string") { preview.textContent = msg.raw; } else { preview.innerHTML = "No message content available."; } var members = job.memberList || []; document.getElementById("recipientCount").textContent = members.length; $('#recipients').dataTable({ data: members.map(formatRecipientRow), columns: [ { data: 'displayName' }, { data: 'email' }, { data: 'status' }, { data: 'time' }, { data: 'error' } ], pageLength: 50, lengthMenu: [25, 50, 100, 250], order: [[2, 'asc']], searching: true, info: true, paging: true }); } function formatRecipientRow(m) { var result = m.results || null; var status; var email = "—"; var err = ""; if (!result) { status = 'Pending'; } else if (result.id && !result.message && !result.errors) { status = 'Delivered'; email = result.toPersonEmail || email; } else { status = 'Failed'; email = result.toPersonEmail || email; if (result.message) err = result.message; else if (result.errors && result.errors.length) { err = result.errors.map(function (e) { return e.description || e.code || JSON.stringify(e); }).join("; "); } } return { displayName: m.displayName || "—", email: email, status: status, time: m.msgTime ? (m.msgTime / 1000).toFixed(2) + " s" : "—", error: err }; } function formatSuccess(stats) { if (!stats || stats.succeededMsgs === undefined) return null; var pct = (typeof stats.succeededMsgPct === "number") ? stats.succeededMsgPct.toFixed(1) : stats.succeededMsgPct; return stats.succeededMsgs + " / " + stats.totalMsgs + " (" + pct + "%)"; } function formatDate(d) { if (!d) return null; try { return new Date(d).toLocaleString(); } catch (e) { return d; } } function getCookie(cname) { let name = cname + "="; let decodedCookie = decodeURIComponent(document.cookie); let ca = decodedCookie.split(';'); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1); if (c.indexOf(name) == 0) return c.substring(name.length, c.length); } return ""; }