239 lines
8.2 KiB
JavaScript
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" });
|
|
})();
|