loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Remove jQuery AJAX from the `repo-issue.js` file (#29776)

Removed all jQuery AJAX calls and replaced with our fetch wrapper.

Tested the following functionalities and they work as before:
- due-date update
- comment deletion
- branch update by merge or rebase
- allow edits from maintainers button
- reviewer addition or deletion
- WIP toggle button
- new diff code comment button
- issue title edit button

# Demo using `fetch` instead of jQuery AJAX
## Updating the due-date of an issue

![due_date](https://github.com/go-gitea/gitea/assets/20454870/7de395d3-63e8-49e8-9a13-8d14fc26810d)

## Deleting a comment

![comment_delete](https://github.com/go-gitea/gitea/assets/20454870/2814e695-44e3-4548-9ee7-7b437bef4b01)

## Updating a branch in a pull request

![branch_update](https://github.com/go-gitea/gitea/assets/20454870/137da77e-acc4-4984-a1bc-be58583bf52a)

## Checking and unchecking the "Allow edits from maintainers" checkbox

![allow_edits](https://github.com/go-gitea/gitea/assets/20454870/8d4829af-5813-432d-90ef-da057f8cdafc)

## Requesting review and removing review request

![reviewer_addition](https://github.com/go-gitea/gitea/assets/20454870/08f210e0-be3f-41af-b271-214a1dd2d0ba)

## Toggling the WIP status of a pull request

![wip](https://github.com/go-gitea/gitea/assets/20454870/dea5e668-1c89-4f3d-a5d6-4c26aefc4814)

## Clicking the new code comment button on the diff page

![code_comment](https://github.com/go-gitea/gitea/assets/20454870/1d17174e-3bba-4cf8-81fe-c3a2c21f80b9)

## Editing the issue title and target branch

![issue_title](https://github.com/go-gitea/gitea/assets/20454870/7099888e-81c0-47d4-9371-8e4469e9e519)

---------

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
Co-authored-by: silverwind <me@silverwind.io>
(cherry picked from commit 0679e60c776cd45f32acc12f52fe41b627da57e9)

authored by

Yarden Shoham
silverwind
and committed by
Earl Warren
f4d75ed4 ed1798f6

+113 -83
+113 -83
web_src/js/features/repo-issue.js
··· 6 6 import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js'; 7 7 import {toAbsoluteUrl} from '../utils.js'; 8 8 import {initDropzone} from './common-global.js'; 9 + import {POST, GET} from '../modules/fetch.js'; 9 10 10 - const {appSubUrl, csrfToken} = window.config; 11 + const {appSubUrl} = window.config; 11 12 12 13 export function initRepoIssueTimeTracking() { 13 14 $(document).on('click', '.issue-add-time', () => { ··· 40 41 }); 41 42 } 42 43 43 - function updateDeadline(deadlineString) { 44 + async function updateDeadline(deadlineString) { 44 45 hideElem($('#deadline-err-invalid-date')); 45 46 $('#deadline-loader').addClass('loading'); 46 47 ··· 56 57 realDeadline = new Date(newDate); 57 58 } 58 59 59 - $.ajax(`${$('#update-issue-deadline-form').attr('action')}`, { 60 - data: JSON.stringify({ 61 - due_date: realDeadline, 62 - }), 63 - headers: { 64 - 'X-Csrf-Token': csrfToken, 65 - }, 66 - contentType: 'application/json', 67 - type: 'POST', 68 - success() { 60 + try { 61 + const response = await POST($('#update-issue-deadline-form').attr('action'), { 62 + data: {due_date: realDeadline} 63 + }); 64 + 65 + if (response.ok) { 69 66 window.location.reload(); 70 - }, 71 - error() { 72 - $('#deadline-loader').removeClass('loading'); 73 - showElem($('#deadline-err-invalid-date')); 74 - }, 75 - }); 67 + } else { 68 + throw new Error('Invalid response'); 69 + } 70 + } catch (error) { 71 + console.error(error); 72 + $('#deadline-loader').removeClass('loading'); 73 + showElem($('#deadline-err-invalid-date')); 74 + } 76 75 } 77 76 78 77 export function initRepoIssueDue() { ··· 156 155 157 156 export function initRepoIssueCommentDelete() { 158 157 // Delete comment 159 - $(document).on('click', '.delete-comment', function () { 158 + $(document).on('click', '.delete-comment', async function () { 160 159 const $this = $(this); 161 160 if (window.confirm($this.data('locale'))) { 162 - $.post($this.data('url'), { 163 - _csrf: csrfToken, 164 - }).done(() => { 161 + try { 162 + const response = await POST($this.data('url')); 163 + if (!response.ok) throw new Error('Failed to delete comment'); 165 164 const $conversationHolder = $this.closest('.conversation-holder'); 166 165 167 166 // Check if this was a pending comment. ··· 186 185 } 187 186 $conversationHolder.remove(); 188 187 } 189 - }); 188 + } catch (error) { 189 + console.error(error); 190 + } 190 191 } 191 192 return false; 192 193 }); ··· 226 227 export function initRepoPullRequestUpdate() { 227 228 // Pull Request update button 228 229 const $pullUpdateButton = $('.update-button > button'); 229 - $pullUpdateButton.on('click', function (e) { 230 + $pullUpdateButton.on('click', async function (e) { 230 231 e.preventDefault(); 231 232 const $this = $(this); 232 233 const redirect = $this.data('redirect'); 233 234 $this.addClass('loading'); 234 - $.post($this.data('do'), { 235 - _csrf: csrfToken 236 - }).done((data) => { 237 - if (data.redirect) { 238 - window.location.href = data.redirect; 239 - } else if (redirect) { 240 - window.location.href = redirect; 241 - } else { 242 - window.location.reload(); 243 - } 244 - }); 235 + let response; 236 + try { 237 + response = await POST($this.data('do')); 238 + } catch (error) { 239 + console.error(error); 240 + } finally { 241 + $this.removeClass('loading'); 242 + } 243 + let data; 244 + try { 245 + data = await response?.json(); // the response is probably not a JSON 246 + } catch (error) { 247 + console.error(error); 248 + } 249 + if (data?.redirect) { 250 + window.location.href = data.redirect; 251 + } else if (redirect) { 252 + window.location.href = redirect; 253 + } else { 254 + window.location.reload(); 255 + } 245 256 }); 246 257 247 258 $('.update-button > .dropdown').dropdown({ ··· 267 278 268 279 const promptError = $checkbox.attr('data-prompt-error'); 269 280 $checkbox.checkbox({ 270 - 'onChange': () => { 281 + 'onChange': async () => { 271 282 const checked = $checkbox.checkbox('is checked'); 272 283 let url = $checkbox.attr('data-url'); 273 284 url += '/set_allow_maintainer_edit'; 274 285 $checkbox.checkbox('set disabled'); 275 - $.ajax({url, type: 'POST', 276 - data: {_csrf: csrfToken, allow_maintainer_edit: checked}, 277 - error: () => { 278 - showTemporaryTooltip($checkbox[0], promptError); 279 - }, 280 - complete: () => { 281 - $checkbox.checkbox('set enabled'); 282 - }, 283 - }); 286 + try { 287 + const response = await POST(url, { 288 + data: {allow_maintainer_edit: checked}, 289 + }); 290 + if (!response.ok) { 291 + throw new Error('Failed to update maintainer edit permission'); 292 + } 293 + } catch (error) { 294 + console.error(error); 295 + showTemporaryTooltip($checkbox[0], promptError); 296 + } finally { 297 + $checkbox.checkbox('set enabled'); 298 + } 284 299 }, 285 300 }); 286 301 } ··· 329 344 }); 330 345 } 331 346 332 - export async function updateIssuesMeta(url, action, issueIds, elementId) { 333 - return $.ajax({ 334 - type: 'POST', 335 - url, 336 - data: { 337 - _csrf: csrfToken, 338 - action, 339 - issue_ids: issueIds, 340 - id: elementId, 341 - }, 342 - }); 347 + export async function updateIssuesMeta(url, action, issue_ids, id) { 348 + try { 349 + const response = await POST(url, {data: new URLSearchParams({action, issue_ids, id})}); 350 + if (!response.ok) { 351 + throw new Error('Failed to update issues meta'); 352 + } 353 + } catch (error) { 354 + console.error(error); 355 + } 343 356 } 344 357 345 358 export function initRepoIssueComments() { ··· 511 524 const td = ntr.find(`.add-comment-${side}`); 512 525 const commentCloud = td.find('.comment-code-cloud'); 513 526 if (commentCloud.length === 0 && !ntr.find('button[name="pending_review"]').length) { 514 - const html = await $.get($(this).closest('[data-new-comment-url]').attr('data-new-comment-url')); 515 - td.html(html); 516 - td.find("input[name='line']").val(idx); 517 - td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed'); 518 - td.find("input[name='path']").val(path); 527 + try { 528 + const response = await GET($(this).closest('[data-new-comment-url]').attr('data-new-comment-url')); 529 + const html = await response.text(); 530 + td.html(html); 531 + td.find("input[name='line']").val(idx); 532 + td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed'); 533 + td.find("input[name='path']").val(path); 519 534 520 - initDropzone(td.find('.dropzone')[0]); 521 - const editor = await initComboMarkdownEditor(td.find('.combo-markdown-editor')); 522 - editor.focus(); 535 + initDropzone(td.find('.dropzone')[0]); 536 + const editor = await initComboMarkdownEditor(td.find('.combo-markdown-editor')); 537 + editor.focus(); 538 + } catch (error) { 539 + console.error(error); 540 + } 523 541 } 524 542 }); 525 543 } ··· 547 565 const title = toggleWip.getAttribute('data-title'); 548 566 const wipPrefix = toggleWip.getAttribute('data-wip-prefix'); 549 567 const updateUrl = toggleWip.getAttribute('data-update-url'); 550 - await $.post(updateUrl, { 551 - _csrf: csrfToken, 552 - title: title?.startsWith(wipPrefix) ? title.slice(wipPrefix.length).trim() : `${wipPrefix.trim()} ${title}`, 553 - }); 554 - window.location.reload(); 568 + 569 + try { 570 + const params = new URLSearchParams(); 571 + params.append('title', title?.startsWith(wipPrefix) ? title.slice(wipPrefix.length).trim() : `${wipPrefix.trim()} ${title}`); 572 + 573 + const response = await POST(updateUrl, {data: params}); 574 + if (!response.ok) { 575 + throw new Error('Failed to toggle WIP status'); 576 + } 577 + window.location.reload(); 578 + } catch (error) { 579 + console.error(error); 580 + } 555 581 }); 556 582 } 557 583 ··· 576 602 577 603 $('#edit-title').on('click', editTitleToggle); 578 604 $('#cancel-edit-title').on('click', editTitleToggle); 579 - $('#save-edit-title').on('click', editTitleToggle).on('click', function () { 580 - const pullrequest_targetbranch_change = function (update_url) { 605 + $('#save-edit-title').on('click', editTitleToggle).on('click', async function () { 606 + const pullrequest_targetbranch_change = async function (update_url) { 581 607 const targetBranch = $('#pull-target-branch').data('branch'); 582 608 const $branchTarget = $('#branch_target'); 583 609 if (targetBranch === $branchTarget.text()) { 584 610 window.location.reload(); 585 611 return false; 586 612 } 587 - $.post(update_url, { 588 - _csrf: csrfToken, 589 - target_branch: targetBranch 590 - }).always(() => { 613 + try { 614 + await POST(update_url, {data: new URLSearchParams({target_branch: targetBranch})}); 615 + } catch (error) { 616 + console.error(error); 617 + } finally { 591 618 window.location.reload(); 592 - }); 619 + } 593 620 }; 594 621 595 622 const pullrequest_target_update_url = $(this).attr('data-target-update-url'); 596 623 if ($editInput.val().length === 0 || $editInput.val() === $issueTitle.text()) { 597 624 $editInput.val($issueTitle.text()); 598 - pullrequest_targetbranch_change(pullrequest_target_update_url); 625 + await pullrequest_targetbranch_change(pullrequest_target_update_url); 599 626 } else { 600 - $.post($(this).attr('data-update-url'), { 601 - _csrf: csrfToken, 602 - title: $editInput.val() 603 - }, (data) => { 627 + try { 628 + const params = new URLSearchParams(); 629 + params.append('title', $editInput.val()); 630 + const response = await POST($(this).attr('data-update-url'), {data: params}); 631 + const data = await response.json(); 604 632 $editInput.val(data.title); 605 633 $issueTitle.text(data.title); 606 634 if (pullrequest_target_update_url) { 607 - pullrequest_targetbranch_change(pullrequest_target_update_url); // it will reload the window 635 + await pullrequest_targetbranch_change(pullrequest_target_update_url); // it will reload the window 608 636 } else { 609 637 window.location.reload(); 610 638 } 611 - }); 639 + } catch (error) { 640 + console.error(error); 641 + } 612 642 } 613 643 return false; 614 644 });