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( '
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) {