(push, options = {})
| 2239 | } |
| 2240 | |
| 2241 | function renderPush(push, options = {}) { |
| 2242 | state.push = push; |
| 2243 | state.selected.clear(); |
| 2244 | state.skipped.clear(); |
| 2245 | state.later.clear(); |
| 2246 | const papers = push?.papers || []; |
| 2247 | const metadata = push?.metadata || {}; |
| 2248 | $("candidateStat").textContent = metadata.total_fetched ?? metadata.fetched_count ?? papers.length ?? 0; |
| 2249 | $("filteredStat").textContent = metadata.paper_count ?? metadata.filtered_count ?? metadata.ranked_count ?? papers.length ?? 0; |
| 2250 | $("latestPushStat").textContent = papers.length || "-"; |
| 2251 | $("readingQueueStat").textContent = "0"; |
| 2252 | $("pushMeta").textContent = pushMetaText(push, papers, metadata, options); |
| 2253 | if (!papers.length) { |
| 2254 | $("paperList").className = "paper-list empty"; |
| 2255 | $("paperList").textContent = ui().papers.noRecommendations; |
| 2256 | updateSelectionSummary(); |
| 2257 | return; |
| 2258 | } |
| 2259 | $("paperList").className = "paper-list"; |
| 2260 | $("paperList").innerHTML = papers.map((paper, index) => { |
| 2261 | const number = Number(paper.number || index + 1); |
| 2262 | const reportKey = paperReportKey(number, push?.push_id); |
| 2263 | const reportId = state.paperReports.get(reportKey); |
| 2264 | const isReading = state.paperReading.has(reportKey); |
| 2265 | const score = normalizeScore(paper.score ?? paper.relevance ?? paper.relevance_score ?? 80); |
| 2266 | const tags = paperDisplayTags(paper); |
| 2267 | return ` |
| 2268 | <article class="paper-card" data-paper-number="${number}"> |
| 2269 | <div class="score-ring" style="--score: ${Math.min(score, 100)}%">${score}%</div> |
| 2270 | <div class="paper-content"> |
| 2271 | <h3>${escapeHtml(paper.title || "Untitled Paper")}</h3> |
| 2272 | <p class="paper-authors">${escapeHtml(Array.isArray(paper.authors) ? paper.authors.join(", ") : (paper.authors || paper.author || ui().papers.authorPending))}</p> |
| 2273 | <p class="paper-abstract">${escapeHtml(paper.abstract || paper.summary || "")}</p> |
| 2274 | <div class="paper-tags"> |
| 2275 | ${tags.map((tag) => `<span>${escapeHtml(tag)}</span>`).join("")} |
| 2276 | </div> |
| 2277 | </div> |
| 2278 | <div class="paper-actions"> |
| 2279 | <button data-action="read" data-number="${number}" class="${reportId ? "ready" : ""} ${isReading ? "loading" : ""}" type="button" ${isReading ? "disabled" : ""}>${isReading ? ui().papers.loading : reportId ? ui().papers.readReport : ui().papers.read}</button> |
| 2280 | <button data-action="skip" data-number="${number}" type="button">${ui().papers.skip}</button> |
| 2281 | <button data-action="later" data-number="${number}" type="button">${ui().papers.later}</button> |
| 2282 | </div> |
| 2283 | </article>`; |
| 2284 | }).join(""); |
| 2285 | updateSelectionSummary(); |
| 2286 | } |
| 2287 | |
| 2288 | async function loadLatestPush() { |
| 2289 | const data = await api(`/api/latest-push?user_id=${encodeURIComponent(currentUser())}`); |
no test coverage detected