From 8ca1a723c598ef3c488d6805531436a769568d7f Mon Sep 17 00:00:00 2001 From: Jacob Peattie Date: Wed, 16 Nov 2022 00:30:36 +1100 Subject: [PATCH] More useful errors and logging when sync fails. --- assets/js/sync/hooks.js | 103 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/assets/js/sync/hooks.js b/assets/js/sync/hooks.js index 84f4651b36..e4786a0b37 100644 --- a/assets/js/sync/hooks.js +++ b/assets/js/sync/hooks.js @@ -1,8 +1,8 @@ /** * WordPress dependencies. */ -import apiFetch from '@wordpress/api-fetch'; import { useCallback, useRef } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies. @@ -23,6 +23,98 @@ export const useIndex = () => { const abort = useRef(new AbortController()); const request = useRef(null); + const onResponse = useCallback( + /** + * Handle the response to the request. + * + * @param {Response} response Request response. + * @throws {Error} An error for unexpected responses. + * @returns {void} + */ + async (response) => { + const responseBody = await response.text(); + + const errorMessage = `${__( + 'ElasticPress: Unexpected response.', + 'elasticpress', + )}\n${responseBody}`; + + /** + * Throw an error for non-20X responses. + */ + if (!response.ok) { + if (response.status === 403) { + /** + * A 403 response will occur if the nonce has expired or + * if the user's session has expired. Reloading the page + * will reset the nonce or prompt the user to log in again. + */ + throw new Error( + __( + 'Permission denied. Reload the sync page and try again.', + 'elasticpress', + ), + ); + } else { + /** + * Log the raw response to the console to assist with + * debugging. + */ + console.error(errorMessage); // eslint-disable-line no-console + + /** + * Any other response is unexpected, and the user will + * need to troubleshoot. + */ + throw new Error( + __( + 'Something went wrong. Find troubleshooting steps at https://elasticpress.zendesk.com/hc/en-us/sections/360010868652-Troubleshooting.', + 'elasticpress', + ), + ); + } + } + + /** + * Parse the response and throw an error if it fails. + */ + try { + return JSON.parse(responseBody); + } catch (e) { + /** + * Log the raw response to the console to assist with + * debugging. + */ + console.error(e.message); // eslint-disable-line no-console + console.error(errorMessage); // eslint-disable-line no-console + + /** + * Invalid JSON is unexpected at this stage, and the user will + * need to troubleshoot. + */ + throw new Error( + __( + 'Unable to parse response. Find troubleshooting steps at https://elasticpress.zendesk.com/hc/en-us/sections/360010868652-Troubleshooting.', + 'elasticpress', + ), + ); + } + }, + [], + ); + + const onComplete = useCallback( + /** + * Handle completion of the request, whether successful or not. + * + * @returns {void} + */ + () => { + request.current = null; + }, + [], + ); + const sendRequest = useCallback( /** * Send AJAX request. @@ -35,13 +127,11 @@ export const useIndex = () => { * @returns {Promise} Current request promise. */ (options) => { - request.current = apiFetch(options).finally(() => { - request.current = null; - }); + request.current = fetch(ajaxUrl, options).then(onResponse).finally(onComplete); return request.current; }, - [], + [onComplete, onResponse], ); const cancelIndex = useCallback( @@ -60,7 +150,6 @@ export const useIndex = () => { body.append('nonce', nonce); const options = { - url: ajaxUrl, method: 'POST', body, signal: abort.current.signal, @@ -89,7 +178,6 @@ export const useIndex = () => { body.append('nonce', nonce); const options = { - url: ajaxUrl, method: 'POST', body, signal: abort.current.signal, @@ -116,7 +204,6 @@ export const useIndex = () => { body.append('nonce', nonce); const options = { - url: ajaxUrl, method: 'POST', body, signal: abort.current.signal,