mirror of
https://github.com/usebruno/bruno.git
synced 2025-01-22 05:38:40 +01:00
[Feature] Stop button for runner execution (#1580)
* First attempts * Sending cancel token in run-folder-event * Remove logs, update lock * cancelTokenUid with default value * Indentation * Generating token in the main process side * Removing uuid import
This commit is contained in:
parent
eab50f01d7
commit
942a895ae0
24608
package-lock.json
generated
24608
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import path from 'path';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { get, cloneDeep } from 'lodash';
|
||||
import { runCollectionFolder } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { runCollectionFolder, cancelRunnerExecution } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { resetCollectionRunner } from 'providers/ReduxStore/slices/collections';
|
||||
import { findItemInCollection, getTotalRequestCountInCollection } from 'utils/collections';
|
||||
import { IconRefresh, IconCircleCheck, IconCircleX, IconCheck, IconX, IconRun } from '@tabler/icons';
|
||||
@ -32,6 +32,7 @@ export default function RunnerResults({ collection }) {
|
||||
|
||||
const collectionCopy = cloneDeep(collection);
|
||||
const runnerInfo = get(collection, 'runnerResult.info', {});
|
||||
|
||||
const items = cloneDeep(get(collection, 'runnerResult.items', []))
|
||||
.map((item) => {
|
||||
const info = findItemInCollection(collectionCopy, item.uid);
|
||||
@ -81,6 +82,10 @@ export default function RunnerResults({ collection }) {
|
||||
);
|
||||
};
|
||||
|
||||
const cancelExecution = () => {
|
||||
dispatch(cancelRunnerExecution(runnerInfo.cancelTokenUid));
|
||||
};
|
||||
|
||||
const totalRequestsInCollection = getTotalRequestCountInCollection(collectionCopy);
|
||||
const passedRequests = items.filter((item) => {
|
||||
return item.status !== 'error' && item.testStatus === 'pass' && item.assertionStatus === 'pass';
|
||||
@ -114,9 +119,16 @@ export default function RunnerResults({ collection }) {
|
||||
|
||||
return (
|
||||
<StyledWrapper className="px-4 pb-4 flex flex-grow flex-col relative">
|
||||
<div className="font-medium mt-6 mb-4 title flex items-center">
|
||||
Runner
|
||||
<IconRun size={20} strokeWidth={1.5} className="ml-2" />
|
||||
<div className="flex flex-row mt-6 mb-4">
|
||||
<div className="font-medium title flex items-center">
|
||||
Runner
|
||||
<IconRun size={20} strokeWidth={1.5} className="ml-2" />
|
||||
</div>
|
||||
{runnerInfo.status !== 'ended' && runnerInfo.cancelTokenUid && (
|
||||
<button className="btn ml-6 btn-sm btn-danger" onClick={cancelExecution}>
|
||||
Cancel Execution
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-1">
|
||||
<div className="flex flex-col flex-1">
|
||||
@ -195,7 +207,6 @@ export default function RunnerResults({ collection }) {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{runnerInfo.status === 'ended' ? (
|
||||
<div className="mt-2 mb-4">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary mt-6" onClick={runAgain}>
|
||||
|
@ -208,6 +208,10 @@ export const cancelRequest = (cancelTokenUid, item, collection) => (dispatch) =>
|
||||
.catch((err) => console.log(err));
|
||||
};
|
||||
|
||||
export const cancelRunnerExecution = (cancelTokenUid) => (dispatch) => {
|
||||
cancelNetworkRequest(cancelTokenUid).catch((err) => console.log(err));
|
||||
};
|
||||
|
||||
export const runCollectionFolder = (collectionUid, folderUid, recursive) => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const collection = findCollectionByUid(state.collections.collections, collectionUid);
|
||||
|
@ -1290,7 +1290,7 @@ export const collectionsSlice = createSlice({
|
||||
}
|
||||
},
|
||||
runFolderEvent: (state, action) => {
|
||||
const { collectionUid, folderUid, itemUid, type, isRecursive, error } = action.payload;
|
||||
const { collectionUid, folderUid, itemUid, type, isRecursive, error, cancelTokenUid } = action.payload;
|
||||
const collection = findCollectionByUid(state.collections, collectionUid);
|
||||
|
||||
if (collection) {
|
||||
@ -1306,6 +1306,7 @@ export const collectionsSlice = createSlice({
|
||||
info.collectionUid = collectionUid;
|
||||
info.folderUid = folderUid;
|
||||
info.isRecursive = isRecursive;
|
||||
info.cancelTokenUid = cancelTokenUid;
|
||||
info.status = 'started';
|
||||
}
|
||||
|
||||
|
@ -400,9 +400,9 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
const scriptingConfig = get(brunoConfig, 'scripts', {});
|
||||
|
||||
try {
|
||||
const cancelToken = axios.CancelToken.source();
|
||||
request.cancelToken = cancelToken.token;
|
||||
saveCancelToken(cancelTokenUid, cancelToken);
|
||||
const controller = new AbortController();
|
||||
request.signal = controller.signal;
|
||||
saveCancelToken(cancelTokenUid, controller);
|
||||
|
||||
await runPreRequest(
|
||||
request,
|
||||
@ -586,7 +586,7 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
ipcMain.handle('cancel-http-request', async (event, cancelTokenUid) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (cancelTokenUid && cancelTokens[cancelTokenUid]) {
|
||||
cancelTokens[cancelTokenUid].cancel();
|
||||
cancelTokens[cancelTokenUid].abort();
|
||||
deleteCancelToken(cancelTokenUid);
|
||||
resolve();
|
||||
} else {
|
||||
@ -679,10 +679,14 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
const collectionUid = collection.uid;
|
||||
const collectionPath = collection.pathname;
|
||||
const folderUid = folder ? folder.uid : null;
|
||||
const cancelTokenUid = uuid();
|
||||
const brunoConfig = getBrunoConfig(collectionUid);
|
||||
const scriptingConfig = get(brunoConfig, 'scripts', {});
|
||||
const collectionRoot = get(collection, 'root', {});
|
||||
|
||||
const abortController = new AbortController();
|
||||
saveCancelToken(cancelTokenUid, abortController);
|
||||
|
||||
if (!folder) {
|
||||
folder = collection;
|
||||
}
|
||||
@ -691,7 +695,8 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
type: 'testrun-started',
|
||||
isRecursive: recursive,
|
||||
collectionUid,
|
||||
folderUid
|
||||
folderUid,
|
||||
cancelTokenUid
|
||||
});
|
||||
|
||||
try {
|
||||
@ -717,6 +722,13 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
let currentRequestIndex = 0;
|
||||
let nJumps = 0; // count the number of jumps to avoid infinite loops
|
||||
while (currentRequestIndex < folderRequests.length) {
|
||||
// user requested to cancel runner
|
||||
if (abortController.signal.aborted) {
|
||||
let error = new Error('Runner execution cancelled');
|
||||
error.isCancel = true;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const item = folderRequests[currentRequestIndex];
|
||||
let nextRequestName;
|
||||
const itemUid = item.uid;
|
||||
@ -770,6 +782,7 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
...eventData
|
||||
});
|
||||
|
||||
request.signal = abortController.signal;
|
||||
const axiosInstance = await configureRequest(
|
||||
collectionUid,
|
||||
request,
|
||||
@ -803,7 +816,7 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
...eventData
|
||||
});
|
||||
} catch (error) {
|
||||
if (error?.response) {
|
||||
if (error?.response && !axios.isCancel(error)) {
|
||||
const { data, dataBuffer } = parseDataFromResponse(error.response);
|
||||
error.response.data = data;
|
||||
|
||||
@ -928,15 +941,19 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
}
|
||||
}
|
||||
|
||||
deleteCancelToken(cancelTokenUid);
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'testrun-ended',
|
||||
collectionUid,
|
||||
folderUid
|
||||
});
|
||||
} catch (error) {
|
||||
deleteCancelToken(cancelTokenUid);
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'error',
|
||||
error
|
||||
type: 'testrun-ended',
|
||||
collectionUid,
|
||||
folderUid,
|
||||
error: error && !error.isCancel ? error : null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
const cancelTokens = {};
|
||||
|
||||
const saveCancelToken = (uid, axiosRequest) => {
|
||||
cancelTokens[uid] = axiosRequest;
|
||||
const saveCancelToken = (uid, abortController) => {
|
||||
cancelTokens[uid] = abortController;
|
||||
};
|
||||
|
||||
const deleteCancelToken = (uid) => {
|
||||
|
Loading…
Reference in New Issue
Block a user