diff --git a/frontend/conversation.js b/frontend/conversation.js index 56ad7e5..beff6c9 100644 --- a/frontend/conversation.js +++ b/frontend/conversation.js @@ -81,4 +81,37 @@ function createConversationPager({ loadPage }) { }; } +function renderConversationComment(comment, controller, escapeHtml, formatTime, renderMarkdown) { + const actions = controller?.actionHtml?.(comment) || ''; + return '
' + + escapeHtml(comment.author || 'Unknown author') + + (comment.created_at ? ' · ' + escapeHtml(formatTime(comment.created_at)) : '') + + '
' + actions + '
' + + renderMarkdown(comment.body || 'No comment body provided.') + '
'; +} + +function createConversationRenderers({qs,renderComment,updateReadPosition,getSelectedUpdate}) { + function status(kind, comments, total) { + qs('#' + kind + '-conversation-status').textContent = comments.length ? + comments.length + ' of ' + Math.max(total || 0, comments.length) + ' messages loaded.' : 'No comments yet.'; + } + function paint(kind, state, controller) { + const comments = state?.comments || []; + qs('#' + kind + '-comments').innerHTML = comments.length ? comments.map(comment => + kind === 'pull' ? '
' + renderComment(comment,controller) + '
' : + renderComment(comment,controller)).join('') : '
No comments yet.
'; + qs('#load-older-' + kind + '-comments').hidden = !Number.isInteger(state?.older_page); + status(kind,comments,state?.total); + if (kind === 'update') { + const newest = qs('#update-comments .issue-comment:last-child'); + updateReadPosition.ready(String(getSelectedUpdate()?.notification_id || ''),newest); + } + } + return { + paintIssueConversation:(state,controller)=>paint('issue',state,controller), + paintPullConversation:(state,controller)=>paint('pull',state,controller), + paintUpdateConversation:(state,controller)=>paint('update',state,controller), + }; +} + if (typeof module !== 'undefined' && module.exports) module.exports = createConversationPager; diff --git a/frontend/dashboard.js b/frontend/dashboard.js index bf6ab29..5721d4b 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -4097,46 +4097,17 @@ toggle?.focus(); } - function renderIssueComment(comment, controller = commentActions) { - const actions = controller?.actionHtml?.(comment) || ''; - return '
' + - escapeHtml(comment.author || 'Unknown author') + - (comment.created_at ? ' · ' + escapeHtml(fmt(comment.created_at)) : '') + - '
' + actions + '
' + - renderMarkdown(comment.body || 'No comment body provided.') + '
'; - } - - function paintIssueConversation(state, controller) { - const comments = state?.comments || []; - qs('#issue-comments').innerHTML = comments.length ? - comments.map(comment => renderIssueComment(comment, controller)).join('') : '
No comments yet.
'; - qs('#load-older-issue-comments').hidden = !Number.isInteger(state?.older_page); - qs('#issue-conversation-status').textContent = comments.length ? - comments.length + ' of ' + Math.max(state.total || 0, comments.length) + ' messages loaded.' : 'No comments yet.'; - } - - function paintUpdateConversation(state, controller) { - const comments = state?.comments || []; - qs('#update-comments').innerHTML = comments.length ? - comments.map(comment => renderIssueComment(comment, controller)).join('') : '
No comments yet.
'; - qs('#load-older-update-comments').hidden = !Number.isInteger(state?.older_page); - qs('#update-conversation-status').textContent = comments.length ? - comments.length + ' of ' + Math.max(state.total || 0, comments.length) + ' messages loaded.' : 'No comments yet.'; - const newest = qs('#update-comments .issue-comment:last-child'); - updateReadPosition.ready(String(selectedUpdate?.notification_id || ''), newest); - } - - function paintPullConversation(state, controller) { - const comments = state?.comments || []; - qs('#pull-comments').innerHTML = comments.length ? comments.map(comment => - '
' + renderIssueComment(comment, controller) + '
' - ).join('') : '
No comments yet.
'; - qs('#load-older-pull-comments').hidden = !Number.isInteger(state?.older_page); - qs('#pull-conversation-status').textContent = comments.length ? - comments.length + ' of ' + Math.max(state.total || 0, comments.length) + ' messages loaded.' : 'No comments yet.'; - } + const {paintIssueConversation,paintPullConversation,paintUpdateConversation}=createConversationRenderers({ + qs,renderComment:(comment,controller)=>renderConversationComment( + comment,controller,escapeHtml,fmt,renderMarkdown), + updateReadPosition,getSelectedUpdate:()=>selectedUpdate, + }); function commentSurface(selector) { + if (selector === '#search-preview-comments') return { + context:{kind:searchPreviewDetail.kind,item:searchPreviewDetail}, pager:searchPreview.commentPager(), + render:state=>showSearchConversationWithActions(state), status:qs('#search-preview-conversation-status'), + }; if (selector === '#issue-comments') return { context:{kind:'issue',item:selectedIssue}, pager:issueConversation, render:renderIssueConversation, status:qs('#issue-sheet-status'), @@ -5664,8 +5635,14 @@ commandSearch.setScope(scope); } let searchPreviewDetail = null; - const renderSearchConversation = conversation => - renderSearchPreviewConversation(conversation, document, escapeHtml, fmt, renderMarkdown); + const showSearchConversationWithActions = createSearchPreviewConversationActions({ + hydrator:actionHydrator, rootNode:qs('#search-preview-comments'), + retry:qs('#retry-search-preview-comment-actions'), + paint:(conversation,controller)=>renderSearchPreviewConversation( + conversation,document,escapeHtml,fmt,renderMarkdown,controller), + wire:controller=>wireCommentActions('#search-preview-comments',controller), + }); + const renderSearchConversation = conversation => { void showSearchConversationWithActions(conversation); }; function renderSearchPreview(state) { followingQueue.preview(state); const sheet = qs('#search-preview'); diff --git a/frontend/index.html b/frontend/index.html index c903f29..efc1207 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -901,6 +901,7 @@
+