Files
2026-04-09 15:42:42 +03:00

239 lines
8.2 KiB
JavaScript

(function () {
const vscode = acquireVsCodeApi();
const feedScrollEl = document.getElementById("feed-scroll");
const headerRagSessionEl = document.getElementById("header-rag-session");
const headerRagSessionValueEl = document.getElementById("header-rag-session-value");
const processVersionEl = document.getElementById("process-version");
const statusBlocksEl = document.getElementById("status-blocks");
const messagesEl = document.getElementById("messages");
const inputEl = document.getElementById("input");
const btnSend = document.getElementById("btn-send");
const btnClear = document.getElementById("btn-clear");
const btnMenu = document.getElementById("btn-menu");
const menuDropdown = document.getElementById("menu-dropdown");
const taskStatusEl = document.getElementById("task-status");
const taskStatusLabelEl = document.getElementById("task-status-label");
const taskStatusDetailEl = document.getElementById("task-status-detail");
const taskProgressEl = document.getElementById("task-progress");
const taskProgressBarEl = document.getElementById("task-progress-bar");
const ragDotEl = document.getElementById("rag-dot");
const ragLabelEl = document.getElementById("rag-label");
const ragDetailEl = document.getElementById("rag-detail");
const ragMetricsEl = document.getElementById("rag-metrics");
let currentRagSessionId = "";
function renderStatusBlocks(items) {
statusBlocksEl.innerHTML = "";
(items || []).forEach(function (block) {
const wrap = document.createElement("div");
wrap.className = "status-block";
const title = document.createElement("div");
title.className = "status-block-title";
title.textContent = block.title || block.id || "Status";
wrap.appendChild(title);
const body = document.createElement("div");
body.className = "status-block-body";
(block.lines || []).forEach(function (line) {
const item = document.createElement("div");
item.className = "status-block-line";
item.textContent = line || "";
body.appendChild(item);
});
wrap.appendChild(body);
statusBlocksEl.appendChild(wrap);
});
}
function renderMessages(items) {
messagesEl.innerHTML = "";
(items || []).forEach(function (m) {
const div = document.createElement("div");
var roleClass = "msg-assistant";
if (m.role === "user") {
roleClass = "msg-user";
} else if (m.role === "status") {
roleClass = "msg-status";
} else if (m.role === "error") {
roleClass = "msg-error";
}
div.className = "msg " + roleClass;
const text = document.createElement("div");
text.className = m.kind === "markdown" ? "msg-markdown" : "msg-text";
text.textContent = m.text || "";
if (m.role !== "status") {
const role = document.createElement("div");
role.className = "msg-role";
role.textContent =
m.role === "user" ? "Вы" : m.role === "error" ? "Ошибка" : "Ответ";
div.appendChild(role);
}
div.appendChild(text);
messagesEl.appendChild(div);
});
}
function renderTaskStatus(status) {
var visible = Boolean(status && status.visible);
taskStatusEl.hidden = !visible;
if (!visible) {
taskProgressEl.hidden = true;
taskProgressBarEl.style.width = "0%";
return;
}
taskStatusLabelEl.textContent = status.label || "Статус";
taskStatusDetailEl.textContent = status.detail || "";
if (typeof status.progress === "number" && isFinite(status.progress)) {
taskProgressEl.hidden = false;
taskProgressBarEl.style.width = Math.max(0, Math.min(100, status.progress)) + "%";
} else {
taskProgressEl.hidden = true;
taskProgressBarEl.style.width = "0%";
}
}
function renderRagStatus(status) {
var state = (status && status.state) || "idle";
var sessionId = (status && status.ragSessionId) || "";
currentRagSessionId = sessionId;
ragDotEl.className = "rag-dot state-" + state;
ragLabelEl.textContent = (status && status.label) || "RAG не готов";
ragDetailEl.textContent =
(status && status.detail) || "Ожидается индексация проекта.";
if (headerRagSessionEl && headerRagSessionValueEl) {
headerRagSessionValueEl.textContent = sessionId || "—";
headerRagSessionEl.title = sessionId
? "Кликните, чтобы скопировать RAG session id"
: "RAG session is not created yet.";
}
var metrics = [];
if (status) {
metrics.push("indexed: " + (status.indexedFiles || 0));
metrics.push("failed: " + (status.failedFiles || 0));
metrics.push("cache hit: " + (status.cacheHitFiles || 0));
metrics.push("cache miss: " + (status.cacheMissFiles || 0));
}
ragMetricsEl.textContent = metrics.join(" | ");
}
function renderState(state) {
renderStatusBlocks(state.statusBlocks);
renderMessages(state.messages);
renderTaskStatus(state.taskStatus);
renderRagStatus(state.ragStatus);
if (processVersionEl && state && state.processVersion) {
processVersionEl.value = state.processVersion;
}
btnSend.disabled = false;
inputEl.disabled = false;
btnClear.disabled = Boolean(state.busy);
if (feedScrollEl) {
feedScrollEl.scrollTop = feedScrollEl.scrollHeight;
}
}
window.addEventListener("message", function (event) {
const msg = event.data;
if (msg && msg.type === "state") {
renderState(msg.payload || {});
}
});
function send() {
const text = (inputEl.value || "").trim();
if (!text) {
return;
}
vscode.postMessage({ type: "send", text: text });
inputEl.value = "";
}
btnSend.addEventListener("click", send);
inputEl.addEventListener("keydown", function (e) {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
send();
}
});
btnClear.addEventListener("click", function () {
vscode.postMessage({ type: "clear" });
});
processVersionEl.addEventListener("change", function () {
vscode.postMessage({
type: "set-process-version",
value: processVersionEl.value || "v2",
});
});
async function copyRagSessionId() {
if (!currentRagSessionId) {
return;
}
try {
if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
await navigator.clipboard.writeText(currentRagSessionId);
} else {
const helper = document.createElement("textarea");
helper.value = currentRagSessionId;
helper.style.position = "fixed";
helper.style.opacity = "0";
document.body.appendChild(helper);
helper.focus();
helper.select();
document.execCommand("copy");
document.body.removeChild(helper);
}
if (headerRagSessionEl) {
headerRagSessionEl.classList.add("copied");
window.setTimeout(function () {
headerRagSessionEl.classList.remove("copied");
}, 1200);
}
} catch (error) {
console.error("Failed to copy RAG session id", error);
}
}
headerRagSessionEl.addEventListener("click", function () {
void copyRagSessionId();
});
headerRagSessionEl.addEventListener("keydown", function (event) {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
void copyRagSessionId();
}
});
btnMenu.addEventListener("click", function (e) {
e.stopPropagation();
const open = menuDropdown.hidden;
menuDropdown.hidden = !open;
btnMenu.setAttribute("aria-expanded", open ? "true" : "false");
});
document.addEventListener("click", function () {
if (!menuDropdown.hidden) {
menuDropdown.hidden = true;
btnMenu.setAttribute("aria-expanded", "false");
}
});
menuDropdown.addEventListener("click", function (e) {
e.stopPropagation();
const t = e.target;
if (t && t.classList && t.classList.contains("menu-item")) {
const action = t.getAttribute("data-action") || "";
vscode.postMessage({ type: "menu", action: action });
menuDropdown.hidden = true;
btnMenu.setAttribute("aria-expanded", "false");
}
});
vscode.postMessage({ type: "ready" });
})();