From 0e49c6efa9dc87f508c1664186c8adbd76e4f3e7 Mon Sep 17 00:00:00 2001 From: Ayangade Adeoluwa <37867493+Irongade@users.noreply.github.com> Date: Wed, 31 Aug 2022 19:08:42 +0100 Subject: [PATCH] fix: replace action execution cancellation toast errors with a better one (#16277) * Remove error messages when user cancel action executions * Add toast message after user cancels action execution * Change error message * Cypress validation for Bug #1609 added Co-authored-by: Aishwarya UR --- .../BugTests/AbortAction_Spec.ts | 20 ++++++----- app/client/src/api/ApiUtils.ts | 3 +- app/client/src/ce/constants/messages.ts | 2 ++ .../editorComponents/ApiResponseView.tsx | 2 +- .../sagas/ActionExecution/PluginActionSaga.ts | 34 ++++++++++++++----- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/BugTests/AbortAction_Spec.ts b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/BugTests/AbortAction_Spec.ts index 11163b0647..6bd0e42c81 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/BugTests/AbortAction_Spec.ts +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/BugTests/AbortAction_Spec.ts @@ -1,6 +1,6 @@ import { ObjectsRegistry } from "../../../../support/Objects/Registry"; -let agHelper = ObjectsRegistry.AggregateHelper, +const agHelper = ObjectsRegistry.AggregateHelper, locator = ObjectsRegistry.CommonLocators, apiPage = ObjectsRegistry.ApiPage, dataSources = ObjectsRegistry.DataSources; @@ -10,22 +10,23 @@ let dsName: any; const largeResponseApiUrl = "https://api.publicapis.org/entries"; //"https://jsonplaceholder.typicode.com/photos";//Commenting since this is faster sometimes & case is failing -const ERROR_ACTION_EXECUTE_FAIL = (actionName: any) => - `${actionName} action returned an error response`; +export const ACTION_EXECUTION_CANCELLED = (actionName: string) => + `${actionName} was cancelled`; describe("Abort Action Execution", function() { - it("1. Bug #14006 - Cancel Request button should abort API action execution", function() { + it("1. Bug #14006, #16093 - Cancel Request button should abort API action execution", function() { apiPage.CreateAndFillApi(largeResponseApiUrl, "AbortApi", 0); apiPage.RunAPI(false, 0); agHelper.GetNClick(locator._cancelActionExecution, 0, true); - agHelper.AssertContains(ERROR_ACTION_EXECUTE_FAIL("AbortApi")); - agHelper.ActionContextMenuWithInPane("Delete", "Are you sure?") + agHelper.AssertContains(ACTION_EXECUTION_CANCELLED("AbortApi")); + agHelper.AssertElementAbsence(locator._specificToast("{}")); //Assert that empty toast does not appear - Bug #16093 + agHelper.ActionContextMenuWithInPane("Delete", "Are you sure?"); }); // Queries were resolving quicker than we could cancel them // Commenting this out till we can find a query that resolves slow enough for us to cancel its execution. - it("2. Bug #14006 Cancel Request button should abort Query action execution", function() { + it("2. Bug #14006, #16093 Cancel Request button should abort Query action execution", function() { dataSources.CreateDataSource("MySql"); cy.get("@dsName").then(($dsName) => { dsName = $dsName; @@ -37,8 +38,9 @@ describe("Abort Action Execution", function() { dataSources.SetQueryTimeout(0); dataSources.RunQuery(false, false, 0); agHelper.GetNClick(locator._cancelActionExecution, 0, true); - agHelper.AssertContains(ERROR_ACTION_EXECUTE_FAIL("AbortQuery")); - agHelper.ActionContextMenuWithInPane("Delete", "Are you sure?") + agHelper.AssertContains(ACTION_EXECUTION_CANCELLED("AbortQuery")); + agHelper.AssertElementAbsence(locator._specificToast("{}")); //Assert that empty toast does not appear - Bug #16093 + agHelper.ActionContextMenuWithInPane("Delete", "Are you sure?"); dataSources.DeleteDatasouceFromWinthinDS(dsName); }); }); diff --git a/app/client/src/api/ApiUtils.ts b/app/client/src/api/ApiUtils.ts index 524fe96761..4d410ec531 100644 --- a/app/client/src/api/ApiUtils.ts +++ b/app/client/src/api/ApiUtils.ts @@ -17,6 +17,7 @@ import { logoutUser } from "actions/userActions"; import { AUTH_LOGIN_URL } from "constants/routes"; import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import getQueryParamsObject from "utils/getQueryParamsObject"; +import { UserCancelledActionExecutionError } from "sagas/ActionExecution/errorUtils"; const executeActionRegex = /actions\/execute/; const timeoutErrorRegex = /timeout of (\d+)ms exceeded/; @@ -77,7 +78,7 @@ export const apiFailureResponseInterceptor = (error: any) => { // Return if the call was cancelled via cancel token if (axios.isCancel(error)) { - return; + throw new UserCancelledActionExecutionError(); } // Return modified response if action execution failed diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index 355b33b1a3..2980afc230 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -222,6 +222,8 @@ export const ERROR_DATEPICKER_MAX_DATE = () => export const ERROR_WIDGET_DOWNLOAD = (err: string) => `Download failed. ${err}`; export const ERROR_PLUGIN_ACTION_EXECUTE = (actionName: string) => `${actionName} failed to execute`; +export const ACTION_EXECUTION_CANCELLED = (actionName: string) => + `${actionName} was cancelled`; export const ERROR_FAIL_ON_PAGE_LOAD_ACTIONS = () => `Failed to execute actions during page load`; export const ERROR_ACTION_EXECUTE_FAIL = (actionName: string) => diff --git a/app/client/src/components/editorComponents/ApiResponseView.tsx b/app/client/src/components/editorComponents/ApiResponseView.tsx index 6cd5d3a288..efed32f26b 100644 --- a/app/client/src/components/editorComponents/ApiResponseView.tsx +++ b/app/client/src/components/editorComponents/ApiResponseView.tsx @@ -216,7 +216,7 @@ type Props = ReduxStateProps & export const EMPTY_RESPONSE: ActionResponse = { statusCode: "", duration: "", - body: {}, + body: "", headers: {}, request: { headers: {}, diff --git a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts index c78f5092c1..299f4a6940 100644 --- a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts @@ -43,6 +43,7 @@ import { ERROR_ACTION_EXECUTE_FAIL, ERROR_FAIL_ON_PAGE_LOAD_ACTIONS, ERROR_PLUGIN_ACTION_EXECUTE, + ACTION_EXECUTION_CANCELLED, } from "@appsmith/constants/messages"; import { Variant } from "components/ads/common"; import { @@ -561,6 +562,19 @@ function* runActionSaga( // When running from the pane, we just want to end the saga if the user has // cancelled the call. No need to log any errors if (e instanceof UserCancelledActionExecutionError) { + // cancel action but do not throw any error. + yield put({ + type: ReduxActionErrorTypes.RUN_ACTION_ERROR, + payload: { + error: e.name, + id: reduxAction.payload.id, + show: false, + }, + }); + Toaster.show({ + text: createMessage(ACTION_EXECUTION_CANCELLED, actionObject.name), + variant: Variant.danger, + }); return; } log.error(e); @@ -910,14 +924,14 @@ function* executePluginActionSaga( params, ); - const response: ActionExecutionResponse = yield ActionAPI.executeAction( - formData, - timeout, - ); - PerformanceTracker.stopAsyncTracking( - PerformanceTransactionName.EXECUTE_ACTION, - ); try { + const response: ActionExecutionResponse = yield ActionAPI.executeAction( + formData, + timeout, + ); + PerformanceTracker.stopAsyncTracking( + PerformanceTransactionName.EXECUTE_ACTION, + ); yield validateResponse(response); const payload = createActionExecutionResponse(response); @@ -949,7 +963,11 @@ function* executePluginActionSaga( response: EMPTY_RESPONSE, }), ); - throw new PluginActionExecutionError("Response not valid", false, response); + if (e instanceof UserCancelledActionExecutionError) { + throw new UserCancelledActionExecutionError(); + } + + throw new PluginActionExecutionError("Response not valid", false); } }