feat: disabling the toast messages on view mode without debug flag (#23768)
## Description When the application is in published mode, this Pr offers the ability to disable the error toast. Only the toasts that the user initiated are displayed; all others are disabled and messages are logged in the console. When the view mode url has `debug=true` as one of the query params, then all the error toasts are visible. #### PR fixes following issue(s) Fixes #23605 Fixes #23603 #### Media > A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video > > #### Type of change > Please delete options that are not relevant. - Bug fix (non-breaking change which fixes an issue) - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) - Chore (housekeeping or task changes that don't impact user perception) - This change requires a documentation update > > > ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [x] Manual - [ ] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Test-plan-implementation#speedbreaker-features-to-consider-for-every-change) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans/_edit#areas-of-interest) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [x] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
parent
c4b9e272db
commit
e558a2ecc2
|
|
@ -30,7 +30,7 @@ describe("Test Create Api and Bind to Button widget", function () {
|
||||||
cy.updateCodeInput($el, "{{Api1.run()}}");
|
cy.updateCodeInput($el, "{{Api1.run()}}");
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.PublishtheApp();
|
_.deployMode.DeployApp();
|
||||||
|
|
||||||
cy.wait(3000);
|
cy.wait(3000);
|
||||||
cy.get("span:contains('Submit')").closest("div").click();
|
cy.get("span:contains('Submit')").closest("div").click();
|
||||||
|
|
@ -54,7 +54,7 @@ describe("Test Create Api and Bind to Button widget", function () {
|
||||||
cy.updateCodeInput($el, "{{Api1.run(() => {}, () => {})}}");
|
cy.updateCodeInput($el, "{{Api1.run(() => {}, () => {})}}");
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.PublishtheApp();
|
_.deployMode.DeployApp();
|
||||||
|
|
||||||
cy.wait(3000);
|
cy.wait(3000);
|
||||||
cy.get("span:contains('Submit')").closest("div").click();
|
cy.get("span:contains('Submit')").closest("div").click();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
import * as _ from "../../../../support/Objects/ObjectsCore";
|
||||||
|
|
||||||
|
const SHOW_ALERT_WORKING_BUTTON = "Show alert working";
|
||||||
|
const SHOW_ALERT_MSG = "Hello World!";
|
||||||
|
const SHOW_ALERT_NOT_WORKING_BUTTON = "Show alert not working";
|
||||||
|
const SHOW_ALERT_NOT_WORKING_MSG = "Correct_input2 is not defined";
|
||||||
|
const RUN_JS_OBJECT_BUTTON = "RUN JSOBJECT";
|
||||||
|
const RUN_JS_OBJECT_MSG = "Incorrect_users failed to execute";
|
||||||
|
|
||||||
|
const PAGE_LOAD_MSG = `The action "Incorrect_users" has failed.`;
|
||||||
|
|
||||||
|
describe("Published mode toggle toast with debug flag in the url", function () {
|
||||||
|
before(() => {
|
||||||
|
cy.fixture("publishedModeToastToggleDsl").then((val) => {
|
||||||
|
_.agHelper.AddDsl(val);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("1. Should not show any application related toasts", function () {
|
||||||
|
cy.fixture("datasources").then((datasourceFormData) => {
|
||||||
|
_.apiPage.CreateAndFillApi(
|
||||||
|
datasourceFormData["mockApiUrl"],
|
||||||
|
"Correct_users",
|
||||||
|
);
|
||||||
|
_.apiPage.ToggleOnPageLoadRun(true);
|
||||||
|
_.apiPage.CreateAndFillApi(
|
||||||
|
datasourceFormData["mockApiUrl"].replace("mock-api", "mock-api2err"),
|
||||||
|
"Incorrect_users",
|
||||||
|
);
|
||||||
|
_.apiPage.ToggleOnPageLoadRun(true);
|
||||||
|
_.jsEditor.CreateJSObject(
|
||||||
|
`export default {
|
||||||
|
async myFun1 () {
|
||||||
|
const res = await Correct_users.run();
|
||||||
|
showAlert("Hello info", "info");
|
||||||
|
showAlert("Hello error", "error");
|
||||||
|
showAlert("Hello warning", "warning");
|
||||||
|
showAlert("Hello success", "success");
|
||||||
|
await Incorrect_users.run();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
{
|
||||||
|
paste: true,
|
||||||
|
completeReplace: true,
|
||||||
|
toRun: false,
|
||||||
|
shouldCreateNewJSObj: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_.deployMode.DeployApp(undefined, true, false);
|
||||||
|
|
||||||
|
_.agHelper.AssertElementAbsence(_.locators._toastMsg);
|
||||||
|
|
||||||
|
_.agHelper.ClickButton(SHOW_ALERT_WORKING_BUTTON);
|
||||||
|
_.agHelper.AssertContains(SHOW_ALERT_MSG, "exist", _.locators._toastMsg);
|
||||||
|
|
||||||
|
_.agHelper.ClickButton(SHOW_ALERT_NOT_WORKING_BUTTON);
|
||||||
|
_.agHelper.AssertContains(
|
||||||
|
SHOW_ALERT_NOT_WORKING_MSG,
|
||||||
|
"not.exist",
|
||||||
|
_.locators._toastMsg,
|
||||||
|
);
|
||||||
|
|
||||||
|
_.agHelper.ClickButton(RUN_JS_OBJECT_BUTTON);
|
||||||
|
_.agHelper.AssertContains("Hello success", "exist", _.locators._toastMsg);
|
||||||
|
_.agHelper.AssertContains(
|
||||||
|
RUN_JS_OBJECT_MSG,
|
||||||
|
"not.exist",
|
||||||
|
_.locators._toastMsg,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("2. Should show all application related toasts with debug flag true in url", function () {
|
||||||
|
cy.url().then((url) => {
|
||||||
|
cy.visit({
|
||||||
|
url,
|
||||||
|
qs: {
|
||||||
|
debug: "true",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
_.agHelper.GetNAssertContains(_.locators._toastMsg, PAGE_LOAD_MSG);
|
||||||
|
|
||||||
|
_.agHelper.ClickButton(SHOW_ALERT_WORKING_BUTTON);
|
||||||
|
_.agHelper.AssertContains(SHOW_ALERT_MSG, "exist", _.locators._toastMsg);
|
||||||
|
|
||||||
|
_.agHelper.Sleep(2000);
|
||||||
|
_.agHelper.ClickButton(SHOW_ALERT_NOT_WORKING_BUTTON);
|
||||||
|
_.agHelper.AssertContains(
|
||||||
|
SHOW_ALERT_NOT_WORKING_MSG,
|
||||||
|
"exist",
|
||||||
|
_.locators._toastMsg,
|
||||||
|
);
|
||||||
|
|
||||||
|
_.agHelper.ClickButton(RUN_JS_OBJECT_BUTTON);
|
||||||
|
_.agHelper.AssertContains("Hello success", "exist", _.locators._toastMsg);
|
||||||
|
_.agHelper.AssertContains(
|
||||||
|
RUN_JS_OBJECT_MSG,
|
||||||
|
"exist",
|
||||||
|
_.locators._toastMsg,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
277
app/client/cypress/fixtures/publishedModeToastToggleDsl.json
Normal file
277
app/client/cypress/fixtures/publishedModeToastToggleDsl.json
Normal file
|
|
@ -0,0 +1,277 @@
|
||||||
|
{
|
||||||
|
"id": "64746c35c8cae423b46bf2b0",
|
||||||
|
"userPermissions": [],
|
||||||
|
"dsl": {
|
||||||
|
"widgetName": "MainContainer",
|
||||||
|
"backgroundColor": "none",
|
||||||
|
"rightColumn": 4896,
|
||||||
|
"snapColumns": 64,
|
||||||
|
"detachFromLayout": true,
|
||||||
|
"widgetId": "0",
|
||||||
|
"topRow": 0,
|
||||||
|
"bottomRow": 380,
|
||||||
|
"containerStyle": "none",
|
||||||
|
"snapRows": 124,
|
||||||
|
"parentRowSpace": 1,
|
||||||
|
"type": "CANVAS_WIDGET",
|
||||||
|
"canExtend": true,
|
||||||
|
"version": 79,
|
||||||
|
"minHeight": 1292,
|
||||||
|
"dynamicTriggerPathList": [],
|
||||||
|
"parentColumnSpace": 1,
|
||||||
|
"dynamicBindingPathList": [],
|
||||||
|
"leftColumn": 0,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"boxShadow": "none",
|
||||||
|
"iconSVG": "/static/media/icon.d0ce957b6c4640f8a7418ce846ee200e.svg",
|
||||||
|
"topRow": 0,
|
||||||
|
"labelWidth": 5,
|
||||||
|
"type": "INPUT_WIDGET_V2",
|
||||||
|
"animateLoading": true,
|
||||||
|
"resetOnSubmit": true,
|
||||||
|
"leftColumn": 0,
|
||||||
|
"dynamicBindingPathList": [
|
||||||
|
{
|
||||||
|
"key": "accentColor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "borderRadius"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"labelStyle": "",
|
||||||
|
"inputType": "TEXT",
|
||||||
|
"isDisabled": false,
|
||||||
|
"isRequired": false,
|
||||||
|
"dynamicHeight": "FIXED",
|
||||||
|
"accentColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||||
|
"showStepArrows": false,
|
||||||
|
"isVisible": true,
|
||||||
|
"version": 2,
|
||||||
|
"isLoading": false,
|
||||||
|
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||||
|
"mobileBottomRow": 39,
|
||||||
|
"widgetName": "Correct_input",
|
||||||
|
"displayName": "Input",
|
||||||
|
"searchTags": [
|
||||||
|
"form",
|
||||||
|
"text input",
|
||||||
|
"number",
|
||||||
|
"textarea"
|
||||||
|
],
|
||||||
|
"bottomRow": 4,
|
||||||
|
"parentRowSpace": 10,
|
||||||
|
"autoFocus": false,
|
||||||
|
"hideCard": false,
|
||||||
|
"mobileRightColumn": 21,
|
||||||
|
"parentColumnSpace": 12.578125,
|
||||||
|
"dynamicTriggerPathList": [],
|
||||||
|
"labelPosition": "Top",
|
||||||
|
"key": "zssusa8tjd",
|
||||||
|
"labelTextSize": "0.875rem",
|
||||||
|
"isDeprecated": false,
|
||||||
|
"rightColumn": 37,
|
||||||
|
"widgetId": "9vv4sm9msa",
|
||||||
|
"minWidth": 450,
|
||||||
|
"label": "",
|
||||||
|
"parentId": "0",
|
||||||
|
"labelAlignment": "left",
|
||||||
|
"renderMode": "CANVAS",
|
||||||
|
"mobileTopRow": 32,
|
||||||
|
"responsiveBehavior": "fill",
|
||||||
|
"mobileLeftColumn": 1,
|
||||||
|
"maxDynamicHeight": 9000,
|
||||||
|
"iconAlign": "left",
|
||||||
|
"defaultText": "Hello World!",
|
||||||
|
"minDynamicHeight": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resetFormOnClick": false,
|
||||||
|
"boxShadow": "none",
|
||||||
|
"mobileBottomRow": 36,
|
||||||
|
"widgetName": "Button1",
|
||||||
|
"onClick": "{{showAlert(Correct_input.text, 'success');}}",
|
||||||
|
"buttonColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||||
|
"displayName": "Button",
|
||||||
|
"iconSVG": "/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg",
|
||||||
|
"searchTags": [
|
||||||
|
"click",
|
||||||
|
"submit"
|
||||||
|
],
|
||||||
|
"topRow": 6,
|
||||||
|
"bottomRow": 10,
|
||||||
|
"parentRowSpace": 10,
|
||||||
|
"type": "BUTTON_WIDGET",
|
||||||
|
"hideCard": false,
|
||||||
|
"mobileRightColumn": 38,
|
||||||
|
"animateLoading": true,
|
||||||
|
"parentColumnSpace": 12.578125,
|
||||||
|
"dynamicTriggerPathList": [
|
||||||
|
{
|
||||||
|
"key": "onClick"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"leftColumn": 0,
|
||||||
|
"dynamicBindingPathList": [
|
||||||
|
{
|
||||||
|
"key": "buttonColor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "borderRadius"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "Show alert working",
|
||||||
|
"isDisabled": false,
|
||||||
|
"key": "sco9w67akk",
|
||||||
|
"isDeprecated": false,
|
||||||
|
"rightColumn": 16,
|
||||||
|
"isDefaultClickDisabled": true,
|
||||||
|
"widgetId": "cqagzdpjej",
|
||||||
|
"minWidth": 120,
|
||||||
|
"isVisible": true,
|
||||||
|
"recaptchaType": "V3",
|
||||||
|
"version": 1,
|
||||||
|
"parentId": "0",
|
||||||
|
"renderMode": "CANVAS",
|
||||||
|
"isLoading": false,
|
||||||
|
"mobileTopRow": 32,
|
||||||
|
"responsiveBehavior": "hug",
|
||||||
|
"disabledWhenInvalid": false,
|
||||||
|
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||||
|
"mobileLeftColumn": 22,
|
||||||
|
"buttonVariant": "PRIMARY",
|
||||||
|
"placement": "CENTER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resetFormOnClick": false,
|
||||||
|
"boxShadow": "none",
|
||||||
|
"mobileBottomRow": 42,
|
||||||
|
"widgetName": "Button2",
|
||||||
|
"onClick": "{{showAlert(Correct_input2.text, '');}}",
|
||||||
|
"buttonColor": "#b91c1c",
|
||||||
|
"displayName": "Button",
|
||||||
|
"iconSVG": "/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg",
|
||||||
|
"searchTags": [
|
||||||
|
"click",
|
||||||
|
"submit"
|
||||||
|
],
|
||||||
|
"topRow": 6,
|
||||||
|
"bottomRow": 10,
|
||||||
|
"parentRowSpace": 10,
|
||||||
|
"type": "BUTTON_WIDGET",
|
||||||
|
"hideCard": false,
|
||||||
|
"mobileRightColumn": 38,
|
||||||
|
"animateLoading": true,
|
||||||
|
"parentColumnSpace": 12.578125,
|
||||||
|
"dynamicTriggerPathList": [
|
||||||
|
{
|
||||||
|
"key": "onClick"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"leftColumn": 21,
|
||||||
|
"dynamicBindingPathList": [
|
||||||
|
{
|
||||||
|
"key": "borderRadius"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "Show alert not working",
|
||||||
|
"isDisabled": false,
|
||||||
|
"key": "sco9w67akk",
|
||||||
|
"isDeprecated": false,
|
||||||
|
"rightColumn": 37,
|
||||||
|
"isDefaultClickDisabled": true,
|
||||||
|
"widgetId": "s7lvatrsrg",
|
||||||
|
"minWidth": 120,
|
||||||
|
"isVisible": true,
|
||||||
|
"recaptchaType": "V3",
|
||||||
|
"version": 1,
|
||||||
|
"parentId": "0",
|
||||||
|
"renderMode": "CANVAS",
|
||||||
|
"isLoading": false,
|
||||||
|
"mobileTopRow": 38,
|
||||||
|
"responsiveBehavior": "hug",
|
||||||
|
"disabledWhenInvalid": false,
|
||||||
|
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||||
|
"mobileLeftColumn": 22,
|
||||||
|
"buttonVariant": "PRIMARY",
|
||||||
|
"placement": "CENTER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resetFormOnClick": false,
|
||||||
|
"boxShadow": "none",
|
||||||
|
"mobileBottomRow": 27,
|
||||||
|
"widgetName": "Button3",
|
||||||
|
"onClick": "{{JSObject1.myFun1();}}",
|
||||||
|
"buttonColor": "#52525b",
|
||||||
|
"displayName": "Button",
|
||||||
|
"iconSVG": "/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg",
|
||||||
|
"searchTags": [
|
||||||
|
"click",
|
||||||
|
"submit"
|
||||||
|
],
|
||||||
|
"topRow": 0,
|
||||||
|
"bottomRow": 4,
|
||||||
|
"parentRowSpace": 10,
|
||||||
|
"type": "BUTTON_WIDGET",
|
||||||
|
"hideCard": false,
|
||||||
|
"mobileRightColumn": 60,
|
||||||
|
"animateLoading": true,
|
||||||
|
"parentColumnSpace": 12.578125,
|
||||||
|
"dynamicTriggerPathList": [
|
||||||
|
{
|
||||||
|
"key": "onClick"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"leftColumn": 44,
|
||||||
|
"dynamicBindingPathList": [
|
||||||
|
{
|
||||||
|
"key": "borderRadius"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "RUN JSOBJECT",
|
||||||
|
"isDisabled": false,
|
||||||
|
"key": "sco9w67akk",
|
||||||
|
"isDeprecated": false,
|
||||||
|
"rightColumn": 60,
|
||||||
|
"isDefaultClickDisabled": true,
|
||||||
|
"widgetId": "fia0l15iti",
|
||||||
|
"minWidth": 120,
|
||||||
|
"isVisible": true,
|
||||||
|
"recaptchaType": "V3",
|
||||||
|
"version": 1,
|
||||||
|
"parentId": "0",
|
||||||
|
"renderMode": "CANVAS",
|
||||||
|
"isLoading": false,
|
||||||
|
"mobileTopRow": 23,
|
||||||
|
"responsiveBehavior": "hug",
|
||||||
|
"disabledWhenInvalid": false,
|
||||||
|
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||||
|
"mobileLeftColumn": 44,
|
||||||
|
"buttonVariant": "PRIMARY",
|
||||||
|
"placement": "CENTER"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"layoutOnLoadActions": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "64746c35c8cae423b46bf2b3",
|
||||||
|
"name": "Incorrect_users",
|
||||||
|
"confirmBeforeExecute": false,
|
||||||
|
"pluginType": "API",
|
||||||
|
"jsonPathKeys": [],
|
||||||
|
"timeoutInMillisecond": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "64746c35c8cae423b46bf2b2",
|
||||||
|
"name": "Correct_users",
|
||||||
|
"confirmBeforeExecute": false,
|
||||||
|
"pluginType": "API",
|
||||||
|
"jsonPathKeys": [],
|
||||||
|
"timeoutInMillisecond": 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"layoutOnLoadActionErrors": [],
|
||||||
|
"new": false
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,7 @@ export class DeployMode {
|
||||||
public DeployApp(
|
public DeployApp(
|
||||||
eleToCheckInDeployPage: string = this.locator._backToEditor,
|
eleToCheckInDeployPage: string = this.locator._backToEditor,
|
||||||
toCheckFailureToast = true,
|
toCheckFailureToast = true,
|
||||||
|
addDebugFlag = true,
|
||||||
) {
|
) {
|
||||||
//cy.intercept("POST", "/api/v1/applications/publish/*").as("publishAppli");
|
//cy.intercept("POST", "/api/v1/applications/publish/*").as("publishAppli");
|
||||||
// Wait before publish
|
// Wait before publish
|
||||||
|
|
@ -36,7 +37,12 @@ export class DeployMode {
|
||||||
// Stubbing window.open to open in the same tab
|
// Stubbing window.open to open in the same tab
|
||||||
cy.window().then((window) => {
|
cy.window().then((window) => {
|
||||||
cy.stub(window, "open").callsFake((url) => {
|
cy.stub(window, "open").callsFake((url) => {
|
||||||
window.location.href = Cypress.config().baseUrl + url.substring(1);
|
const updatedUrl = `${Cypress.config().baseUrl + url.substring(1)}`;
|
||||||
|
window.location.href = `${updatedUrl}${
|
||||||
|
addDebugFlag
|
||||||
|
? (updatedUrl.indexOf("?") > -1 ? "&" : "?") + "debug=true"
|
||||||
|
: ""
|
||||||
|
}`;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.get(this.locator._publishButton).click();
|
cy.get(this.locator._publishButton).click();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { spawn } from "redux-saga/effects";
|
import { call, spawn } from "redux-saga/effects";
|
||||||
import {
|
import {
|
||||||
logActionExecutionError,
|
logActionExecutionError,
|
||||||
TriggerFailureError,
|
TriggerFailureError,
|
||||||
|
|
@ -35,6 +35,6 @@ export function* executePostMessage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logActionExecutionError((error as Error).message, true);
|
yield call(logActionExecutionError, (error as Error).message, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import AppsmithConsole from "utils/AppsmithConsole";
|
import AppsmithConsole from "utils/AppsmithConsole";
|
||||||
import { ActionValidationError } from "sagas/ActionExecution/errorUtils";
|
import { ActionValidationError } from "sagas/ActionExecution/errorUtils";
|
||||||
import { getType, Types } from "utils/TypeHelpers";
|
import { getType, Types } from "utils/TypeHelpers";
|
||||||
import { toast } from "design-system";
|
import type { ToastKind } from "design-system";
|
||||||
import type { TShowAlertDescription } from "workers/Evaluation/fns/showAlert";
|
import type { TShowAlertDescription } from "workers/Evaluation/fns/showAlert";
|
||||||
|
import { call } from "redux-saga/effects";
|
||||||
|
import showToast from "sagas/ToastSagas";
|
||||||
|
|
||||||
export default function* showAlertSaga(action: TShowAlertDescription) {
|
export default function* showAlertSaga(action: TShowAlertDescription) {
|
||||||
const { payload } = action;
|
const { payload } = action;
|
||||||
|
|
@ -14,24 +16,15 @@ export default function* showAlertSaga(action: TShowAlertDescription) {
|
||||||
getType(payload.message),
|
getType(payload.message),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let kind: "success" | "info" | "warning" | "error" | undefined = undefined;
|
// This is the toast that is rendered which is user generated by using `showAlert` platform function. This is forceDisplayed no matter the conditions.
|
||||||
switch (payload.style) {
|
yield call(
|
||||||
case "info":
|
showToast,
|
||||||
kind = "info";
|
payload.message,
|
||||||
break;
|
{
|
||||||
case "success":
|
kind: payload.style as ToastKind,
|
||||||
kind = "success";
|
},
|
||||||
break;
|
{ forceDisplay: true },
|
||||||
case "warning":
|
);
|
||||||
kind = "warning";
|
|
||||||
break;
|
|
||||||
case "error":
|
|
||||||
kind = "error";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
toast.show(payload.message, {
|
|
||||||
kind: kind,
|
|
||||||
});
|
|
||||||
AppsmithConsole.info({
|
AppsmithConsole.info({
|
||||||
text: payload.style
|
text: payload.style
|
||||||
? `showAlert('${payload.message}', '${payload.style}') was triggered`
|
? `showAlert('${payload.message}', '${payload.style}') was triggered`
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import type { Types } from "utils/TypeHelpers";
|
||||||
import type { ActionTriggerKeys } from "@appsmith/workers/Evaluation/fns/index";
|
import type { ActionTriggerKeys } from "@appsmith/workers/Evaluation/fns/index";
|
||||||
import { getActionTriggerFunctionNames } from "@appsmith/workers/Evaluation/fns/index";
|
import { getActionTriggerFunctionNames } from "@appsmith/workers/Evaluation/fns/index";
|
||||||
import { getAppsmithConfigs } from "@appsmith/configs";
|
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||||
import { toast } from "design-system";
|
|
||||||
import { getAppMode } from "@appsmith/selectors/applicationSelectors";
|
import { getAppMode } from "@appsmith/selectors/applicationSelectors";
|
||||||
import AnalyticsUtil from "../../utils/AnalyticsUtil";
|
import AnalyticsUtil from "../../utils/AnalyticsUtil";
|
||||||
import {
|
import {
|
||||||
|
|
@ -17,6 +16,8 @@ import {
|
||||||
} from "../../actions/debuggerActions";
|
} from "../../actions/debuggerActions";
|
||||||
import { DEBUGGER_TAB_KEYS } from "../../components/editorComponents/Debugger/helpers";
|
import { DEBUGGER_TAB_KEYS } from "../../components/editorComponents/Debugger/helpers";
|
||||||
import store from "store";
|
import store from "store";
|
||||||
|
import showToast from "sagas/ToastSagas";
|
||||||
|
import { call } from "redux-saga/effects";
|
||||||
|
|
||||||
const APPSMITH_CONFIGS = getAppsmithConfigs();
|
const APPSMITH_CONFIGS = getAppsmithConfigs();
|
||||||
|
|
||||||
|
|
@ -62,10 +63,10 @@ export class ActionValidationError extends TriggerFailureError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const logActionExecutionError = (
|
export function* logActionExecutionError(
|
||||||
errorMessage: string,
|
errorMessage: string,
|
||||||
isExecuteJSFunc = true,
|
isExecuteJSFunc = true,
|
||||||
) => {
|
) {
|
||||||
//Commenting as per decision taken for the error hanlding epic to not show the trigger errors in the debugger.
|
//Commenting as per decision taken for the error hanlding epic to not show the trigger errors in the debugger.
|
||||||
// if (triggerPropertyName) {
|
// if (triggerPropertyName) {
|
||||||
// AppsmithConsole.addErrors([
|
// AppsmithConsole.addErrors([
|
||||||
|
|
@ -102,8 +103,9 @@ export const logActionExecutionError = (
|
||||||
store.dispatch(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.ERROR_TAB));
|
store.dispatch(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.ERROR_TAB));
|
||||||
}
|
}
|
||||||
|
|
||||||
isExecuteJSFunc &&
|
if (isExecuteJSFunc)
|
||||||
toast.show(errorMessage, {
|
// This is the toast that is rendered when any unhandled error occurs in JS object.
|
||||||
|
yield call(showToast, errorMessage, {
|
||||||
kind: "error",
|
kind: "error",
|
||||||
action: {
|
action: {
|
||||||
text: "debug",
|
text: "debug",
|
||||||
|
|
@ -111,7 +113,7 @@ export const logActionExecutionError = (
|
||||||
className: "t--toast-debug-button",
|
className: "t--toast-debug-button",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Thrown when action execution fails for some reason
|
* Thrown when action execution fails for some reason
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import {
|
||||||
getUserLocation,
|
getUserLocation,
|
||||||
} from "./geolocationSaga";
|
} from "./geolocationSaga";
|
||||||
import { setUserCurrentGeoLocation } from "actions/browserRequestActions";
|
import { setUserCurrentGeoLocation } from "actions/browserRequestActions";
|
||||||
|
import { logActionExecutionError } from "./errorUtils";
|
||||||
|
|
||||||
const mockFn = jest.fn();
|
const mockFn = jest.fn();
|
||||||
|
|
||||||
jest.mock("./errorUtils.ts", () => ({
|
jest.mock("./errorUtils.ts", () => ({
|
||||||
|
|
@ -79,8 +81,14 @@ describe("getCurrentLocationSaga", () => {
|
||||||
};
|
};
|
||||||
const iter = getCurrentLocationSaga(trigger);
|
const iter = getCurrentLocationSaga(trigger);
|
||||||
expect(iter.next().value).toEqual(call(getUserLocation, payload.options));
|
expect(iter.next().value).toEqual(call(getUserLocation, payload.options));
|
||||||
iter.next();
|
|
||||||
expect(mockFn).toBeCalled();
|
expect(iter.next().value).toEqual(
|
||||||
|
call(
|
||||||
|
logActionExecutionError,
|
||||||
|
"Cannot read properties of undefined (reading 'coords')",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
expect(iter.next().done).toBe(true);
|
expect(iter.next().done).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ function* errorCallbackHandler(triggerMeta: TriggerMeta, listenerId?: string) {
|
||||||
{ error: sanitizeGeolocationError(error) },
|
{ error: sanitizeGeolocationError(error) },
|
||||||
listenerId,
|
listenerId,
|
||||||
);
|
);
|
||||||
logActionExecutionError(error.message, true);
|
yield call(logActionExecutionError, error.message, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ export function* getCurrentLocationSaga(action: TGetGeoLocationDescription) {
|
||||||
yield put(setUserCurrentGeoLocation(currentLocation));
|
yield put(setUserCurrentGeoLocation(currentLocation));
|
||||||
return currentLocation;
|
return currentLocation;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logActionExecutionError((error as Error).message, true);
|
yield call(logActionExecutionError, (error as Error).message, true);
|
||||||
if (error instanceof GeolocationPositionError) {
|
if (error instanceof GeolocationPositionError) {
|
||||||
const sanitizedError = sanitizeGeolocationError(error);
|
const sanitizedError = sanitizeGeolocationError(error);
|
||||||
throw new GeoLocationError(sanitizedError.message, [sanitizedError]);
|
throw new GeoLocationError(sanitizedError.message, [sanitizedError]);
|
||||||
|
|
@ -135,7 +135,8 @@ export function* watchCurrentLocation(
|
||||||
if (watchId) {
|
if (watchId) {
|
||||||
// When a watch is already active, we will not start a new watch.
|
// When a watch is already active, we will not start a new watch.
|
||||||
// at a given point in time, only one watch is active
|
// at a given point in time, only one watch is active
|
||||||
logActionExecutionError(
|
yield call(
|
||||||
|
logActionExecutionError,
|
||||||
"A watchLocation is already active. Clear it before before starting a new one",
|
"A watchLocation is already active. Clear it before before starting a new one",
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
@ -165,7 +166,7 @@ export function* watchCurrentLocation(
|
||||||
|
|
||||||
export function* stopWatchCurrentLocation() {
|
export function* stopWatchCurrentLocation() {
|
||||||
if (watchId === undefined) {
|
if (watchId === undefined) {
|
||||||
logActionExecutionError("No location watch active", true);
|
yield call(logActionExecutionError, "No location watch active", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigator.geolocation.clearWatch(watchId);
|
navigator.geolocation.clearWatch(watchId);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import * as Sentry from "@sentry/react";
|
||||||
import { axiosConnectionAbortedCode } from "@appsmith/api/ApiUtils";
|
import { axiosConnectionAbortedCode } from "@appsmith/api/ApiUtils";
|
||||||
import { getLoginUrl } from "@appsmith/utils/adminSettingsHelpers";
|
import { getLoginUrl } from "@appsmith/utils/adminSettingsHelpers";
|
||||||
import type { PluginErrorDetails } from "api/ActionAPI";
|
import type { PluginErrorDetails } from "api/ActionAPI";
|
||||||
import { toast } from "design-system";
|
import showToast from "sagas/ToastSagas";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* making with error message with action name
|
* making with error message with action name
|
||||||
|
|
@ -224,7 +224,8 @@ export function* errorSaga(errorAction: ReduxAction<ErrorActionPayload>) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ErrorEffectTypes.SHOW_ALERT: {
|
case ErrorEffectTypes.SHOW_ALERT: {
|
||||||
showAlertAboutError(message);
|
// This is the toast that is rendered when any page load API fails.
|
||||||
|
yield call(showToast, message, { kind: "error" });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ErrorEffectTypes.SAFE_CRASH: {
|
case ErrorEffectTypes.SAFE_CRASH: {
|
||||||
|
|
@ -252,10 +253,6 @@ function logErrorSaga(action: ReduxAction<{ error: ErrorPayloadType }>) {
|
||||||
if (action.payload) log.error(action.payload.error);
|
if (action.payload) log.error(action.payload.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAlertAboutError(message: string) {
|
|
||||||
toast.show(message, { kind: "error" });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this saga do some logic before actually setting safeCrash to true
|
* this saga do some logic before actually setting safeCrash to true
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import type { EvalError, EvaluationError } from "utils/DynamicBindingUtils";
|
||||||
import { EvalErrorTypes, getEvalErrorPath } from "utils/DynamicBindingUtils";
|
import { EvalErrorTypes, getEvalErrorPath } from "utils/DynamicBindingUtils";
|
||||||
import { find, get, some } from "lodash";
|
import { find, get, some } from "lodash";
|
||||||
import LOG_TYPE from "entities/AppsmithConsole/logtype";
|
import LOG_TYPE from "entities/AppsmithConsole/logtype";
|
||||||
import { put, select } from "redux-saga/effects";
|
import { call, put, select } from "redux-saga/effects";
|
||||||
import type { AnyReduxAction } from "@appsmith/constants/ReduxActionConstants";
|
import type { AnyReduxAction } from "@appsmith/constants/ReduxActionConstants";
|
||||||
import AppsmithConsole from "utils/AppsmithConsole";
|
import AppsmithConsole from "utils/AppsmithConsole";
|
||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
|
|
@ -324,7 +324,7 @@ export function* dynamicTriggerErrorHandler(errors: any[]) {
|
||||||
for (const error of errors) {
|
for (const error of errors) {
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
error.errorMessage.message.message || error.errorMessage.message;
|
error.errorMessage.message.message || error.errorMessage.message;
|
||||||
logActionExecutionError(errorMessage, true);
|
yield call(logActionExecutionError, errorMessage, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
app/client/src/sagas/ToastSagas.ts
Normal file
35
app/client/src/sagas/ToastSagas.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import type { ToastProps } from "design-system";
|
||||||
|
import { toast } from "design-system";
|
||||||
|
import { APP_MODE } from "entities/App";
|
||||||
|
import { select } from "redux-saga/effects";
|
||||||
|
import { getAppMode } from "selectors/entitiesSelector";
|
||||||
|
import log from "loglevel";
|
||||||
|
|
||||||
|
type ExtraOptions = {
|
||||||
|
// This enables showing of toast no matter the conditions
|
||||||
|
forceDisplay?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows toast
|
||||||
|
* @param message
|
||||||
|
* @param [options] These are toast props that toast from design-sytem(react-toastify) library takes
|
||||||
|
* @param [extraOtions] These additional options enable the addition of additional requirements, based on which the toast will only then be produced. (for future extensibility as well)
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function* showToast(
|
||||||
|
message: string,
|
||||||
|
options?: ToastProps,
|
||||||
|
extraOtions?: ExtraOptions,
|
||||||
|
) {
|
||||||
|
const appMode: APP_MODE | undefined = yield select(getAppMode);
|
||||||
|
const urlObject = new URL(window?.location?.href);
|
||||||
|
const debugFlag = urlObject?.searchParams?.get("debug");
|
||||||
|
const debug = debugFlag === "true" || debugFlag;
|
||||||
|
if (appMode === APP_MODE.PUBLISHED && !debug && !extraOtions?.forceDisplay) {
|
||||||
|
log.error(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.show(message, options);
|
||||||
|
}
|
||||||
|
|
@ -129,9 +129,7 @@ function* executeInIntervals(
|
||||||
source: triggerMeta.source,
|
source: triggerMeta.source,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logActionExecutionError(
|
yield call(logActionExecutionError, e.message);
|
||||||
e.message,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
yield delay(interval);
|
yield delay(interval);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user