(() => { const operationCard = document.querySelector("[data-operation-url]"); if (operationCard) { const stageNode = document.getElementById("operation-stage"); const detailNode = document.getElementById("operation-detail"); const errorNode = document.getElementById("operation-error"); const logNode = document.getElementById("operation-log"); const statusUrl = operationCard.dataset.operationUrl; const successUrl = operationCard.dataset.operationSuccess; const poll = async () => { const response = await fetch(statusUrl, { headers: { Accept: "application/json" } }); if (!response.ok) { return; } const payload = await response.json(); const op = payload.operation || {}; if (stageNode) stageNode.textContent = op.stage || "queued"; if (detailNode) detailNode.textContent = op.detail || ""; if (errorNode) errorNode.textContent = op.error || ""; if (logNode && op.build_log_path) logNode.textContent = op.build_log_path; if (op.done && op.success && successUrl) { window.location.assign(successUrl); return; } if (!op.done) { window.setTimeout(poll, 1000); } }; window.setTimeout(poll, 800); } const copyButtons = document.querySelectorAll("[data-copy-text]"); copyButtons.forEach((button) => { button.addEventListener("click", async () => { try { await navigator.clipboard.writeText(button.dataset.copyText || ""); button.textContent = "Copied"; window.setTimeout(() => { button.textContent = "Copy"; }, 1000); } catch (_) {} }); }); document.querySelectorAll("form[data-confirm]").forEach((form) => { form.addEventListener("submit", (event) => { const message = form.dataset.confirm || "Are you sure?"; if (!window.confirm(message)) { event.preventDefault(); } }); }); const logToggle = document.getElementById("log-auto-refresh"); if (logToggle) { const schedule = () => { if (!logToggle.checked) return; window.setTimeout(() => { if (logToggle.checked) { window.location.reload(); } }, 4000); }; logToggle.addEventListener("change", schedule); schedule(); } const dialog = document.getElementById("path-picker"); if (!dialog) return; const listNode = document.getElementById("picker-list"); const currentPathNode = document.getElementById("picker-current-path"); const closeButton = document.getElementById("picker-close"); const selectCurrentButton = document.getElementById("picker-select-current"); let currentInput = null; let currentKind = "file"; let currentPath = "/"; const loadListing = async (path) => { const response = await fetch(`/api/fs?path=${encodeURIComponent(path)}&kind=${encodeURIComponent(currentKind)}`, { headers: { Accept: "application/json" } }); if (!response.ok) return; const payload = await response.json(); currentPath = payload.path; currentPathNode.textContent = payload.path; listNode.innerHTML = ""; payload.entries.forEach((entry) => { const button = document.createElement("button"); button.type = "button"; button.className = "picker-entry"; button.dataset.kind = entry.kind; button.dataset.path = entry.path; button.innerHTML = `${entry.name}${entry.kind}`; button.addEventListener("click", () => { if (entry.kind === "dir" || entry.kind === "up") { loadListing(entry.path); return; } if (currentInput) { currentInput.value = entry.path; dialog.close(); } }); listNode.appendChild(button); }); }; document.querySelectorAll("[data-picker-target]").forEach((button) => { button.addEventListener("click", () => { const fieldName = button.dataset.pickerTarget; currentKind = button.dataset.pickerKind || "file"; currentInput = document.querySelector(`input[name="${fieldName}"]`); if (!currentInput) return; const initialPath = currentInput.value || "/"; dialog.showModal(); loadListing(initialPath); }); }); document.querySelectorAll("[data-picker-root]").forEach((button) => { button.addEventListener("click", () => loadListing(button.dataset.pickerRoot || "/")); }); closeButton.addEventListener("click", () => dialog.close()); selectCurrentButton.addEventListener("click", () => { if (!currentInput) return; currentInput.value = currentPath; dialog.close(); }); })();