diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index d55923df4..bbbc9a61e 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -35,9 +35,9 @@ import { responseReceived, updateLastAction, setCollectionSecurityConfig, - setRequestStartTime, collectionAddOauth2CredentialsByUrl, - collectionClearOauth2CredentialsByUrl + collectionClearOauth2CredentialsByUrl, + initRunRequestEvent } from './index'; import { each } from 'lodash'; @@ -221,21 +221,26 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => { const state = getState(); const { globalEnvironments, activeGlobalEnvironmentUid } = state.globalEnvironments; const collection = findCollectionByUid(state.collections.collections, collectionUid); + const itemUid = item?.uid; - dispatch(setRequestStartTime({ - itemUid: item.uid, - collectionUid: collectionUid, - timestamp: Date.now() - })); - - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { if (!collection) { return reject(new Error('Collection not found')); } - - const itemCopy = cloneDeep(item || {}); + let collectionCopy = cloneDeep(collection); + const itemCopy = cloneDeep(item); + + const requestUid = uuid(); + itemCopy.requestUid = requestUid; + + await dispatch(initRunRequestEvent({ + requestUid, + itemUid, + collectionUid + })); + // add selected global env variables to the collection object const globalEnvironmentVariables = getGlobalEnvironmentVariables({ globalEnvironments, activeGlobalEnvironmentUid }); collectionCopy.globalEnvironmentVariables = globalEnvironmentVariables; @@ -254,8 +259,8 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => { return dispatch( responseReceived({ - itemUid: item.uid, - collectionUid: collectionUid, + itemUid, + collectionUid, response: serializedResponse }) ); @@ -266,8 +271,8 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => { console.log('>> request cancelled'); dispatch( responseReceived({ - itemUid: item.uid, - collectionUid: collectionUid, + itemUid, + collectionUid, response: null }) ); @@ -284,8 +289,8 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => { dispatch( responseReceived({ - itemUid: item.uid, - collectionUid: collectionUid, + itemUid, + collectionUid, response: errorResponse }) ); diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 5ac2ef838..67c099428 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -276,6 +276,8 @@ export const collectionsSlice = createSlice({ if (item) { item.response = null; item.cancelTokenUid = null; + item.requestUid = null; + item.requestStartTime = null; } } }, @@ -288,6 +290,7 @@ export const collectionsSlice = createSlice({ item.requestState = 'received'; item.response = action.payload.response; item.cancelTokenUid = null; + item.requestStartTime = null; if (!collection.timeline) { collection.timeline = []; @@ -1954,26 +1957,40 @@ export const collectionsSlice = createSlice({ collection.runnerResult = null; } }, + initRunRequestEvent: (state, action) => { + const { requestUid, itemUid, collectionUid } = action.payload; + const collection = findCollectionByUid(state.collections, collectionUid); + if (!collection) return; + + const item = findItemInCollection(collection, itemUid); + if (!item) return; + + item.requestState = null; + item.requestUid = requestUid; + item.requestStartTime = Date.now(); + }, runRequestEvent: (state, action) => { - const { itemUid, collectionUid, type, requestUid, hasError } = action.payload; + const { itemUid, collectionUid, type, requestUid } = action.payload; const collection = findCollectionByUid(state.collections, collectionUid); if (collection) { const item = findItemInCollection(collection, itemUid); if (item) { + // ignore outdated updates in case multiple requests are fired rapidly to avoid state inconsistency + if (item.requestUid !== requestUid) return; + if (type === 'pre-request-script-execution') { - item.requestUid = requestUid; item.preRequestScriptErrorMessage = action.payload.errorMessage; } if(type === 'post-response-script-execution') { - item.requestUid = requestUid; item.postResponseScriptErrorMessage = action.payload.errorMessage; } if (type === 'request-queued') { const { cancelTokenUid } = action.payload; - item.requestUid = requestUid; + // ignore if request is already in progress or completed + if (['sending', 'received'].includes(item.requestState)) return; item.requestState = 'queued'; item.cancelTokenUid = cancelTokenUid; } @@ -1981,10 +1998,9 @@ export const collectionsSlice = createSlice({ if (type === 'request-sent') { const { cancelTokenUid, requestSent } = action.payload; item.requestSent = requestSent; - + // sometimes the response is received before the request-sent event arrives - if (item.requestUid === requestUid && item.requestState === 'queued') { - item.requestUid = requestUid; + if (item.requestState === 'queued') { item.requestState = 'sending'; item.cancelTokenUid = cancelTokenUid; } @@ -2105,17 +2121,6 @@ export const collectionsSlice = createSlice({ } } }, - setRequestStartTime: (state, action) => { - const { itemUid, collectionUid, timestamp } = action.payload; - const collection = findCollectionByUid(state.collections, collectionUid); - - if (collection) { - const item = findItemInCollection(collection, itemUid); - if (item) { - item.requestStartTime = timestamp; - } - } - }, collectionAddOauth2CredentialsByUrl: (state, action) => { const { collectionUid, folderUid, itemUid, url, credentials, credentialsId, debugInfo } = action.payload; const collection = findCollectionByUid(state.collections, collectionUid); @@ -2309,13 +2314,13 @@ export const { collectionAddEnvFileEvent, collectionRenamedEvent, resetRunResults, + initRunRequestEvent, runRequestEvent, runFolderEvent, resetCollectionRunner, updateRequestDocs, updateFolderDocs, moveCollection, - setRequestStartTime, collectionAddOauth2CredentialsByUrl, collectionClearOauth2CredentialsByUrl, collectionGetOauth2CredentialsByUrl, diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index c97b7f63c..f5a49ca1d 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -557,7 +557,8 @@ const registerNetworkIpc = (mainWindow) => { const collectionUid = collection.uid; const collectionPath = collection.pathname; const cancelTokenUid = uuid(); - const requestUid = uuid(); + // requestUid is passed when a request is triggered; defaults to uuid() if not provided (e.g., bru.runRequest()) + const requestUid = item.requestUid || uuid(); const runRequestByItemPathname = async (relativeItemPathname) => { return new Promise(async (resolve, reject) => { @@ -699,7 +700,7 @@ const registerNetworkIpc = (mainWindow) => { // timeline prop won't be accessible in the usual way in the renderer process if we reject the promise return { statusText: error.statusText, - error: error.message, + error: error.message || 'Error occured while executing the request!', timeline: error.timeline } } @@ -837,7 +838,7 @@ const registerNetworkIpc = (mainWindow) => { // timeline prop won't be accessible in the usual way in the renderer process if we reject the promise return { status: error?.status, - error: error?.message || 'an error ocurred: debug', + error: error?.message || 'Error occured while executing the request!', timeline: error?.timeline }; }