From 59a62f083f4c9a6a157f54926e230fe8b56125ac Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu <31145988+chidozieononiwu@users.noreply.github.com> Date: Thu, 27 Jul 2023 17:16:27 -0700 Subject: [PATCH] Resolve bug in Comment Auto Refresh (#6574) --- .../Client/src/shared/comments.module.ts | 77 ++++++++++++++++++ .../APIViewWeb/Client/src/shared/comments.ts | 1 - .../APIViewWeb/Client/src/shared/helpers.ts | 8 +- .../APIViewWeb/Client/src/shared/signalr.ts | 80 ++----------------- 4 files changed, 89 insertions(+), 77 deletions(-) create mode 100644 src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts new file mode 100644 index 00000000000..aac62ea0bc8 --- /dev/null +++ b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts @@ -0,0 +1,77 @@ + +import * as hp from "./helpers"; + +/** +* Updates comment thread HTML to match the current user's context +* Remove remove/edit buttons of sender's comments +* Add remove/edit buttons to current user's comments (if any) +* @param commentThreadHTML +* @returns partial view result for the current user +*/ +export function updateCommentThreadUserContext(commentThreadHTML: string) { + let commentThread = $(commentThreadHTML); + + // remove all delete and edit anchors + commentThread.find("a.dropdown-item.js-delete-comment").next().next().remove(); + commentThread.find("a.dropdown-item.js-delete-comment").next().remove(); + commentThread.find("a.dropdown-item.js-delete-comment").remove(); + + //verify name and add delete and edit anchors + let $commentContents = commentThread.find("div.comment-contents > span"); + $commentContents.each((index, value) => { + let commenter; + if (value.children) { + commenter = value.children[0]; + } + if (!commenter) { + return; + } + + let commenterHref = commenter.attributes.getNamedItem('href')?.value; + let profileHref; + $('ul.navbar-nav.ms-auto > li.nav-item > a.nav-link').each((index, value) => { + if (value.textContent && value.textContent.trim() === 'Profile') { + profileHref = value.attributes.getNamedItem('href')?.value; + } + }); + + + if (profileHref === commenterHref) { + let dropdown = commentThread.find('div.dropdown-menu.dropdown-menu-right')[index]; + $('
  • ').prependTo(dropdown); + $('Edit').prependTo(dropdown); + $('Delete').prependTo(dropdown); + } + }); + + let partialViewString = commentThreadHTML.split(""; + return partialViewString; +} + + +/** + * Replaces the row or comment thread with partial view result (an updated comment thread) + * @param reviewId + * @param elementId + * @param commentThreadHTML + */ +export function updateCommentThreadInReviewPageDOM(reviewId: any, elementId: any, commentThreadHTML: any) { + if (hp.checkReviewRevisionIdAgainstCurrent(reviewId, null, false)) { + var rowSectionClasses = hp.getCodeRowSectionClasses(elementId); + hp.showCommentBox(elementId, rowSectionClasses, undefined, false); + + let commentsRow = hp.getCommentsRow(elementId); + const replyText = commentsRow.find(".new-thread-comment-text-mirror").text(); + hp.updateCommentThread(commentsRow, commentThreadHTML); + hp.updateUserIcon(); + if (replyText) { + commentsRow = hp.getCommentsRow(elementId); + commentsRow.find(".review-thread-reply-button").click(); + commentsRow.find(".new-thread-comment-text-mirror").text(replyText) + commentsRow.find(".new-thread-comment-text").html(replyText); + } + hp.addCommentThreadNavigation(); + hp.removeCommentIconIfEmptyCommentBox(elementId); + } +} + diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts index 11fcd294a39..726b1cdbd79 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts @@ -531,5 +531,4 @@ $(() => { toggleComments(id); } } - }); diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts b/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts index 40b78104625..415c89d5ac3 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts @@ -153,9 +153,9 @@ export function addToastNotification(notification : Notification, id : string = } // Auto Refresh Comment -export function updateCommentThread(commentBox, partialViewResult) { - partialViewResult = $.parseHTML(partialViewResult); - $(commentBox).replaceWith(partialViewResult); +export function updateCommentThread(commentBox, commentThreadHTML) { + commentThreadHTML = $.parseHTML(commentThreadHTML); + $(commentBox).replaceWith(commentThreadHTML); return false; } @@ -383,7 +383,7 @@ export function checkReviewRevisionIdAgainstCurrent(reviewId, revisionId, checkR return false; } - if (checkRevision && currRevisionId && currRevisionId === revisionId) { + if (checkRevision && currRevisionId && currRevisionId != revisionId) { return false; } diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/shared/signalr.ts b/src/dotnet/APIView/APIViewWeb/Client/src/shared/signalr.ts index 71ce3d498d7..af40217ab82 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/shared/signalr.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/shared/signalr.ts @@ -1,5 +1,6 @@ import * as hp from "./helpers"; import * as rvM from "../pages/review.module"; +import * as cM from "../shared/comments.module"; const signalR = require('@microsoft/signalr'); @@ -48,19 +49,19 @@ $(() => { * solution: send to all users AND the group and raise flag */ let alreadyRefreshedComment = false; - connection.on("ReceiveCommentSelf", (reviewId, elementId, partialViewResult) => { - replaceRowWIthPartialViewResult(reviewId, elementId, partialViewResult); + connection.on("ReceiveCommentSelf", (reviewId, elementId, commentThreadHTML) => { + cM.updateCommentThreadInReviewPageDOM(reviewId, elementId, commentThreadHTML); alreadyRefreshedComment = true; }); - connection.on("ReceiveComment", (reviewId: string, elementId: string, partialViewResult: string) => { + connection.on("ReceiveComment", (reviewId: string, elementId: string, commentThreadHTML: string) => { if (alreadyRefreshedComment == true) { alreadyRefreshedComment = false; return; } - let partialViewString = getCurrentUserPartialViewResult(partialViewResult); - replaceRowWIthPartialViewResult(reviewId, elementId, partialViewString); + let commentThreadString = (commentThreadHTML && commentThreadHTML != '\r\n') ? cM.updateCommentThreadUserContext(commentThreadHTML) : commentThreadHTML; + cM.updateCommentThreadInReviewPageDOM(reviewId, elementId, commentThreadString); }); let approvalPendingText = "Current Revision Approval Pending"; @@ -111,78 +112,13 @@ $(() => { if (approvalToggle) { rvM.addApprover(lowerTextSpan, approvedByText, approverHref, approver); + rvM.addApprovedBorder(); } else { rvM.removeApprover(lowerTextSpan, approver, approvalPendingText); + rvM.removeApprovalBorder(); } }) // Start the connection. start(); }); - -/** -* Auto refresh's raw partial view result input is sent w.r.t. the sender's profile -* Remove remove/edit buttons of sender's comments -* Add remove/edit buttons to current user's comments (if any) -* @param partialViewResult -* @returns partial view result for the current user -*/ -function getCurrentUserPartialViewResult(partialViewResult: string) { - let partialView = $(partialViewResult); - - // remove all delete and edit anchors - partialView.find("a.dropdown-item.js-delete-comment").next().next().remove(); - partialView.find("a.dropdown-item.js-delete-comment").next().remove(); - partialView.find("a.dropdown-item.js-delete-comment").remove(); - - //verify name and add delete and edit anchors - let $commentContents = partialView.find("div.comment-contents > span"); - $commentContents.each((index, value) => { - let commenter; - if (value.children) { - commenter = value.children[0]; - } - if (!commenter) { - return; - } - - let commenterHref = commenter.attributes.getNamedItem('href')?.value; - let profileHref; - $('ul.navbar-nav.ms-auto > li.nav-item > a.nav-link').each((index, value) => { - if (value.textContent && value.textContent.trim() === 'Profile') { - profileHref = value.attributes.getNamedItem('href')?.value; - } - }); - - - if (profileHref === commenterHref) { - let dropdown = partialView.find('div.dropdown-menu.dropdown-menu-right')[index]; - $('
  • ').prependTo(dropdown); - $('Edit').prependTo(dropdown); - $('Delete').prependTo(dropdown); - } - }); - - let partialViewString = partialViewResult.split(""; - return partialViewString; -} - -/** - * Replaces the row or comment thread with partial view result - * @param reviewId - * @param elementId - * @param partialViewResult - */ -function replaceRowWIthPartialViewResult(reviewId: any, elementId: any, partialViewResult: any) { - hp.checkReviewRevisionIdAgainstCurrent(reviewId, null, false); - - var rowSectionClasses = hp.getCodeRowSectionClasses(elementId); - hp.showCommentBox(elementId, rowSectionClasses, undefined, false); - - let commentsRow = hp.getCommentsRow(elementId); - hp.updateCommentThread(commentsRow, partialViewResult); - hp.addCommentThreadNavigation(); - hp.removeCommentIconIfEmptyCommentBox(elementId); - - hp.updateUserIcon(); -}