Первый коммит
This commit is contained in:
+238
@@ -0,0 +1,238 @@
|
||||
(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" });
|
||||
})();
|
||||
Reference in New Issue
Block a user