refactor: apply 5-pass audit optimizations across mcp-memory codebase
This commit is contained in:
1 parent
924b6d09fa
commit
5bd8b1587a
43 files changed
+1866
-1658
No files matched your search
@@ -55,6 +55,12 @@ function switchTab(tabId, btn) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
function toggleTheme() {
|
||||
const currentTheme = document.documentElement.getAttribute("data-theme");
|
||||
const newTheme = currentTheme === "dark" ? "light" : "dark";
|
||||
document.documentElement.setAttribute("data-theme", newTheme);
|
||||
localStorage.setItem("theme", newTheme);
|
||||
}
|
||||
if (localStorage.getItem("theme") === "dark" || !localStorage.getItem("theme") && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||
document.documentElement.setAttribute("data-theme", "dark");
|
||||
}
|
||||
@@ -91,6 +97,11 @@ function zoomGraph(step) {
|
||||
const currentScale = network.getScale();
|
||||
network.moveTo({ scale: currentScale * (1 + step) });
|
||||
}
|
||||
function resetGraph() {
|
||||
if (!network)
|
||||
return;
|
||||
network.fit({ animation: { duration: 500, easingFunction: "easeInOutQuad" } });
|
||||
}
|
||||
function closeInspector() {
|
||||
const inspector = document.getElementById("inspector-panel");
|
||||
if (inspector)
|
||||
@@ -128,6 +139,14 @@ function showInspector(nodeId) {
|
||||
if (inspector)
|
||||
inspector.classList.add("open");
|
||||
}
|
||||
function toggleFilter(type) {
|
||||
if (activeFilters.has(type))
|
||||
activeFilters.delete(type);
|
||||
else
|
||||
activeFilters.add(type);
|
||||
renderFilters();
|
||||
updateGraphData();
|
||||
}
|
||||
function renderFilters() {
|
||||
const container = document.getElementById("graph-filters");
|
||||
if (!container)
|
||||
@@ -240,6 +259,14 @@ async function loadGraph() {
|
||||
}
|
||||
}
|
||||
}
|
||||
async function completeTask(id) {
|
||||
try {
|
||||
await fetch(`/api/tasks/${id}/complete`, { method: "POST" });
|
||||
loadTasks();
|
||||
} catch (e) {
|
||||
console.error("Failed to complete task", e);
|
||||
}
|
||||
}
|
||||
function buildTaskTreeHTML(tasks, parentId, depth = 0) {
|
||||
let html = "";
|
||||
const children = tasks.filter((t) => {
|
||||
@@ -340,6 +367,64 @@ async function loadTasks() {
|
||||
console.error("Failed to load tasks", err);
|
||||
}
|
||||
}
|
||||
function highlightText(text, query) {
|
||||
if (!query)
|
||||
return text;
|
||||
const regex = new RegExp(`(${query})`, "gi");
|
||||
return text.replace(regex, '<span class="search-highlight">$1</span>');
|
||||
}
|
||||
var searchDebounceTimer = null;
|
||||
var activeSearchAbortController = null;
|
||||
async function handleSearch(e) {
|
||||
const input = e.target;
|
||||
const q = input.value.trim();
|
||||
if (searchDebounceTimer)
|
||||
clearTimeout(searchDebounceTimer);
|
||||
if (!q) {
|
||||
if (activeSearchAbortController)
|
||||
activeSearchAbortController.abort();
|
||||
const resultsEl = document.getElementById("search-results");
|
||||
if (resultsEl)
|
||||
resultsEl.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
const delay = e.key === "Enter" ? 0 : 250;
|
||||
searchDebounceTimer = setTimeout(async () => {
|
||||
if (activeSearchAbortController)
|
||||
activeSearchAbortController.abort();
|
||||
activeSearchAbortController = new AbortController;
|
||||
try {
|
||||
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`, {
|
||||
signal: activeSearchAbortController.signal
|
||||
});
|
||||
const data = await res.json();
|
||||
const container = document.getElementById("search-results");
|
||||
if (!container)
|
||||
return;
|
||||
if (!data.results || data.results.length === 0) {
|
||||
container.innerHTML = '<div style="padding:15px;color:var(--text-secondary);">No results found.</div>';
|
||||
return;
|
||||
}
|
||||
container.innerHTML = data.results.map((r) => `
|
||||
<div class="search-result-item" onclick="if(rawEntities['${r.id}']){ showInspector('${r.id}'); network.selectNodes(['${r.id}']); network.focus('${r.id}', {scale:1.2, animation:true}); }" style="cursor:pointer;">
|
||||
<div style="display:flex; justify-content:space-between; align-items:flex-start;">
|
||||
<div>
|
||||
<strong>${highlightText(r.title, q)}</strong>
|
||||
<span style="font-size: 0.7em; color: var(--text-secondary); background: var(--canvas-bg); padding: 2px 6px; border-radius: 4px; margin-left: 8px; text-transform: uppercase; border: 1px solid var(--border-color);">${r.type_name}</span>
|
||||
</div>
|
||||
<div style="font-size:0.75em; color:var(--text-secondary);">${r.score.toFixed(2)}</div>
|
||||
</div>
|
||||
<div style="margin-top:6px; font-size:0.9em; line-height:1.4;">${highlightText(r.content.substring(0, 150), q)}${r.content.length > 150 ? "..." : ""}</div>
|
||||
<div style="font-size:0.75em; color:var(--text-secondary); margin-top:8px; font-family:monospace; background: var(--canvas-bg); padding: 2px 4px; border-radius: 3px; display: inline-block;">ID: ${r.id}</div>
|
||||
</div>
|
||||
`).join("");
|
||||
} catch (err) {
|
||||
if (err.name !== "AbortError") {
|
||||
console.error("Search error:", err);
|
||||
}
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
var MAX_ACTIVITY_HISTORY = 100;
|
||||
function escapeHtml(str) {
|
||||
if (str === null || str === undefined)
|
||||
@@ -785,6 +870,39 @@ function loadPRs() {
|
||||
</ul>
|
||||
`);
|
||||
}
|
||||
function loadAllExtras() {
|
||||
loadTerminal();
|
||||
loadTechDebt();
|
||||
loadADRs();
|
||||
loadWorkspaces();
|
||||
loadPinned();
|
||||
loadMemos();
|
||||
loadSnippets();
|
||||
loadPRs();
|
||||
}
|
||||
async function testClipboard() {
|
||||
const modal = document.getElementById("clipboard-modal");
|
||||
const resultDiv = document.getElementById("clipboard-result");
|
||||
if (modal)
|
||||
modal.style.display = "flex";
|
||||
if (resultDiv)
|
||||
resultDiv.innerHTML = '<p id="clipboard-loading" style="color:var(--text-secondary);">Analyzing your clipboard...</p>';
|
||||
try {
|
||||
const res = await fetch("/api/clipboard/capture", { method: "POST" });
|
||||
const data = await res.json();
|
||||
if (resultDiv) {
|
||||
if (data.success) {
|
||||
resultDiv.innerHTML = `<img src="${data.image}" style="max-width:100%; max-height:60vh; border-radius:4px; border:1px solid var(--border-color); box-shadow: 0 5px 15px rgba(0,0,0,0.3);" />`;
|
||||
} else {
|
||||
resultDiv.innerHTML = `<p style="color:var(--error-color); font-weight:bold;">Failed to read clipboard: ${data.error}</p>`;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (resultDiv) {
|
||||
resultDiv.innerHTML = `<p style="color:var(--error-color); font-weight:bold;">Error calling endpoint: ${err.message}</p>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
async function loadVersion() {
|
||||
try {
|
||||
const res = await fetch("/api/version");
|
||||
@@ -836,6 +954,89 @@ document.addEventListener("keydown", function(e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
function refreshActiveTab() {
|
||||
switch (currentTabId) {
|
||||
case "graph-tab":
|
||||
loadGraph();
|
||||
break;
|
||||
case "task-tab":
|
||||
loadTasks();
|
||||
break;
|
||||
case "sticky-tab":
|
||||
loadStickyNotes();
|
||||
break;
|
||||
case "techdebt-tab":
|
||||
loadTechDebt();
|
||||
break;
|
||||
case "adrs-tab":
|
||||
loadADRs();
|
||||
break;
|
||||
case "workspaces-tab":
|
||||
loadWorkspaces();
|
||||
break;
|
||||
case "pinned-tab":
|
||||
loadPinned();
|
||||
break;
|
||||
case "memos-tab":
|
||||
loadMemos();
|
||||
break;
|
||||
case "snippets-tab":
|
||||
loadSnippets();
|
||||
break;
|
||||
case "pr-tab":
|
||||
loadPRs();
|
||||
break;
|
||||
case "terminal-tab":
|
||||
loadTerminal();
|
||||
break;
|
||||
case "preferences-tab":
|
||||
loadPreferences();
|
||||
break;
|
||||
case "activity-tab":
|
||||
loadActivityHistory();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Object.assign(window, {
|
||||
switchTab,
|
||||
toggleTheme,
|
||||
getColorForType,
|
||||
zoomGraph,
|
||||
resetGraph,
|
||||
closeInspector,
|
||||
showInspector,
|
||||
toggleFilter,
|
||||
renderFilters,
|
||||
updateGraphData,
|
||||
loadGraph,
|
||||
completeTask,
|
||||
buildTaskTreeHTML,
|
||||
loadTasks,
|
||||
highlightText,
|
||||
handleSearch,
|
||||
escapeHtml,
|
||||
parseActivityPayload,
|
||||
loadActivityHistory,
|
||||
requestDomainRefresh,
|
||||
handleIncomingActivity,
|
||||
setupWS,
|
||||
loadPreferences,
|
||||
loadStickyNotes,
|
||||
loadGenericList,
|
||||
loadTerminal,
|
||||
loadTechDebt,
|
||||
loadADRs,
|
||||
loadWorkspaces,
|
||||
loadPinned,
|
||||
loadMemos,
|
||||
loadSnippets,
|
||||
loadPRs,
|
||||
loadAllExtras,
|
||||
testClipboard,
|
||||
loadVersion,
|
||||
setupSSE,
|
||||
refreshActiveTab
|
||||
});
|
||||
loadVersion();
|
||||
loadActivityHistory();
|
||||
setupWS();
|
||||
|
||||
Reference in new issue
Block a user