Skip to content

Refactor comment history and fix content edit #33018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions templates/repo/diff/box.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@

{{if and (not $.Repository.IsArchived) (not .DiffNotAvailable)}}
<template id="issue-comment-editor-template">
<div class="ui form comment">
<form class="ui form comment">
{{template "shared/combomarkdowneditor" (dict
"CustomInit" true
"MarkdownPreviewInRepo" $.Repository
Expand All @@ -252,7 +252,7 @@
<button class="ui cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button>
<button class="ui primary button">{{ctx.Locale.Tr "repo.issues.save"}}</button>
</div>
</div>
</form>
</template>
{{end}}
{{if (not .DiffNotAvailable)}}
Expand Down
2 changes: 2 additions & 0 deletions web_src/js/features/repo-diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ function initRepoDiffFileViewToggle() {
}

function initRepoDiffConversationForm() {
// FIXME: there could be various different form in a conversation-holder (for example: reply form, edit form).
// This listener is for "reply form" only, it should clearly distinguish different forms in the future.
addDelegatedEventListener<HTMLFormElement, SubmitEvent>(document, 'submit', '.conversation-holder form', async (form, e) => {
e.preventDefault();
const textArea = form.querySelector<HTMLTextAreaElement>('textarea');
Expand Down
69 changes: 36 additions & 33 deletions web_src/js/features/repo-issue-content.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import $ from 'jquery';
import {svg} from '../svg.ts';
import {showErrorToast} from '../modules/toast.ts';
import {GET, POST} from '../modules/fetch.ts';
import {showElem} from '../utils/dom.ts';
import {createElementFromHTML, showElem} from '../utils/dom.ts';
import {parseIssuePageInfo} from '../utils.ts';
import {fomanticQuery} from '../modules/fomantic/base.ts';

let i18nTextEdited;
let i18nTextOptions;
let i18nTextDeleteFromHistory;
let i18nTextDeleteFromHistoryConfirm;
let i18nTextEdited: string;
let i18nTextOptions: string;
let i18nTextDeleteFromHistory: string;
let i18nTextDeleteFromHistoryConfirm: string;

function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleHtml) {
let $dialog = $('.content-history-detail-dialog');
if ($dialog.length) return;

$dialog = $(`
function showContentHistoryDetail(issueBaseUrl: string, commentId: string, historyId: string, itemTitleHtml: string) {
const elDetailDialog = createElementFromHTML(`
<div class="ui modal content-history-detail-dialog">
${svg('octicon-x', 16, 'close icon inside')}
<div class="header tw-flex tw-items-center tw-justify-between">
Expand All @@ -29,8 +26,11 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
</div>
<div class="comment-diff-data is-loading"></div>
</div>`);
$dialog.appendTo($('body'));
$dialog.find('.dialog-header-options').dropdown({
document.body.append(elDetailDialog);
const elOptionsDropdown = elDetailDialog.querySelector('.ui.dropdown.dialog-header-options');
const $fomanticDialog = fomanticQuery(elDetailDialog);
const $fomanticDropdownOptions = fomanticQuery(elOptionsDropdown);
$fomanticDropdownOptions.dropdown({
showOnFocus: false,
allowReselection: true,
async onChange(_value, _text, $item) {
Expand All @@ -46,7 +46,7 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
const resp = await response.json();

if (resp.ok) {
$dialog.modal('hide');
$fomanticDialog.modal('hide');
} else {
showErrorToast(resp.message);
}
Expand All @@ -60,10 +60,10 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
}
},
onHide() {
$(this).dropdown('clear', true);
$fomanticDropdownOptions.dropdown('clear', true);
},
});
$dialog.modal({
$fomanticDialog.modal({
async onShow() {
try {
const params = new URLSearchParams();
Expand All @@ -74,43 +74,46 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
const response = await GET(url);
const resp = await response.json();

const commentDiffData = $dialog.find('.comment-diff-data')[0];
commentDiffData?.classList.remove('is-loading');
const commentDiffData = elDetailDialog.querySelector('.comment-diff-data');
commentDiffData.classList.remove('is-loading');
commentDiffData.innerHTML = resp.diffHtml;
// there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden.
if (resp.canSoftDelete) {
showElem($dialog.find('.dialog-header-options'));
showElem(elOptionsDropdown);
}
} catch (error) {
console.error('Error:', error);
}
},
onHidden() {
$dialog.remove();
$fomanticDialog.remove();
},
}).modal('show');
}

function showContentHistoryMenu(issueBaseUrl, $item, commentId) {
const $headerLeft = $item.find('.comment-header-left');
function showContentHistoryMenu(issueBaseUrl: string, elCommentItem: Element, commentId: string) {
const elHeaderLeft = elCommentItem.querySelector('.comment-header-left');
const menuHtml = `
<div class="ui dropdown interact-fg content-history-menu" data-comment-id="${commentId}">
&bull; ${i18nTextEdited}${svg('octicon-triangle-down', 14, 'dropdown icon')}
<div class="menu">
</div>
</div>`;

$headerLeft.find(`.content-history-menu`).remove();
$headerLeft.append($(menuHtml));
$headerLeft.find('.dropdown').dropdown({
elHeaderLeft.querySelector(`.ui.dropdown.content-history-menu`)?.remove(); // remove the old one if exists
elHeaderLeft.append(createElementFromHTML(menuHtml));

const elDropdown = elHeaderLeft.querySelector('.ui.dropdown.content-history-menu');
const $fomanticDropdown = fomanticQuery(elDropdown);
$fomanticDropdown.dropdown({
action: 'hide',
apiSettings: {
cache: false,
url: `${issueBaseUrl}/content-history/list?comment_id=${commentId}`,
},
saveRemoteData: false,
onHide() {
$(this).dropdown('change values', null);
$fomanticDropdown.dropdown('change values', null);
},
onChange(value, itemHtml, $item) {
if (value && !$item.find('[data-history-is-deleted=1]').length) {
Expand All @@ -124,9 +127,9 @@ export async function initRepoIssueContentHistory() {
const issuePageInfo = parseIssuePageInfo();
if (!issuePageInfo.issueNumber) return;

const $itemIssue = $('.repository.issue .timeline-item.comment.first'); // issue(PR) main content
const $comments = $('.repository.issue .comment-list .comment'); // includes: issue(PR) comments, review comments, code comments
if (!$itemIssue.length && !$comments.length) return;
const elIssueDescription = document.querySelector('.repository.issue .timeline-item.comment.first'); // issue(PR) main content
const elComments = document.querySelectorAll('.repository.issue .comment-list .comment'); // includes: issue(PR) comments, review comments, code comments
if (!elIssueDescription && !elComments.length) return;

const issueBaseUrl = `${issuePageInfo.repoLink}/issues/${issuePageInfo.issueNumber}`;

Expand All @@ -139,13 +142,13 @@ export async function initRepoIssueContentHistory() {
i18nTextDeleteFromHistoryConfirm = resp.i18n.textDeleteFromHistoryConfirm;
i18nTextOptions = resp.i18n.textOptions;

if (resp.editedHistoryCountMap[0] && $itemIssue.length) {
showContentHistoryMenu(issueBaseUrl, $itemIssue, '0');
if (resp.editedHistoryCountMap[0] && elIssueDescription) {
showContentHistoryMenu(issueBaseUrl, elIssueDescription, '0');
}
for (const [commentId, _editedCount] of Object.entries(resp.editedHistoryCountMap)) {
if (commentId === '0') continue;
const $itemComment = $(`#issuecomment-${commentId}`);
showContentHistoryMenu(issueBaseUrl, $itemComment, commentId);
const elIssueComment = document.querySelector(`#issuecomment-${commentId}`);
if (elIssueComment) showContentHistoryMenu(issueBaseUrl, elIssueComment, commentId);
}
} catch (error) {
console.error('Error:', error);
Expand Down
3 changes: 3 additions & 0 deletions web_src/js/features/repo-issue-edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ async function tryOnEditContent(e) {

const saveAndRefresh = async (e) => {
e.preventDefault();
// we are already in a form, do not bubble up to the document otherwise there will be other "form submit handlers"
// at the moment, the form submit event conflicts with initRepoDiffConversationForm (global '.conversation-holder form' event handler)
e.stopPropagation();
renderContent.classList.add('is-loading');
showElem(renderContent);
hideElem(editContentZone);
Expand Down
Loading