// Part 7 of 15 of the operator console app script. // // Knowledge, candidates, corrections, providers, audit panels and renderAll. // // Load order is significant: these are classic (non-module) scripts sharing one // global scope, and index.html must keep them in the order listed above/below. // Splitting is a pure line-range extraction of the former single app.js. function filteredKnowledgeEntries() { const query = knowledgeFilters.query.trim().toLowerCase(); return knowledgeEntries.filter((entry) => { const typeOk = knowledgeFilters.type === "all" || entry.type === knowledgeFilters.type; const statusOk = knowledgeFilters.status === "all" || (entry.entryStatus || "confirmed") === knowledgeFilters.status; const activeOk = knowledgeFilters.active === "all" || (knowledgeFilters.active === "active") === Boolean(entry.active); const haystack = [entry.name, ...(entry.aliases || []), ...(entry.keywords || [])].join(" ").toLowerCase(); const queryOk = !query || haystack.includes(query); return typeOk && statusOk && activeOk && queryOk; }); } function renderKnowledgeBase() { const entries = filteredKnowledgeEntries(); document.getElementById("knowledge-list").innerHTML = entries.length ? entries .map((entry) => { const aliases = entry.aliases || []; const keywords = entry.keywords || []; const entryStatus = entry.entryStatus || "confirmed"; const statusMeta = entryStatus === "watchlist" ? `원 케이스: ${escapeHtml(entry.sourceSubmissionId || "-")}미래 검출 ${escapeHtml(entry.contributionCount || 0)}건` : ""; const memoInline = entry.memo && entry.memo.startsWith("외부 후보 수집에서 반영:") ? `${escapeHtml(entry.memo)}` : ""; const memoBlock = memoInline ? "" : `
${escapeHtml(entry.memo)}
`; const lifecycleActions = entryStatus === "watchlist" ? ` ` : entryStatus === "excluded" ? "" : entry.active ? `` : ``; const editForm = editingKnowledgeEntryId === entry.id ? ` ` : ""; return `${escapeHtml(correction.reason)}