From 50fb3143f6332f66e170e419efdead252dac3466 Mon Sep 17 00:00:00 2001 From: Dominik Heidler Date: Fri, 13 Sep 2024 14:12:02 +0200 Subject: [PATCH] Replace $.ajax() with fetch() Ticket: https://progress.opensuse.org/issues/166310 Co-authored-by: Martchus --- assets/javascripts/admin_assets.js | 49 +++++++------ assets/javascripts/admin_groups.js | 98 +++++++++++++++----------- assets/javascripts/admin_needle.js | 20 +++--- assets/javascripts/admin_user.js | 51 +++++++------- assets/javascripts/admin_worker.js | 23 +++--- assets/javascripts/audit_log.js | 27 +++++--- assets/javascripts/comments.js | 108 +++++++++++++++-------------- assets/javascripts/index.js | 27 ++++---- assets/javascripts/openqa.js | 32 ++++++--- assets/javascripts/overview.js | 17 ++--- assets/javascripts/running.js | 42 +++++++---- assets/javascripts/test_result.js | 51 +++++++++----- assets/javascripts/tests.js | 17 +++-- 13 files changed, 309 insertions(+), 253 deletions(-) diff --git a/assets/javascripts/admin_assets.js b/assets/javascripts/admin_assets.js index cd60962e672..8a0c7c42f7c 100644 --- a/assets/javascripts/admin_assets.js +++ b/assets/javascripts/admin_assets.js @@ -121,37 +121,42 @@ function reloadAssetsTable() { } function deleteAsset(assetId) { - $.ajax({ - url: urlWithBase('/api/v1/assets/' + assetId), - method: 'DELETE', - dataType: 'json', - success: function () { + fetchWithCSRF(urlWithBase(`/api/v1/assets/${assetId}`), {method: 'DELETE'}) + .then(response => { + // not checking for status code as 404 case also returns proper json + return response.json(); + }) + .then(response => { + if (response.error) throw response.error; addFlash( 'info', - 'The asset was deleted successfully. The asset table\'s contents are cached. Hence the removal is not immediately visible. To update the view use the "Trigger asset cleanup" button. Note that this is an expensive operation which might take a while.' + "The asset was deleted successfully. The asset table's contents are cached." + + 'Hence the removal is not immediately visible. To update the view use the "Trigger asset cleanup" button.' + + 'Note that this is an expensive operation which might take a while.' ); - }, - error: function (xhr, ajaxOptions, thrownError) { - var error_message = xhr.responseJSON.error; - addFlash('danger', error_message); - } - }); + }) + .catch(error => { + console.error(error); + addFlash('danger', `Error deleting asset: ${error}`); + }); } function triggerAssetCleanup(form) { - $.ajax({ - url: form.action, - method: form.method, - success: function () { + fetchWithCSRF(form.action, {method: form.method}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(response => { addFlash( 'info', - 'Asset cleanup has been triggered. Open the Minion dashboard to keep track of the task.' + `Asset cleanup has been triggered. Open the Minion dashboard to keep track of the task (gru_id #${response.gru_id}).` ); - }, - error: function (xhr, ajaxOptions, thrownError) { - addFlash('danger', 'Unable to trigger the asset cleanup: ' + thrownError); - } - }); + }) + .catch(error => { + console.error(error); + addFlash('danger', `Unable to trigger the asset cleanup: ${error}`); + }); } function showLastAssetStatusUpdate(assetStatus) { diff --git a/assets/javascripts/admin_groups.js b/assets/javascripts/admin_groups.js index 342939f1859..4e8f4cdba54 100644 --- a/assets/javascripts/admin_groups.js +++ b/assets/javascripts/admin_groups.js @@ -37,21 +37,23 @@ function showError(message) { } function fetchHtmlEntry(url, targetElement) { - $.ajax({ - url: url, - method: 'GET', - success: function (response) { + fetch(url) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.text(); + }) + .then(response => { var element = $(response); element.hide(); targetElement.prepend(element); $('#new_group_creating').hide(); $('#add_group_modal').modal('hide'); element.fadeIn('slow'); - }, - error: function (xhr, ajaxOptions, thrownError) { - showError(thrownError + ' (requesting entry HTML, group probably added though! - reload page to find out)'); - } - }); + }) + .catch(error => { + console.error(error); + showError(`${error} (requesting entry HTML, group probably added though! - reload page to find out)`); + }); } function countEmptyInputs(form) { @@ -87,7 +89,7 @@ function createGroup(form) { $('#new_group_error').hide(); $('#new_group_creating').show(); - let data = $(form).serialize(); + let data = new FormData(form); let postUrl, rowUrl, targetElement; if (form.dataset.createParent !== 'false') { postUrl = form.dataset.postParentGroupUrl; @@ -99,36 +101,26 @@ function createGroup(form) { const parentId = form.dataset.parentId; if (parentId !== 'none') { targetElement = $('#parent_group_' + parentId).find('ul'); - data += '&parent_id=' + parentId; + data.set('parent_id', parentId); } else { targetElement = $('#job_group_list'); } } - $.ajax({ - url: postUrl, - method: 'POST', - data: data, - success: function (response) { - if (!response) { - showError('Server returned no response'); - return; - } - var id = response.id; - if (!id) { - showError('Server returned no ID'); - return; - } + fetchWithCSRF(postUrl, {method: 'POST', body: data}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(response => { + if (!response) throw 'Server returned no response'; + if (!response.id) throw 'Server returned no ID'; fetchHtmlEntry(rowUrl + response.id, targetElement); - }, - error: function (xhr, ajaxOptions, thrownError) { - if (xhr.responseJSON.error) { - showError(xhr.responseJSON.error); - } else { - showError(thrownError); - } - } - }); + }) + .catch(error => { + console.error(error); + showError(error); + }); return false; } @@ -262,24 +254,25 @@ function saveReorganizedGroups() { var updateJobGroupUrl = jobGroupList.data('put-job-group-url'); // event handlers for AJAX queries - var handleError = function (xhr, ajaxOptions, thrownError) { + var handleError = function (error) { + console.error(error); $('#reorganize_groups_panel').show(); $('#reorganize_groups_error').show(); $('#reorganize_groups_progress').hide(); - $('#reorganize_groups_error_message').text(thrownError ? thrownError : 'something went wrong'); + $('#reorganize_groups_error_message').text(error ? error : 'something went wrong'); $('html, body').animate({scrollTop: 0}, 1000); }; var handleSuccess = function (response, groupLi, index, parentId) { if (!response) { - handleError(undefined, undefined, 'Server returned nothing'); + handleError('Server returned nothing'); return; } if (!response.nothingToDo) { var id = response.id; if (!id) { - handleError(undefined, undefined, 'Server returned no ID'); + handleError('Server returned no ID'); return; } @@ -292,7 +285,7 @@ function saveReorganizedGroups() { if (ajaxQueries.length) { // do next query - $.ajax(ajaxQueries.shift()); + handleQuery(ajaxQueries.shift()); } else { // all queries done if (showPanelTimeout) { @@ -325,7 +318,7 @@ function saveReorganizedGroups() { ajaxQueries.push({ url: updateGroupUrl + groupId, method: 'PUT', - data: { + body: { sort_order: groupIndex, parent_id: 'none', drag: 1 @@ -350,7 +343,7 @@ function saveReorganizedGroups() { ajaxQueries.push({ url: updateJobGroupUrl + jobGroupId, method: 'PUT', - data: { + body: { sort_order: childGroupIndex, parent_id: groupId, drag: 1 @@ -366,9 +359,30 @@ function saveReorganizedGroups() { }); if (ajaxQueries.length) { - $.ajax(ajaxQueries.shift()); + handleQuery(ajaxQueries.shift()); } else { handleSuccess({nothingToDo: true}); } return false; } + +function handleQuery(query) { + const url = query.url; + delete query.url; + const success = query.success; + delete query.success; + const error = query.error; + delete query.error; + var body = new FormData(); + for (const key in query.body) { + body.append(key, query.body[key]); + } + query.body = body; + fetchWithCSRF(url, query) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(success) + .catch(error); +} diff --git a/assets/javascripts/admin_needle.js b/assets/javascripts/admin_needle.js index f85e366a162..9178c0b6756 100644 --- a/assets/javascripts/admin_needle.js +++ b/assets/javascripts/admin_needle.js @@ -158,10 +158,12 @@ function setupAdminNeedles() { deleteBunchOfNeedles(); }; - $.ajax({ - url: url + nextIDs.join('&id='), - type: 'DELETE', - success: function (response) { + fetchWithCSRF(url + nextIDs.join('&id='), {method: 'DELETE'}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(response => { // add error affecting all deletions var singleError = response.error; if (singleError) { @@ -191,11 +193,11 @@ function setupAdminNeedles() { }); deleteBunchOfNeedles(); - }, - error: function (xhr, ajaxOptions, thrownError) { - handleSingleError(thrownError); - } - }); + }) + .catch(error => { + console.error(error); + handleSingleError(error); + }); return true; }; diff --git a/assets/javascripts/admin_user.js b/assets/javascripts/admin_user.js index d05240bc31a..8da704ee158 100644 --- a/assets/javascripts/admin_user.js +++ b/assets/javascripts/admin_user.js @@ -22,46 +22,43 @@ function setup_admin_user() { return; } - var data = form.serializeArray(); - var newRole = data[1].value; + var data = new FormData(form[0]); + var newRole = data.get('role'); - $.ajax({ - type: 'POST', - url: form.attr('action'), - data: jQuery.param(data), - success: function (data) { + fetch(form.attr('action'), {method: 'POST', body: data}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; findDefault(form).removeClass('default'); form.find('input[value="' + newRole + '"]').addClass('default'); - }, - error: function (err) { + }) + .catch(error => { + console.error(error); rollback(form); - addFlash('danger', 'An error occurred when changing the user role'); - } - }); + addFlash('danger', `An error occurred when changing the user role: ${error}`); + }); }); window.deleteUser = function (id) { if (!confirm('Are you sure you want to delete this user?')) return; - $.ajax({ - url: urlWithBase('/api/v1/user/' + id), - method: 'DELETE', - dataType: 'json', - success: function () { + fetchWithCSRF(urlWithBase('/api/v1/user/' + id), {method: 'DELETE'}) + .then(response => { + if (response.status == 500) + throw 'An internal server error has occurred. Maybe there are unsatisfied foreign key restrictions in the DB for this user.'; + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(response => { + if (response.error) throw response.error; addFlash('info', 'The user was deleted successfully.'); window.admin_user_table .row($('#user_' + id)) .remove() .draw(); - }, - error: function (xhr, ajaxOptions, thrownError) { - if (xhr.responseJSON && xhr.responseJSON.error) addFlash('danger', xhr.responseJSON.error); - else - addFlash( - 'danger', - 'An error has occurred. Maybe there are unsatisfied foreign key restrictions in the DB for this user.' - ); - } - }); + }) + .catch(error => { + console.error(error); + addFlash('danger', error); + }); }; } diff --git a/assets/javascripts/admin_worker.js b/assets/javascripts/admin_worker.js index bf8c9e543f5..2d587fb840d 100644 --- a/assets/javascripts/admin_worker.js +++ b/assets/javascripts/admin_worker.js @@ -61,18 +61,17 @@ function loadWorkerTable() { function deleteWorker(deleteBtn) { var post_url = $(deleteBtn).attr('post_delete_url'); - $.ajax({ - url: post_url, - method: 'DELETE', - dataType: 'json', - success: function (data) { + fetchWithCSRF(post_url, {method: 'DELETE'}) + .then(response => { + return response.json(); + }) + .then(response => { + if (response.error) throw response.error; var table = $('#workers').DataTable(); table.row($(deleteBtn).parents('tr')).remove().draw(); - addFlash('info', data.message); - }, - error: function (xhr, ajaxOptions, thrownError) { - var message = xhr.responseJSON.error; - addFlash('danger', "The worker couldn't be deleted: " + message); - } - }); + addFlash('info', response.message); + }) + .catch(error => { + addFlash('danger', "The worker couldn't be deleted: " + error); + }); } diff --git a/assets/javascripts/audit_log.js b/assets/javascripts/audit_log.js index 7771813fdd4..4a4b4c2441b 100644 --- a/assets/javascripts/audit_log.js +++ b/assets/javascripts/audit_log.js @@ -56,16 +56,25 @@ function undoComments(undoButton) { return; } undoButton.style.display = 'none'; - $.ajax({ - url: urlWithBase('/api/v1/comments'), - method: 'DELETE', - data: ids.map(id => `id=${id}`).join('&'), - success: () => addFlash('info', 'The comments have been deleted.'), - error: (jqXHR, textStatus, errorThrown) => { + var data = new FormData(); + console.log('ids:'); + console.log(ids); + for (const id of ids) { + data.append('id', id); + } + fetchWithCSRF(urlWithBase('/api/v1/comments'), {method: 'DELETE', body: data}) + .then(response => { + return response.json(); + }) + .then(response => { + if (response.error) throw response.error; + addFlash('info', 'The comments have been deleted.'); + }) + .catch(error => { + console.error(error); undoButton.style.display = 'inline'; - addFlash('danger', 'The comments could not be deleted: ' + getXhrError(jqXHR, textStatus, errorThrown)); - } - }); + addFlash('danger', `The comments could not be deleted: ${error}`); + }); } function getElementForEventType(type, eventData) { diff --git a/assets/javascripts/comments.js b/assets/javascripts/comments.js index 8121045f8f3..ea7ef40d1f2 100644 --- a/assets/javascripts/comments.js +++ b/assets/javascripts/comments.js @@ -34,10 +34,6 @@ function renderCommentHeading(comment, commentId) { return heading; } -function showXhrError(context, jqXHR, textStatus, errorThrown) { - window.alert(context + getXhrError(jqXHR, textStatus, errorThrown)); -} - function updateNumerOfComments() { const commentsLink = document.querySelector('a[href="#comments"]'); if (commentsLink) { @@ -51,15 +47,15 @@ function deleteComment(deleteButton) { if (!window.confirm('Do you really want to delete the comment written by ' + author + '?')) { return; } - $.ajax({ - url: deleteButton.dataset.deleteUrl, - method: 'DELETE', - success: () => { + fetchWithCSRF(deleteButton.dataset.deleteUrl, {method: 'DELETE'}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; $(deleteButton).parents('.comment-row, .pinned-comment-row').remove(); updateNumerOfComments(); - }, - error: showXhrError.bind(undefined, "The comment couldn't be deleted: ") - }); + }) + .catch(error => { + window.alert(`The comment couldn't be deleted: ${error}`); + }); } function updateComment(form) { @@ -75,31 +71,30 @@ function updateComment(form) { displayElements([textElement, form.applyChanges, form.discardChanges], 'none'); markdownElement.style.display = ''; markdownElement.innerHTML = 'Loading…'; - $.ajax({ - url: url, - method: 'PUT', - data: $(form).serialize(), - success: () => { - $.ajax({ - url: url, - method: 'GET', - success: response => { + fetchWithCSRF(url, {method: 'PUT', body: new FormData(form)}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + // get rendered markdown + fetch(url) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(comment => { const commentId = headingElement.querySelector('.comment-anchor').href.split('#comment-')[1]; - headingElement.replaceWith(renderCommentHeading(response, commentId)); - textElement.value = response.text; - markdownElement.innerHTML = response.renderedMarkdown; + headingElement.replaceWith(renderCommentHeading(comment, commentId)); + textElement.value = comment.text; + markdownElement.innerHTML = comment.renderedMarkdown; hideCommentEditor(form); - }, - error: () => location.reload() - }); - }, - error: (jqXHR, textStatus, errorThrown) => { - textElement.value = text; - markdownElement.innerHTML = markdown; - showCommentEditor(form); - window.alert("The comment couldn't be updated: " + getXhrError(jqXHR, textStatus, errorThrown)); - } - }); + }) + .catch(error => { + console.error(error); + location.reload(); + }); + }) + .catch(error => { + window.alert(`The comment couldn't be updated : ${error}`); + }); } function addComment(form, insertAtBottom) { @@ -109,22 +104,26 @@ function addComment(form, insertAtBottom) { return window.alert("The comment text mustn't be empty."); } const url = form.action; - $.ajax({ - url: url, - method: 'POST', - data: $(form).serialize(), - success: response => { - const commentId = response.id; + fetch(url, {method: 'POST', body: new FormData(form)}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(data => { + const commentId = data.id; + console.log(`Created comment #${commentId}`); // get rendered markdown - $.ajax({ - url: url + '/' + commentId, - method: 'GET', - success: response => { + fetch(`${url}/${commentId}`) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(comment => { const templateElement = document.getElementById('comment-row-template'); const commentRow = $(templateElement.innerHTML.replace(/@comment_id@/g, commentId))[0]; - commentRow.querySelector('[name="text"]').value = response.text; - commentRow.querySelector('h4').replaceWith(renderCommentHeading(response, commentId)); - commentRow.querySelector('.markdown').innerHTML = response.renderedMarkdown; + commentRow.querySelector('[name="text"]').value = comment.text; + commentRow.querySelector('h4').replaceWith(renderCommentHeading(comment, commentId)); + commentRow.querySelector('.markdown').innerHTML = comment.renderedMarkdown; let nextElement; if (!insertAtBottom) { nextElement = document.querySelectorAll('.comment-row')[0]; @@ -136,12 +135,15 @@ function addComment(form, insertAtBottom) { $('html, body').animate({scrollTop: commentRow.offsetTop}, 1000); textElement.value = ''; updateNumerOfComments(); - }, - error: () => location.reload() - }); - }, - error: showXhrError.bind(undefined, "The comment couldn't be added: ") - }); + }) + .catch(error => { + console.error(error); + location.reload(); + }); + }) + .catch(error => { + window.alert(`The comment couldn't be added: ${error}`); + }); } function insertTemplate(button) { diff --git a/assets/javascripts/index.js b/assets/javascripts/index.js index ec475518c0d..2526c423d26 100644 --- a/assets/javascripts/index.js +++ b/assets/javascripts/index.js @@ -93,28 +93,25 @@ function loadBuildResults(queryParams) { }; // query build results via AJAX using parameters from filter form - $.ajax({ - url: buildResultsElement.data('build-results-url'), - data: queryParams ? queryParams : window.location.search.substr(1), - success: function (response) { - showBuildResults(response); + var url = new URL(buildResultsElement.data('build-results-url'), window.location.href); + url.search = queryParams ? queryParams : window.location.search.substr(1); + fetch(url) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.text(); + }) + .then(responsetext => { + showBuildResults(responsetext); window.buildResultStatus = 'success'; - }, - error: function (xhr, textStatus, thrownError) { - // ignore error if just navigating away - if (textStatus !== 'timeout' && !xhr.getAllResponseHeaders()) { - return; - } - const error = xhr.responseJSON?.error; + }) + .catch(error => { const message = error ? htmlEscape(error) : 'Unable to fetch build results.'; showBuildResults( '' ); - window.buildResultStatus = 'error: ' + thrownError; - } - }); + }); } function autoRefreshRestart() { diff --git a/assets/javascripts/openqa.js b/assets/javascripts/openqa.js index dd4de2be52c..4d686a425ad 100644 --- a/assets/javascripts/openqa.js +++ b/assets/javascripts/openqa.js @@ -23,6 +23,16 @@ function setupForAll() { }); } +function getCSRFToken() { + return document.querySelector('meta[name="csrf-token"]').content; +} + +function fetchWithCSRF(resource, options) { + options.headers ??= {}; + options.headers['X-CSRF-TOKEN'] ??= getCSRFToken(); + return fetch(resource, options); +} + function makeFlashElement(text) { return typeof text === 'string' ? '' + text + '' : text; } @@ -238,11 +248,12 @@ function restartJob(ajaxUrl, jobId) { addFlash('danger', errorMessage); }; - return $.ajax({ - type: 'POST', - url: ajaxUrl, - success: function (data, res, xhr) { - var responseJSON = xhr.responseJSON; + return fetchWithCSRF(ajaxUrl, {method: 'POST'}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(responseJSON => { var newJobUrl; try { newJobUrl = responseJSON.test_url[0][jobId]; @@ -261,13 +272,12 @@ function restartJob(ajaxUrl, jobId) { if (newJobUrl) { window.location.replace(newJobUrl); } else { - showError('URL for new job not available'); + throw 'URL for new job not available'; } - }, - error: function (xhr, ajaxOptions, thrownError) { - showError(xhr.responseJSON ? xhr.responseJSON.error : undefined); - } - }); + }) + .catch(error => { + showError(error); + }); } function htmlEscape(str) { diff --git a/assets/javascripts/overview.js b/assets/javascripts/overview.js index 0e64463ab41..003f65f6cbc 100644 --- a/assets/javascripts/overview.js +++ b/assets/javascripts/overview.js @@ -301,20 +301,17 @@ function addComments(form) { controls.style.display = 'inline'; window.addCommentsModal.hide(); }; - $.ajax({ - url: form.action, - method: 'POST', - data: $(form).serialize(), - success: response => { + fetchWithCSRF(form.action, {method: 'POST', body: new FormData(form)}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; addFlash( 'info', 'The comments have been created. Reload the page to show changes.' ); done(); - }, - error: (jqXHR, textStatus, errorThrown) => { - addFlash('danger', 'The comments could not be added: ' + getXhrError(jqXHR, textStatus, errorThrown)); + }) + .catch(error => { + addFlash('danger', `The comments could not be added: ${error}`); done(); - } - }); + }); } diff --git a/assets/javascripts/running.js b/assets/javascripts/running.js index ec173d0de1e..65f9cc6efbc 100644 --- a/assets/javascripts/running.js +++ b/assets/javascripts/running.js @@ -70,8 +70,12 @@ function updateTestStatus(newStatus) { } // redraw module list if a new module have been started - $.ajax(detailsTab.panelElement.dataset.src) - .done(function (data) { + fetch(detailsTab.panelElement.dataset.src) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(data => { if (typeof data !== 'object') { console.log('No details for current job available.'); return; @@ -171,8 +175,9 @@ function updateTestStatus(newStatus) { reloadBrokenThumbnails(true); } }) - .fail(function () { + .catch(error => { console.log('ERROR: modlist fail'); + console.error(error); }); } @@ -182,15 +187,20 @@ function updateStatus() { return; } - $.ajax(testStatus.status_url) - .done(function (status) { + fetch(testStatus.status_url) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.json(); + }) + .then(status => { updateTestStatus(status); // continue polling for job state updates until the job state is done if (testStatus.state !== 'done') { setTimeout(updateStatus, 5000); } }) - .fail(function () { + .catch(error => { + console.error(error); setTimeout(reloadPage, 5000); }); } @@ -355,10 +365,12 @@ function setupRunning(jobid, status_url) { function refreshInfoPanel() { const infoPanel = document.getElementById('info_box'); - $.ajax({ - url: infoPanel.dataset.src, - method: 'GET', - success: function (response) { + fetch(infoPanel.dataset.src) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.text(); + }) + .then(response => { infoPanel.innerHTML = response; const infoBoxContent = document.getElementById('info-box-content'); if (!infoBoxContent) { @@ -372,15 +384,15 @@ function refreshInfoPanel() { infoBoxJQuery.find('.timeago').timeago(); infoBoxJQuery.find('[data-bs-toggle="popover"]').popover({html: true}); setupResultButtons(); - }, - error: function (xhr, ajaxOptions, thrownError) { + }) + .catch(error => { + console.error(error); addFlash( 'danger', - 'Unable to update the info panel.' + + `Unable to update the info panel: ${error}` + ' Retry' ); - } - }); + }); } function handleJobStateTransition(oldJobState, newJobState, newJobResult) { diff --git a/assets/javascripts/test_result.js b/assets/javascripts/test_result.js index 4d7e79fd335..db67bb979f3 100644 --- a/assets/javascripts/test_result.js +++ b/assets/javascripts/test_result.js @@ -497,27 +497,30 @@ function loadTabPanelElement(tabName, tabConfig) { return false; } tabConfig.panelElement = tabPanelElement; // for easier access in custom renderers - $.ajax({ - url: ajaxUrl, - method: 'GET', - success: function (response) { + fetch(ajaxUrl, {method: 'GET'}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + if (response.headers.get('Content-Type').includes('application/json')) return response.json(); + return response.text(); + }) + .then(response => { const customRenderer = tabConfig.renderContents; if (customRenderer) { return customRenderer.call(tabConfig, response); } tabPanelElement.innerHTML = response; - }, - error: function (xhr, ajaxOptions, thrownError) { + }) + .catch(error => { + console.error(error); const customRenderer = tabConfig.renderError; if (customRenderer) { - return customRenderer.call(tabConfig, xhr, ajaxOptions, thrownError); + return customRenderer.call(tabConfig, error); } tabPanelElement.innerHTML = ''; tabPanelElement.appendChild( - document.createTextNode('Unable to load ' + (tabConfig.descriptiveName || tabName) + '.') + document.createTextNode('Unable to load ' + (tabConfig.descriptiveName || tabName) + `: ${error}`) ); - } - }); + }); tabPanelElement.innerHTML = '

Loading ' + (tabConfig.descriptiveName || tabName) + @@ -707,14 +710,19 @@ function loadEmbeddedLogFiles(filter) { if (logFileElement.dataset.contentsLoaded) { return; } - $.ajax(logFileElement.dataset.src) - .done(function (response) { + fetch(logFileElement.dataset.src) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.text(); + }) + .then(response => { const lines = (logFileElement.content = response.split(/\r?\n/)); filter ? filter() : showLogLines(logFileElement, lines, false); logFileElement.dataset.contentsLoaded = true; }) - .fail(function (jqXHR, textStatus, errorThrown) { - logFileElement.appendChild(document.createTextNode('Unable to load logfile: ' + errorThrown)); + .catch(error => { + log.error(error); + logFileElement.appendChild(document.createTextNode(`Unable to load logfile: ${error}`)); }); }); } @@ -922,20 +930,25 @@ function renderCommentsTab(response) { } const id = found[1]; const url = urlWithBase('/api/v1/experimental/jobs/' + id + '/status'); - $.ajax(url) - .done(function (response) { + fetch(url) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; + return response.text(); + }) + .then(comments => { const span = document.createElement('span'); span.className = 'openqa-testref'; const i = document.createElement('i'); - const job = response; - const stateHTML = testStateHTML(job); + const stateHTML = testStateHTML(comments); i.className = stateHTML[0]; span.title = stateHTML[1]; span.appendChild(i); element.parentNode.replaceChild(span, element); span.appendChild(element); }) - .fail(function (jqXHR, textStatus, errorThrown) {}); + .catch(error => { + console.error(error); + }); }); } diff --git a/assets/javascripts/tests.js b/assets/javascripts/tests.js index 72457253315..6591562fc11 100644 --- a/assets/javascripts/tests.js +++ b/assets/javascripts/tests.js @@ -191,16 +191,15 @@ function changeJobPrio(jobId, delta, linkElement) { } var newPrio = currentPrio + delta; - $.ajax({ - url: urlWithBase('/api/v1/jobs/' + jobId + '/prio?prio=' + newPrio), - method: 'POST', - success: function (result) { + + fetchWithCSRF(urlWithBase(`/api/v1/jobs/${jobId}/prio?prio=${newPrio}`), {method: 'POST'}) + .then(response => { + if (!response.ok) throw `Server returned ${response.status}: ${response.statusText}`; prioValueElement.text(newPrio); - }, - error: function (xhr, ajaxOptions, thrownError) { - addFlash('danger', 'Unable to set the priority value of job ' + jobId + '.'); - } - }); + }) + .catch(error => { + addFlash('danger', `Unable to set the priority value of job ${jobId}: ${error}`); + }); } function renderTestSummary(data) {