fix: Fall of the error toasts wall (#35839)

This commit is contained in:
Hetu Nandu 2024-09-05 11:06:43 +05:30 committed by GitHub
parent 5aa93926ef
commit 65eb8546f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
62 changed files with 464 additions and 321 deletions

View File

@ -238,7 +238,7 @@ describe("storeValue Action test", { tags: ["@tag.JS"] }, () => {
});
agHelper.ClickButton("Test store logs");
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.OpenDebugger();
debuggerHelper.ClickLogsTab();
debuggerHelper.changeLogsGroup("System logs");
debuggerHelper.DoesConsoleLogExist("storeValue('xyz', '123', true)");

View File

@ -11,6 +11,7 @@ import {
draggableWidgets,
fakerHelper,
dataManager,
debuggerHelper,
} from "../../../../support/Objects/ObjectsCore";
const widgetsToTest = {
@ -180,8 +181,18 @@ Object.entries(widgetsToTest).forEach(([widgetSelector, testConfig], index) => {
agHelper.GetNClick(locators._widgetInputSelector(widgetSelector));
agHelper.PressDelete();
//Since widget is removed & Button is still holding its reference
debuggerHelper.AssertDebugError(
`'${testConfig.widgetPrefixName}1' is not defined.`,
"",
true,
false,
);
debuggerHelper.CloseBottomBar();
agHelper.GetNClick(getWidgetSelector(draggableWidgets.BUTTON));
agHelper.AssertContains("is not defined"); //Since widget is removed & Button is still holding its reference
agHelper.ValidateToastMessage(
`${testConfig.widgetPrefixName}1 is not defined`,
);
agHelper.PressDelete();
agHelper.GetNClick(getWidgetSelector(draggableWidgets.TEXT)).click();

View File

@ -122,7 +122,7 @@ describe(
deployMode.NavigateBacktoEditor();
//verify runAstros triggered on PageLaoad of Edit page!
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.OpenDebugger();
debuggerHelper.ClickLogsTab();
debuggerHelper.DebuggerLogsFilter("JSObject1.runAstros");
debuggerHelper.DoesConsoleLogExist("JS Function executed successfully");

View File

@ -27,7 +27,7 @@ describe(
apiPage.EnterHeader("test", "test");
debuggerHelper.AssertErrorCount(1);
EditorNavigation.ShowCanvas();
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.OpenDebugger();
debuggerHelper.ClicklogEntityLink();
agHelper.AssertElementVisibility(apiPage._nextCursorValue);

View File

@ -30,7 +30,7 @@ describe("JSObjects", () => {
shouldCreateNewJSObj: true,
});
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.OpenDebugger();
debuggerHelper.ClicklogEntityLink();
agHelper.AssertCursorInput(".js-editor", { ch: 20, line: 6 });

View File

@ -66,8 +66,7 @@ describe(
);
debuggerHelper.AssertErrorCount(2);
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.ClicklogEntityLink();
debuggerHelper.OpenDebugger();
agHelper.AssertElementVisibility(
".t--actionConfiguration\\.formData\\.limitDocuments\\.data",
);

View File

@ -14,7 +14,7 @@ describe(
_.debuggerHelper.AssertErrorCount(1);
_.propPane.ToggleSection("general");
_.agHelper.AssertElementAbsence("animateloading");
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink();
_.propPane.AssertIfPropertyIsVisible("animateloading");
@ -28,7 +28,7 @@ describe(
_.propPane.EnterJSContext("visible", "{{test}}", true, false);
_.debuggerHelper.AssertErrorCount(1);
_.propPane.NavigateBackToPropertyPane();
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink();
_.agHelper.GetNAssertContains(_.propPane._paneTitle, "Tab 2");
_.propPane.AssertIfPropertyIsVisible("visible");
@ -48,7 +48,7 @@ describe(
_.debuggerHelper.AssertErrorCount(1);
_.propPane.NavigateBackToPropertyPane(false);
_.propPane.NavigateBackToPropertyPane();
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink();
_.agHelper.GetNAssertContains(_.propPane._paneTitle, "Menu Item");
_.propPane.AssertIfPropertyIsVisible("icon");
@ -65,7 +65,7 @@ describe(
_.propPane.MoveToTab("Style");
_.debuggerHelper.AssertErrorCount(1);
_.propPane.NavigateBackToPropertyPane();
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink();
_.agHelper.GetNAssertContains(_.propPane._paneTitle, "Second Menu Item");
_.propPane.AssertIfPropertyIsVisible("disabled");
@ -110,7 +110,7 @@ describe(
_.propPane.NavigateBackToPropertyPane(false);
_.propPane.NavigateBackToPropertyPane();
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink();
_.agHelper.GetNAssertContains(_.propPane._paneTitle, "Custom Field 2");
_.propPane.AssertIfPropertyIsVisible("borderradius");
@ -133,7 +133,7 @@ describe(
_.propPane.EnterJSContext("disabled", "{{test}}", true, false);
_.debuggerHelper.AssertErrorCount(2);
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink(true);
_.agHelper.GetNAssertContains(_.propPane._paneTitle, "First Menu Item");
_.debuggerHelper.CloseBottomBar();
@ -173,7 +173,7 @@ describe(
_.propPane.ToggleSection("validation");
_.propPane.NavigateBackToPropertyPane();
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink();
_.agHelper.GetNAssertContains(_.propPane._paneTitle, "imdb_id");
_.debuggerHelper.CloseBottomBar();

View File

@ -3,9 +3,6 @@ import EditorNavigation, {
EntityType,
} from "../../../../support/Pages/EditorNavigation";
import PageList from "../../../../support/Pages/PageList";
const locators = {
errorPageTitle: ".t--error-page-title",
};
describe("Pages", { tags: ["@tag.IDE"] }, function () {
let veryLongPageName = `abcdefghijklmnopqrstuvwxyz1234`;
@ -36,7 +33,7 @@ describe("Pages", { tags: ["@tag.IDE"] }, function () {
EditorNavigation.SelectEntityByName("Page1 Copy", EntityType.Page);
//Checks if 404 is showing correct route
cy.visit("/route-that-does-not-exist");
cy.get(locators.errorPageTitle).should(($x) => {
cy.get(_.locators.errorPageTitle).should(($x) => {
expect($x).contain(Cypress.env("MESSAGES").PAGE_NOT_FOUND());
});
});

View File

@ -7,7 +7,7 @@ describe("Entity bottom bar", { tags: ["@tag.IDE"] }, () => {
//Verify if bottom bar is closed.
_.debuggerHelper.AssertClosed();
//verify if bottom bar is open on clicking debugger icon in canvas.
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.AssertOpen(PageType.Canvas);
//Verify if selected tab is errors in tab title.
_.debuggerHelper.AssertSelectedTab(
@ -48,7 +48,7 @@ describe("Entity bottom bar", { tags: ["@tag.IDE"] }, () => {
//Verify that the errors tab is still closed.
_.debuggerHelper.AssertClosed();
//Verify if bottom bar opens on clicking debugger icon in api page.
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.AssertOpen(PageType.API);
//Verify if selected tab is errors in tab title.
_.debuggerHelper.AssertSelectedTab(
@ -70,7 +70,7 @@ describe("Entity bottom bar", { tags: ["@tag.IDE"] }, () => {
//Expecting errors tab to be closed as this is now a datasource
_.debuggerHelper.AssertClosed();
//Verify if bottom bar opens on clicking debugger icon in datasource page.
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.AssertOpen(PageType.DataSources);
});
@ -91,7 +91,7 @@ describe("Entity bottom bar", { tags: ["@tag.IDE"] }, () => {
_.debuggerHelper.AssertClosed();
//Verify if bottom bar opens on clicking debugger icon in query page.
_.dataSources.CreateQueryAfterDSSaved();
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.AssertOpen(PageType.Query);
//Verify if bottom bar is closed on clicking close icon in query page.
_.debuggerHelper.CloseBottomBar();
@ -130,7 +130,7 @@ describe("Entity bottom bar", { tags: ["@tag.IDE"] }, () => {
_.debuggerHelper.AssertClosed();
//Verify if bottom bar opens on clicking debugger icon in query page.
_.dataSources.CreateQueryAfterDSSaved();
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.AssertOpen(PageType.Query);
//Verify if bottom bar is closed on clicking close icon in query page.
_.debuggerHelper.CloseBottomBar();

View File

@ -33,13 +33,21 @@ describe("Sanitise toast error messages", () => {
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
_.propPane.EnterJSContext("onClick", "{{a.kjbfjdfbkds()}}");
_.agHelper.ClickButton("Submit");
_.agHelper.WaitUntilToastDisappear("a is not defined");
_.debuggerHelper.AssertDebugError("'a' is not defined.", "", true, false);
});
it("2. Does not show type error label when js obj function does not exist", () => {
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
_.propPane.EnterJSContext("onClick", "{{JSObject1.myFun1efef()}}");
// Assert the lint error that shows up
_.debuggerHelper.AssertDebugError(
`"myFun1efef" doesn't exist in JSObject1`,
"",
false,
false,
);
_.agHelper.ClickButton("Submit");
// Assert the execution error that shows up
_.agHelper.WaitUntilToastDisappear("Object1.myFun1efef is not a function");
});

View File

@ -7,7 +7,7 @@ describe("Inspect Entity", function () {
it("1. Check whether depedencies and references are shown correctly", function () {
cy.openPropertyPane("inputwidgetv2");
cy.testJsontext("defaultvalue", "{{Button1.text}}");
_.agHelper.GetNClick(".t--debugger-count");
_.debuggerHelper.OpenDebugger();
cy.contains(".ads-v2-tabs__list-tab", "Inspect entity").click();
cy.contains(".t--dependencies-item", "Button1").click();
cy.contains(".t--dependencies-item", "Input1");

View File

@ -1,5 +1,3 @@
import commonlocators from "../../../../locators/commonlocators.json";
import { homePage } from "../../../../support/Objects/ObjectsCore";
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
import EditorNavigation, {
EntityType,
@ -26,18 +24,18 @@ describe("Debugger logs", function () {
logString = generateTestLogString();
});
it("3. Console log on button click with normal moustache binding", function () {
it("1. Console log on button click with normal moustache binding", function () {
ee.DragDropWidgetNVerify("buttonwidget", 200, 200);
// Testing with normal log in moustache binding
propPane.EnterJSContext("onClick", `{{console.log("${logString}")}}`);
agHelper.Sleep(2000);
agHelper.ClickButton("Submit");
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.OpenDebugger();
agHelper.GetNClick(jsEditor._logsTab);
debuggerHelper.DoesConsoleLogExist(logString);
});
it("4. Console log on button click with arrow function IIFE", function () {
it("2. Console log on button click with arrow function IIFE", function () {
debuggerHelper.ClearLogs();
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
// Testing with normal log in iifee
@ -51,7 +49,7 @@ describe("Debugger logs", function () {
debuggerHelper.DoesConsoleLogExist(logString);
});
it("5. Console log on button click with function keyword IIFE", function () {
it("3. Console log on button click with function keyword IIFE", function () {
debuggerHelper.ClearLogs();
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
// Testing with normal log in iifee
@ -65,7 +63,7 @@ describe("Debugger logs", function () {
debuggerHelper.DoesConsoleLogExist(logString);
});
it("6. Console log on button click with async function IIFE", function () {
it("4. Console log on button click with async function IIFE", function () {
debuggerHelper.ClearLogs();
// Testing with normal log in iifee
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
@ -79,7 +77,7 @@ describe("Debugger logs", function () {
debuggerHelper.DoesConsoleLogExist(logString);
});
it("7. Console log on button click with mixed function IIFE", function () {
it("5. Console log on button click with mixed function IIFE", function () {
debuggerHelper.ClearLogs();
// Testing with normal log in iifee
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
@ -96,7 +94,7 @@ describe("Debugger logs", function () {
debuggerHelper.DoesConsoleLogExist(logStringChild);
});
it("8. Console log grouping on button click", function () {
it("6. Console log grouping on button click", function () {
debuggerHelper.ClearLogs();
// Testing with normal log in iifee
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
@ -116,7 +114,7 @@ describe("Debugger logs", function () {
debuggerHelper.AssertConsecutiveConsoleLogCount(5);
});
it("9. Console log grouping on button click with different log in between", function () {
it("7. Console log grouping on button click with different log in between", function () {
debuggerHelper.ClearLogs();
// Testing with normal log in iifee
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);
@ -135,7 +133,7 @@ describe("Debugger logs", function () {
debuggerHelper.AssertConsecutiveConsoleLogCount(2);
});
it("10. Console log grouping on button click from different source", function () {
it("8. Console log grouping on button click from different source", function () {
debuggerHelper.ClearLogs();
// Testing with normal log in iifee
EditorNavigation.SelectEntityByName("Button1", EntityType.Widget);

View File

@ -34,7 +34,7 @@ describe("Debugger logs", { tags: ["@tag.IDE"] }, function () {
_.agHelper.RefreshPage();
// Wait for the debugger icon to be visible
_.agHelper.AssertElementVisibility(".t--debugger-count");
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.agHelper.GetNClick(_.jsEditor._logsTab);
_.debuggerHelper.DoesConsoleLogExist(logString);
});
@ -286,7 +286,7 @@ describe("Debugger logs", { tags: ["@tag.IDE"] }, function () {
EditorNavigation.SelectEntityByName("Page1", EntityType.Page);
_.agHelper.AssertElementVisibility(".t--debugger-count");
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClicklogEntityLink();

View File

@ -23,7 +23,7 @@ describe("Widget error state", function () {
//Check if the current value is shown in the debugger
_.debuggerHelper.ClickDebuggerIcon();
_.debuggerHelper.OpenDebugger();
cy.get("[data-testid=t--tab-ERROR]").click();
//This feature is disabled in updated error log - epic 17720
// _.debuggerHelper.LogStateContains("Test");
@ -44,8 +44,8 @@ describe("Widget error state", function () {
);
// All errors should be expanded by default
//Updated count to 1 as the decision not to show triggerexecution/uncaughtpromise error in - epic 17720
_.debuggerHelper.AssertVisibleErrorMessagesCount(1);
//Updated count to 2 as the decision to show the widget trigger lint errors to show in the debugger
_.debuggerHelper.AssertVisibleErrorMessagesCount(2);
// Recent errors are shown at the top of the list
cy.testJsontext("label", "{{[]}}");
@ -63,7 +63,7 @@ describe("Widget error state", function () {
cy.deleteWidget();
_.debuggerHelper.AssertVisibleErrorMessagesCount(0);
cy.get("body").type(`{${modifierKey}}z`);
_.debuggerHelper.AssertVisibleErrorMessagesCount(2);
_.debuggerHelper.AssertVisibleErrorMessagesCount(3);
//Bug-2760: Error log on a widget property not clearing out when the widget property is deleted
_.entityExplorer.DragDropWidgetNVerify(WIDGET.TABLE, 150, 300);

View File

@ -43,13 +43,7 @@ describe(
.should("be.visible")
.contains("'lintError' is not defined.");
cy.get(commonlocators.debugger)
.should("be.visible")
.click({ force: true });
cy.get(commonlocators.errorTab)
.should("be.visible")
.click({ force: true });
_.debuggerHelper.OpenDebugger();
cy.get(commonlocators.debugErrorMsg).should("have.length", 3);
});

View File

@ -43,13 +43,7 @@ describe(
.should("be.visible")
.contains("'DATA' is not defined.");
cy.get(commonlocators.debugger)
.should("be.visible")
.click({ force: true });
cy.get(commonlocators.errorTab)
.should("be.visible")
.click({ force: true });
_.debuggerHelper.OpenDebugger();
cy.get(commonlocators.debugErrorMsg).should("have.length", 6);
});

View File

@ -91,10 +91,11 @@ describe(
1,
);
//Open debugger by clicking debugger icon in canvas.
debuggerHelper.ClickDebuggerIcon();
agHelper.GetNAssertContains(
debuggerHelper.locators._debuggerList,
debuggerHelper.AssertDebugError(
"This data identifier is evaluating to a duplicate value. Please use an identifier that evaluates to a unique value.",
"",
true,
false,
);
});
},

View File

@ -9,6 +9,7 @@ import {
import EditorNavigation, {
EntityType,
} from "../../../../../support/Pages/EditorNavigation";
import * as _ from "../../../../../support/Objects/ObjectsCore";
describe(
"Nested List widget V2 ",
@ -40,8 +41,11 @@ describe(
"List3",
]);
agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{v}`);
agHelper.ValidateToastMessage(
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClickLogsTab();
_.debuggerHelper.DoesConsoleLogExist(
"Cannot have more than 3 levels of nesting in the list widget",
true,
);
});

View File

@ -6,9 +6,11 @@ const commonlocators = require("../../../../../locators/commonlocators.json");
import {
agHelper,
assertHelper,
debuggerHelper,
entityExplorer,
propPane,
} from "../../../../../support/Objects/ObjectsCore";
import * as _ from "../../../../../support/Objects/ObjectsCore";
const widgetsPage = require("../../../../../locators/Widgets.json");
const widgetSelector = (name) => `[data-widgetname-cy="${name}"]`;
@ -72,7 +74,12 @@ describe(
.type(`{${modifierKey}}{v}`);
cy.wait(500);
cy.validateToastMessage("Cannot have more than 3 levels of nesting");
_.debuggerHelper.OpenDebugger();
_.debuggerHelper.ClickLogsTab();
_.debuggerHelper.DoesConsoleLogExist(
"Cannot have more than 3 levels of nesting",
true,
);
cy.get(`${widgetSelector("List2Copy1")}`).should("not.exist");
});

View File

@ -44,15 +44,7 @@ describe(
.should("be.visible")
.contains("'lintErrror' is not defined.");
cy.get(commonlocators.debugger)
.should("be.visible")
.click({ force: true });
cy.get(commonlocators.errorTab)
.should("be.visible")
.click({ force: true });
cy.get(commonlocators.debugErrorMsg).should("have.length", 3);
_.debuggerHelper.AssertErrorCount(3);
});
},
);

View File

@ -124,7 +124,17 @@ describe(
Cypress.env("TESTPASSWORD2"),
);
agHelper.VisitNAssert(currentUrl);
agHelper.ValidateToastMessage("Resource Not Found"); //for 404 screen
cy.get(locators.errorPageTitle).should(($x) => {
//for 404 screen
expect($x).contain(Cypress.env("MESSAGES").PAGE_NOT_FOUND());
});
cy.get(locators.errorPageDescription).should(($x) => {
//for 404 screen
expect($x).contain(
"Either this page doesn't exist, or you don't have access to this page",
);
});
agHelper.ValidateToastMessage("Resource Not Found");
homePage.LogOutviaAPI();
// visit the app as anonymous user and validate redirection to login page
agHelper.VisitNAssert(currentUrl);

View File

@ -126,7 +126,7 @@ describe("JS Function Execution", { tags: ["@tag.JS"] }, function () {
//It should open only in case of execution error.
debuggerHelper.AssertClosed();
//Verify there is no error shown in the response tab.
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.OpenDebugger();
debuggerHelper.ClickResponseTab();
jsEditor.AssertParseError(false);
agHelper.ActionContextMenuWithInPane({
@ -400,7 +400,6 @@ describe("JS Function Execution", { tags: ["@tag.JS"] }, function () {
jsEditor.EnableDisableAsyncFuncSettings(
functionSetting.name,
functionSetting.onPageLoad,
functionSetting.confirmBeforeExecute,
);
},
);
@ -496,12 +495,12 @@ return "yes";`;
// Switch to settings tab
agHelper.GetNClick(jsEditor._settingsTab);
// Enable all settings
jsEditor.EnableDisableAsyncFuncSettings("asyncToSync", true, false);
jsEditor.EnableDisableAsyncFuncSettings("asyncToSync", true);
// Modify js object
jsEditor.EditJSObj(syncJSCode, false);
agHelper.RefreshPage();
jsEditor.VerifyAsyncFuncSettings("asyncToSync", true, false);
jsEditor.VerifyAsyncFuncSettings("asyncToSync", true);
agHelper.ActionContextMenuWithInPane({
action: "Delete",
entityType: entityItems.JSObject,

View File

@ -2,6 +2,7 @@ import {
agHelper,
apiPage,
assertHelper,
debuggerHelper,
entityExplorer,
entityItems,
propPane,
@ -58,7 +59,12 @@ describe(
`{{PageLoadApi2.data.data}}`,
);
agHelper.RefreshPage();
agHelper.ValidateToastMessage(`The action "PageLoadApi2" has failed.`);
debuggerHelper.AssertDebugError(
'The action "PageLoadApi2" has failed.',
"",
true,
false,
);
});
after(() => {

View File

@ -91,7 +91,7 @@ describe(
EditorNavigation.SelectEntityByName("Page1", EntityType.Page);
agHelper.RefreshPage();
debuggerHelper.ClickDebuggerIcon();
debuggerHelper.OpenDebugger();
debuggerHelper.ClickLogsTab();
debuggerHelper.DebuggerLogsFilter("JSObject1.astros");
debuggerHelper.DoesConsoleLogExist("JS Function executed successfully");

View File

@ -4,7 +4,11 @@ import {
} from "../../../support/Pages/EditorNavigation";
const datasourceEditor = require("../../../locators/DatasourcesEditor.json");
import { agHelper, dataSources } from "../../../support/Objects/ObjectsCore";
import {
agHelper,
dataSources,
debuggerHelper,
} from "../../../support/Objects/ObjectsCore";
const commonlocators = require("../../../locators/commonlocators.json");
describe(
@ -60,9 +64,15 @@ describe(
force: true,
});
cy.wait(2000);
cy.get(commonlocators.toastmsg).contains(
"NoiseTestQuery failed to execute",
debuggerHelper.OpenDebugger();
debuggerHelper.ClickLogsTab();
debuggerHelper.DoesConsoleLogExist(
"Execution failed with status PE-STC-5000",
true,
"NoiseTestQuery",
);
cy.wait("@postExecute").then(({ response }) => {
expect(response.body.data.statusCode).to.eq("200 OK");
});

View File

@ -334,6 +334,8 @@ export class CommonLocators {
_menuItem = ".bp3-menu-item";
_slashCommandHintText = ".slash-command-hint-text";
_selectionItem = ".rc-select-selection-item";
errorPageTitle = ".t--error-page-title";
errorPageDescription = ".t--error-page-description";
_selectClearButton_testId = "selectbutton.btn.cancel";
_selectClearButton_dataTestId = `[data-testid="${this._selectClearButton_testId}"]`;
}

View File

@ -34,6 +34,7 @@ export class DebuggerHelper {
[PageType.JsEditor]: ".t--js-editor-bottom-pane-container",
[PageType.DataSources]: ".t--datasource-bottom-pane-container",
},
_ideBottomViewContainer: ".t--ide-bottom-view",
_debuggerList: ".debugger-list",
_debuggerFilter: "input[data-testid=t--debugger-search]",
_debuggerSelectedTab: ".ads-v2-tabs__list-tab",
@ -49,17 +50,16 @@ export class DebuggerHelper {
_downStreamLogMessage: ".t--debugger-log-downstream-message",
};
ClickDebuggerIcon(
index?: number,
force?: boolean,
waitTimeInterval?: number,
) {
this.agHelper.GetNClick(
this.locators._debuggerIcon,
index,
force,
waitTimeInterval,
);
OpenDebugger() {
// Open opens if it is not open yet
cy.get("body").then(($body) => {
if ($body.find(this.locators._ideBottomViewContainer).length === 0) {
this.agHelper.GetNClick(this.locators._debuggerIcon, 0, false);
} else {
this.agHelper.GetNClick(this.commonLocators._errorTab, 0, true, 0);
}
});
this.AssertOpen();
}
ClickDebuggerToggle(expand = true, index = 0) {
@ -93,7 +93,7 @@ export class DebuggerHelper {
this.agHelper.GetNClick(this.locators._closeButton);
}
AssertOpen(pageType: PageType) {
AssertOpen(pageType?: PageType) {
switch (pageType) {
case PageType.Canvas:
this.agHelper.AssertElementExist(this.locators._tabsContainer);
@ -106,6 +106,10 @@ export class DebuggerHelper {
this.locators._bottomPaneContainer[pageType],
);
break;
default:
this.agHelper.AssertElementVisibility(
this.locators._ideBottomViewContainer,
);
}
}
@ -118,12 +122,19 @@ export class DebuggerHelper {
this.agHelper.AssertSelectedTab(this.locators._debuggerSelectedTab, "true");
}
DoesConsoleLogExist(text: string, exists = true) {
DoesConsoleLogExist(text: string, exists = true, entityName?: string) {
this.agHelper.GetNAssertContains(
this.locators._logMessage,
text,
exists ? "exist" : "not.exist",
);
if (entityName) {
this.agHelper
.GetElement(this.locators._logMessage)
.contains(text)
.closest(".error")
.contains(this.locators._logEntityLink, entityName);
}
}
DebuggerLogsFilter(text: string) {
@ -187,9 +198,10 @@ export class DebuggerHelper {
message: string,
shouldOpenDebugger = true,
shouldToggleDebugger = true,
errorLabelIndex = 0,
) {
if (shouldOpenDebugger) {
this.ClickDebuggerIcon();
this.OpenDebugger();
}
this.agHelper.GetNClick(this.commonLocators._errorTab, 0, true, 0);
@ -198,7 +210,7 @@ export class DebuggerHelper {
}
this.agHelper
.GetText(this.locators._debuggerLabel, "text", 0)
.GetText(this.locators._debuggerLabel, "text", errorLabelIndex)
.then(($text) => {
expect($text).to.eq(label);
});
@ -222,7 +234,7 @@ export class DebuggerHelper {
AssertDownStreamLogError(message: string, shouldOpenDebugger = true) {
if (shouldOpenDebugger) {
this.ClickDebuggerIcon();
this.OpenDebugger();
}
this.agHelper.GetNClick(this.commonLocators._responseTab, 0, true, 0);

View File

@ -6,6 +6,7 @@ import Resizer, {
import { CodeEditorWithGutterStyles } from "pages/Editor/JSEditor/styledComponents";
import { ViewDisplayMode, ViewHideBehaviour } from "IDE/Interfaces/View";
import { Button } from "@appsmith/ads";
import classNames from "classnames";
const VIEW_MIN_HEIGHT = 38;
@ -112,6 +113,7 @@ const ViewHide = (props: ViewHideProps) => {
const BottomView = (props: Props) => {
const panelRef = useRef<HTMLDivElement>(null);
const { className = "" } = props;
// Handle the height of the view when toggling the hidden state
useEffect(() => {
@ -126,7 +128,10 @@ const BottomView = (props: Props) => {
return (
<Container
className={`select-text ${props.className || ""}`}
className={classNames("select-text", {
[className]: true,
"t--ide-bottom-view": !props.hidden,
})}
displayMode={props.displayMode || ViewDisplayMode.BLOCK}
ref={panelRef}
>

View File

@ -8,6 +8,7 @@ import type { JSCollection } from "entities/JSCollection";
import type { CreateJSCollectionRequest } from "ee/api/JSActionAPI";
import type { EventLocation } from "ee/utils/analyticsUtilTypes";
import type { ApiResponse } from "api/ApiResponses";
import type { ErrorActionPayload } from "../sagas/ErrorSagas";
export interface FetchJSCollectionsPayload {
applicationId: string;
@ -62,10 +63,12 @@ export const copyJSCollectionSuccess = (payload: JSCollection) => {
};
};
export const copyJSCollectionError = (payload: {
id: string;
destinationPageId: string;
}) => {
export const copyJSCollectionError = (
payload: {
id: string;
destinationPageId: string;
} & ErrorActionPayload,
) => {
return {
type: ReduxActionErrorTypes.COPY_JS_ACTION_ERROR,
payload,
@ -90,10 +93,12 @@ export const moveJSCollectionSuccess = (payload: JSCollection) => {
};
};
export const moveJSCollectionError = (payload: {
id: string;
originalPageId: string;
}) => {
export const moveJSCollectionError = (
payload: {
id: string;
originalPageId: string;
} & ErrorActionPayload,
) => {
return {
type: ReduxActionErrorTypes.MOVE_JS_ACTION_ERROR,
payload,

View File

@ -15,6 +15,7 @@ import type { ModalInfo } from "reducers/uiReducers/modalActionReducer";
import type { OtlpSpan } from "UITelemetry/generateTraces";
import type { ApiResponse } from "api/ApiResponses";
import type { JSCollection } from "entities/JSCollection";
import type { ErrorActionPayload } from "sagas/ErrorSagas";
export const createActionRequest = (payload: Partial<Action>) => {
return {
@ -205,10 +206,12 @@ export const moveActionSuccess = (payload: Action) => {
};
};
export const moveActionError = (payload: {
id: string;
originalPageId: string;
}) => {
export const moveActionError = (
payload: {
id: string;
originalPageId: string;
} & ErrorActionPayload,
) => {
return {
type: ReduxActionErrorTypes.MOVE_ACTION_ERROR,
payload,
@ -233,10 +236,12 @@ export const copyActionSuccess = (payload: Action) => {
};
};
export const copyActionError = (payload: {
id: string;
destinationPageId: string;
}) => {
export const copyActionError = (
payload: {
id: string;
destinationPageId: string;
} & ErrorActionPayload,
) => {
return {
type: ReduxActionErrorTypes.COPY_ACTION_ERROR,
payload,

View File

@ -368,7 +368,6 @@ const UserAuthActionTypes = {
SAAS_GET_OAUTH_ACCESS_TOKEN: "SAAS_GET_OAUTH_ACCESS_TOKEN",
GET_OAUTH_ACCESS_TOKEN: "GET_OAUTH_ACCESS_TOKEN",
GET_OAUTH_ACCESS_TOKEN_SUCCESS: "GET_OAUTH_ACCESS_TOKEN_SUCCESS",
GET_OAUTH_ACCESS_TOKEN_ERROR: "GET_OAUTH_ACCESS_TOKEN_ERROR",
};
const UserAuthActionErrorTypes = {
CREATE_USER_ERROR: "CREATE_USER_ERROR",
@ -379,6 +378,7 @@ const UserAuthActionErrorTypes = {
LOGOUT_USER_ERROR: "LOGOUT_USER_ERROR",
VERIFY_INVITE_ERROR: "VERIFY_INVITE_ERROR",
INVITED_USER_SIGNUP_ERROR: "INVITED_USER_SIGNUP_ERROR",
GET_OAUTH_ACCESS_TOKEN_ERROR: "GET_OAUTH_ACCESS_TOKEN_ERROR",
};
const UserProfileActionTypes = {
@ -1334,6 +1334,20 @@ export const ReduxActionErrorTypes = {
...WorkspaceActionErrorTypes,
};
export const toastMessageErrorTypes = {
...AdminSettingsActionErrorTypes,
...ApplicationActionErrorTypes,
...AppViewActionErrorTypes,
...DatasourceEditorActionErrorTypes,
...GitActionErrorTypes,
...ImportExportActionErrorTypes,
...PlatformActionErrorTypes,
...TenantActionErrorTypes,
...UserAuthActionErrorTypes,
...UserProfileActionErrorTypes,
...WorkspaceActionErrorTypes,
};
export type ReduxActionErrorType =
(typeof ReduxActionErrorTypes)[keyof typeof ReduxActionErrorTypes];

View File

@ -1,4 +1,4 @@
import type { JSActionEntity } from "ee/entities/DataTree/types";
import type { JSActionEntity, WidgetEntity } from "ee/entities/DataTree/types";
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
import type { DataTreeEntity } from "entities/DataTree/dataTreeTypes";
@ -9,6 +9,9 @@ const entityUniqueIdGetterMap: Record<
[ENTITY_TYPE.JSACTION]: (entity) => {
return (entity as JSActionEntity).actionId;
},
[ENTITY_TYPE.WIDGET]: (entity) => {
return (entity as WidgetEntity).widgetId;
},
};
export default function getEntityUniqueIdForLogs(entity: DataTreeEntity) {

View File

@ -1,8 +1,16 @@
import { isJSAction } from "ee/workers/Evaluation/evaluationUtils";
import { isJSAction, isWidget } from "ee/workers/Evaluation/evaluationUtils";
import type { DataTreeEntity } from "entities/DataTree/dataTreeTypes";
import type { DataTreeEntityConfig } from "ee/entities/DataTree/types";
export default function isLintErrorLoggingEnabledForEntity(
entity: DataTreeEntity,
propertyPath: string,
config: DataTreeEntityConfig,
) {
return isJSAction(entity);
if (isJSAction(entity)) {
return true;
}
if (isWidget(entity)) {
return !(propertyPath in config.reactivePaths);
}
}

View File

@ -192,10 +192,15 @@ export function* copyJSCollectionSaga(
}
} catch (e) {
const actionName = actionObject ? actionObject.name : "";
toast.show(createMessage(ERROR_JS_ACTION_COPY_FAIL, actionName), {
kind: "error",
});
yield put(copyJSCollectionError(action.payload));
yield put(
copyJSCollectionError({
...action.payload,
show: true,
error: {
message: createMessage(ERROR_JS_ACTION_COPY_FAIL, actionName),
},
}),
);
}
}
@ -265,13 +270,14 @@ export function* moveJSCollectionSaga(
// @ts-expect-error: response.data is of type unknown
yield put(moveJSCollectionSuccess(response.data));
} catch (e) {
toast.show(createMessage(ERROR_JS_ACTION_MOVE_FAIL, actionObject.name), {
kind: "error",
});
yield put(
moveJSCollectionError({
id: action.payload.id,
originalPageId: actionObject.pageId,
show: true,
error: {
message: createMessage(ERROR_JS_ACTION_MOVE_FAIL, actionObject.name),
},
}),
);
}
@ -375,15 +381,15 @@ export function* saveJSObjectName(
payload: {
actionId: action.payload.id,
oldName: collection.config.name,
show: true,
error: {
message: createMessage(
ERROR_JS_COLLECTION_RENAME_FAIL,
action.payload.name,
),
},
},
});
toast.show(
createMessage(ERROR_JS_COLLECTION_RENAME_FAIL, action.payload.name),
{
kind: "error",
},
);
log.error(e);
}
}

View File

@ -267,9 +267,7 @@ function LogItem(props: LogItemProps) {
size="md"
/>
<span className={`debugger-time ${props.severity}`}>
{props.severity === Severity.ERROR
? moment(parseInt(props.timestamp)).format("HH:mm:ss")
: props.timestamp}
{moment(parseInt(props.timestamp)).format("HH:mm:ss")}
</span>
<Button

View File

@ -158,6 +158,7 @@ export function* pasteWidgetSagas() {
payload: {
action: ReduxActionTypes.PASTE_COPIED_WIDGET_INIT,
error,
logToDebugger: true,
},
});
}

View File

@ -370,7 +370,7 @@ const datasourceReducer = createReducer(initialState, {
loadingTokenForDatasourceId: null,
};
},
[ReduxActionTypes.GET_OAUTH_ACCESS_TOKEN_ERROR]: (
[ReduxActionErrorTypes.GET_OAUTH_ACCESS_TOKEN_ERROR]: (
state: DatasourceDataState,
) => {
return {

View File

@ -9,9 +9,9 @@ import {
} from "redux-saga/effects";
import * as Sentry from "@sentry/react";
import type { updateActionDataPayloadType } from "actions/pluginActionActions";
import { executePageLoadActions } from "actions/pluginActionActions";
import {
clearActionResponse,
executePageLoadActions,
executePluginActionError,
executePluginActionRequest,
executePluginActionSuccess,
@ -72,8 +72,7 @@ import {
} from "sagas/ErrorSagas";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import type { Action } from "entities/Action";
import { ActionExecutionContext } from "entities/Action";
import { PluginType } from "entities/Action";
import { ActionExecutionContext, PluginType } from "entities/Action";
import LOG_TYPE from "entities/AppsmithConsole/logtype";
import {
ACTION_EXECUTION_CANCELLED,
@ -1267,9 +1266,8 @@ function* executePageLoadActionsSaga(
checkAndLogErrorsIfCyclicDependency(layoutOnLoadActionErrors);
} catch (e) {
log.error(e);
toast.show(createMessage(ERROR_FAIL_ON_PAGE_LOAD_ACTIONS), {
kind: "error",
AppsmithConsole.error({
text: createMessage(ERROR_FAIL_ON_PAGE_LOAD_ACTIONS),
});
}
endSpan(span);

View File

@ -1,6 +1,6 @@
import { call, spawn } from "redux-saga/effects";
import {
logActionExecutionError,
showToastOnExecutionError,
TriggerFailureError,
} from "sagas/ActionExecution/errorUtils";
import { isEmpty } from "lodash";
@ -35,6 +35,6 @@ export function* executePostMessage(
}
}
} catch (error) {
yield call(logActionExecutionError, (error as Error).message, true);
yield call(showToastOnExecutionError, (error as Error).message);
}
}

View File

@ -5,15 +5,14 @@ import {
import type { ApiResponse } from "api/ApiResponses";
import { isString } from "lodash";
import type { Types } from "utils/TypeHelpers";
import type { ActionTriggerKeys } from "ee/workers/Evaluation/fns/index";
import { getActionTriggerFunctionNames } from "ee/workers/Evaluation/fns/index";
import { getAppMode } from "ee/selectors/applicationSelectors";
import type { ActionTriggerKeys } from "ee/workers/Evaluation/fns";
import { getActionTriggerFunctionNames } from "ee/workers/Evaluation/fns";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { setDebuggerSelectedTab, showDebugger } from "actions/debuggerActions";
import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers";
import store from "store";
import showToast from "sagas/ToastSagas";
import { call } from "redux-saga/effects";
import { call, put } from "redux-saga/effects";
/*
* The base trigger error that also logs the errors in the debugger.
@ -55,39 +54,11 @@ export class ActionValidationError extends TriggerFailureError {
}
}
export function* logActionExecutionError(
export function* showToastOnExecutionError(
errorMessage: string,
isExecuteJSFunc = true,
showCTA = true,
) {
//Commenting as per decision taken for the error hanlding epic to not show the trigger errors in the debugger.
// if (triggerPropertyName) {
// AppsmithConsole.addErrors([
// {
// payload: {
// id: `${source?.id}-${triggerPropertyName}`,
// logType: LOG_TYPE.TRIGGER_EVAL_ERROR,
// text: createMessage(DEBUGGER_TRIGGER_ERROR, triggerPropertyName),
// source: {
// type: ENTITY_TYPE.WIDGET,
// id: source?.id ?? "",
// name: source?.name ?? "",
// propertyPath: triggerPropertyName,
// },
// messages: [
// {
// type: errorType,
// message: { name: "TriggerExecutionError", message: errorMessage },
// },
// ],
// },
// },
// ]);
// }
function onDebugClick() {
const appMode = getAppMode(store.getState());
if (appMode === "PUBLISHED") return null;
AnalyticsUtil.logEvent("OPEN_DEBUGGER", {
source: "TOAST",
});
@ -95,16 +66,24 @@ export function* logActionExecutionError(
store.dispatch(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.ERROR_TAB));
}
if (isExecuteJSFunc)
// This is the toast that is rendered when any unhandled error occurs in JS object.
yield call(showToast, errorMessage, {
kind: "error",
action: {
const action = showCTA
? {
text: "debug",
effect: () => onDebugClick(),
className: "t--toast-debug-button",
},
});
}
: undefined;
// This is the toast that is rendered when any unhandled error occurs in JS object.
yield call(showToast, errorMessage, {
kind: "error",
action,
});
}
export function* showDebuggerOnExecutionError() {
yield put(showDebugger(true));
yield put(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.ERROR_TAB));
}
/*

View File

@ -5,14 +5,14 @@ import {
getUserLocation,
} from "./geolocationSaga";
import { setUserCurrentGeoLocation } from "actions/browserRequestActions";
import { logActionExecutionError } from "./errorUtils";
import { showToastOnExecutionError } from "./errorUtils";
const mockFn = jest.fn();
jest.mock("./errorUtils.ts", () => ({
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
logActionExecutionError: (payload: any) => mockFn(payload),
showToastOnExecutionError: (payload: any) => mockFn(payload),
}));
describe("getCurrentLocationSaga", () => {
@ -86,7 +86,7 @@ describe("getCurrentLocationSaga", () => {
expect(iter.next().value).toHaveProperty(
"payload.fn",
logActionExecutionError,
showToastOnExecutionError,
);
expect(iter.next().done).toBe(true);
});

View File

@ -1,7 +1,7 @@
import type { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { TriggerMeta } from "ee/sagas/ActionExecution/ActionExecutionSagas";
import { call, put, spawn, take } from "redux-saga/effects";
import { logActionExecutionError } from "sagas/ActionExecution/errorUtils";
import { showToastOnExecutionError } from "sagas/ActionExecution/errorUtils";
import { setUserCurrentGeoLocation } from "actions/browserRequestActions";
import type { Channel } from "redux-saga";
import { channel } from "redux-saga";
@ -107,7 +107,7 @@ function* errorCallbackHandler(triggerMeta: TriggerMeta, listenerId?: string) {
{ error: sanitizeGeolocationError(error) },
listenerId,
);
yield call(logActionExecutionError, error.message, true);
yield call(showToastOnExecutionError, error.message);
}
}
@ -122,7 +122,7 @@ export function* getCurrentLocationSaga(action: TGetGeoLocationDescription) {
yield put(setUserCurrentGeoLocation(currentLocation));
return currentLocation;
} catch (error) {
yield call(logActionExecutionError, (error as Error).message, true);
yield call(showToastOnExecutionError, (error as Error).message);
if (error instanceof GeolocationPositionError) {
const sanitizedError = sanitizeGeolocationError(error);
throw new GeoLocationError(sanitizedError.message, [sanitizedError]);
@ -141,9 +141,8 @@ export function* watchCurrentLocation(
// When a watch is already active, we will not start a new watch.
// at a given point in time, only one watch is active
yield call(
logActionExecutionError,
showToastOnExecutionError,
"A watchLocation is already active. Clear it before before starting a new one",
true,
);
return;
@ -171,7 +170,7 @@ export function* watchCurrentLocation(
export function* stopWatchCurrentLocation() {
if (watchId === undefined) {
yield call(logActionExecutionError, "No location watch active", true);
yield call(showToastOnExecutionError, "No location watch active");
return;
}
navigator.geolocation.clearWatch(watchId);

View File

@ -106,7 +106,6 @@ import {
createNewQueryAction,
} from "actions/apiPaneActions";
import type { Plugin } from "api/PluginApi";
import * as log from "loglevel";
import { shouldBeDefined } from "utils/helpers";
import {
apiEditorIdURL,
@ -704,13 +703,14 @@ function* moveActionSaga(
// @ts-expect-error: response is of type unknown
yield put(moveActionSuccess(response.data));
} catch (e) {
toast.show(createMessage(ERROR_ACTION_MOVE_FAIL, actionObject.name), {
kind: "error",
});
yield put(
moveActionError({
id: action.payload.id,
originalPageId: action.payload.originalPageId,
show: true,
error: {
message: createMessage(ERROR_ACTION_MOVE_FAIL, actionObject.name),
},
}),
);
}
@ -797,10 +797,13 @@ function* copyActionSaga(
yield put(copyActionSuccess(payload));
} catch (e) {
const actionName = actionObject ? actionObject.name : "";
toast.show(createMessage(ERROR_ACTION_COPY_FAIL, actionName), {
kind: "error",
});
yield put(copyActionError(action.payload));
yield put(
copyActionError({
...action.payload,
show: true,
error: { message: createMessage(ERROR_ACTION_COPY_FAIL, actionName) },
}),
);
}
}
@ -899,12 +902,9 @@ function* saveActionName(action: ReduxAction<{ id: string; name: string }>) {
payload: {
actionId: action.payload.id,
oldName: api.config.name,
message: createMessage(ERROR_ACTION_RENAME_FAIL, action.payload.name),
},
});
toast.show(createMessage(ERROR_ACTION_RENAME_FAIL, action.payload.name), {
kind: "error",
});
log.error(e);
}
}

View File

@ -4,7 +4,6 @@
import get from "lodash/get";
import omit from "lodash/omit";
import { all, call, put, select, take, takeEvery } from "redux-saga/effects";
import * as Sentry from "@sentry/react";
import type {
ReduxAction,
ReduxActionWithMeta,
@ -68,7 +67,6 @@ import { getCurrentBasePageId } from "selectors/editorSelectors";
import { validateResponse } from "./ErrorSagas";
import type { CreateDatasourceSuccessAction } from "actions/datasourceActions";
import { removeTempDatasource } from "actions/datasourceActions";
import { toast } from "@appsmith/ads";
import type { AutoGeneratedHeader } from "pages/Editor/APIEditor/helpers";
import { deriveAutoGeneratedHeaderState } from "pages/Editor/APIEditor/helpers";
import { TEMP_DATASOURCE_ID } from "constants/Datasource";
@ -744,6 +742,7 @@ function* handleApiNameChangeSaga(
) {
yield put(change(API_EDITOR_FORM_NAME, "name", action.payload.name));
}
function* handleApiNameChangeSuccessSaga(
action: ReduxAction<{ actionId: string }>,
) {
@ -751,19 +750,15 @@ function* handleApiNameChangeSuccessSaga(
const actionObj: Action | undefined = yield select(getAction, actionId);
yield take(ReduxActionTypes.FETCH_ACTIONS_FOR_PAGE_SUCCESS);
if (!actionObj) {
// Error case, log to sentry
toast.show(createMessage(ERROR_ACTION_RENAME_FAIL, ""), {
kind: "error",
});
Sentry.captureException(
new Error(createMessage(ERROR_ACTION_RENAME_FAIL, "")),
{
extra: {
actionId: actionId,
},
yield put({
type: ReduxActionErrorTypes.SAVE_ACTION_NAME_ERROR,
payload: {
actionId,
show: true,
error: { message: createMessage(ERROR_ACTION_RENAME_FAIL, "") },
logToSentry: true,
},
);
});
return;
}
if (actionObj.pluginType === PluginType.API) {

View File

@ -199,6 +199,7 @@ export function* addWidgetAndMoveWidgetsSaga(
payload: {
action: ReduxActionTypes.WIDGETS_ADD_CHILD_AND_MOVE,
error,
logToDebugger: true,
},
});
}
@ -424,6 +425,7 @@ function* moveWidgetsSaga(
payload: {
action: ReduxActionTypes.WIDGETS_MOVE,
error,
logToDebugger: true,
},
});
}

View File

@ -471,12 +471,9 @@ export function* deleteDatasourceSaga(
yield select(getDatasource, actionPayload.payload.id),
`Datasource not found for id - ${actionPayload.payload.id}`,
);
toast.show((error as Error).message, {
kind: "error",
});
yield put({
type: ReduxActionErrorTypes.DELETE_DATASOURCE_ERROR,
payload: { error, id: actionPayload.payload.id, show: false },
payload: { error, id: actionPayload.payload.id, show: true },
});
AppsmithConsole.error({
text: (error as Error).message,
@ -736,12 +733,15 @@ function* getOAuthAccessTokenSaga(
if (!appsmithToken) {
// Error out because auth token should been here
log.error(OAUTH_APPSMITH_TOKEN_NOT_FOUND);
toast.show(OAUTH_AUTHORIZATION_APPSMITH_ERROR, {
kind: "error",
});
yield put({
type: ReduxActionTypes.GET_OAUTH_ACCESS_TOKEN_ERROR,
payload: { datasourceId: datasourceId },
type: ReduxActionErrorTypes.GET_OAUTH_ACCESS_TOKEN_ERROR,
show: true,
payload: {
datasourceId: datasourceId,
error: {
message: OAUTH_AUTHORIZATION_APPSMITH_ERROR,
},
},
});
return;
}
@ -800,11 +800,14 @@ function* getOAuthAccessTokenSaga(
}
} catch (e) {
yield put({
type: ReduxActionTypes.GET_OAUTH_ACCESS_TOKEN_ERROR,
payload: { datasourceId: datasourceId },
});
toast.show(OAUTH_AUTHORIZATION_FAILED, {
kind: "error",
type: ReduxActionErrorTypes.GET_OAUTH_ACCESS_TOKEN_ERROR,
payload: {
datasourceId: datasourceId,
show: true,
error: {
message: OAUTH_AUTHORIZATION_FAILED,
},
},
});
log.error(e);
}
@ -913,25 +916,20 @@ function* testDatasourceSaga(actionPayload: ReduxAction<Datasource>) {
}
if (responseData.invalids && responseData.invalids.length) {
AnalyticsUtil.logEvent("TEST_DATA_SOURCE_FAILED", {
datasoureId: datasource?.id,
datasourceId: datasource?.id,
environmentId: currentEnvironment,
environmentName: currentEnvDetails.name,
pluginName: plugin?.name,
errorMessages: responseData.invalids,
messages: responseData.messages,
});
responseData.invalids.forEach((message: string) => {
toast.show(message, {
kind: "error",
});
});
yield put({
type: ReduxActionErrorTypes.TEST_DATASOURCE_ERROR,
payload: {
show: false,
id: datasource.id,
environmentId: currentEnvironment,
messages: messages,
show: true,
error: { message: responseData.invalids.join(", ") },
},
});
AppsmithConsole.error({
@ -2107,10 +2105,12 @@ function* updateDatasourceAuthStateSaga(
} catch (error) {
yield put({
type: ReduxActionErrorTypes.UPDATE_DATASOURCE_ERROR,
payload: { error },
});
toast.show(OAUTH_AUTHORIZATION_FAILED, {
kind: "error",
payload: {
error: {
message: OAUTH_AUTHORIZATION_FAILED,
},
show: true,
},
});
}
}

View File

@ -1,6 +1,6 @@
import type {
DeleteErrorLogPayload,
LogDebuggerErrorAnalyticsPayload,
import {
type DeleteErrorLogPayload,
type LogDebuggerErrorAnalyticsPayload,
} from "actions/debuggerActions";
import {
addErrorLogs,

View File

@ -1,5 +1,8 @@
import { get } from "lodash";
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import {
type ReduxAction,
toastMessageErrorTypes,
} from "ee/constants/ReduxActionConstants";
import {
ReduxActionTypes,
ReduxActionErrorTypes,
@ -30,6 +33,14 @@ import { axiosConnectionAbortedCode } from "ee/api/ApiUtils";
import { getLoginUrl } from "ee/utils/adminSettingsHelpers";
import type { PluginErrorDetails } from "api/ActionAPI";
import showToast from "sagas/ToastSagas";
import AppsmithConsole from "../utils/AppsmithConsole";
import type { SourceEntity } from "../entities/AppsmithConsole";
import { getAppMode } from "ee/selectors/applicationSelectors";
import { APP_MODE } from "../entities/App";
const shouldShowToast = (action: string) => {
return action in toastMessageErrorTypes;
};
/**
* making with error message with action name
@ -190,8 +201,9 @@ const getErrorMessageFromActionType = (
enum ErrorEffectTypes {
SHOW_ALERT = "SHOW_ALERT",
SAFE_CRASH = "SAFE_CRASH",
LOG_ERROR = "LOG_ERROR",
LOG_TO_CONSOLE = "LOG_TO_CONSOLE",
LOG_TO_SENTRY = "LOG_TO_SENTRY",
LOG_TO_DEBUGGER = "LOG_TO_DEBUGGER",
}
export interface ErrorActionPayload {
@ -199,16 +211,33 @@ export interface ErrorActionPayload {
show?: boolean;
crash?: boolean;
logToSentry?: boolean;
logToDebugger?: boolean;
sourceEntity?: SourceEntity;
}
export function* errorSaga(errorAction: ReduxAction<ErrorActionPayload>) {
const effects = [ErrorEffectTypes.LOG_ERROR];
const effects = [ErrorEffectTypes.LOG_TO_CONSOLE];
const { payload, type } = errorAction;
const { error, logToSentry, show = true } = payload || {};
const message = getErrorMessageFromActionType(type, error);
const {
error,
logToDebugger,
logToSentry,
show = true,
sourceEntity,
} = payload || {};
const appMode: APP_MODE = yield select(getAppMode);
// "show" means show a toast. We check if the error has been asked to not been shown
// By making the default behaviour "true" we are ensuring undefined actions still pass through this check
if (show) {
effects.push(ErrorEffectTypes.SHOW_ALERT);
// We want to show toasts for certain actions only so we avoid issues or if it is outside edit mode
if (shouldShowToast(type) || appMode !== APP_MODE.EDIT) {
effects.push(ErrorEffectTypes.SHOW_ALERT);
}
}
if (logToDebugger) {
effects.push(ErrorEffectTypes.LOG_TO_DEBUGGER);
}
if (error && error.crash) {
@ -220,19 +249,26 @@ export function* errorSaga(errorAction: ReduxAction<ErrorActionPayload>) {
effects.push(ErrorEffectTypes.LOG_TO_SENTRY);
}
const message = getErrorMessageFromActionType(type, error);
for (const effect of effects) {
switch (effect) {
case ErrorEffectTypes.LOG_ERROR: {
case ErrorEffectTypes.LOG_TO_CONSOLE: {
logErrorSaga(errorAction);
break;
}
case ErrorEffectTypes.LOG_TO_DEBUGGER: {
AppsmithConsole.error({
text: message,
source: sourceEntity,
});
break;
}
case ErrorEffectTypes.SHOW_ALERT: {
// This is the toast that is rendered when any page load API fails.
yield call(showToast, message, { kind: "error" });
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((window as any).Cypress) {
if ("Cypress" in window) {
if (message === "" || message === null) {
yield put(
safeCrashApp({

View File

@ -48,7 +48,7 @@ import {
} from "actions/evaluationActions";
import ConfigTreeActions from "utils/configTree";
import {
dynamicTriggerErrorHandler,
showExecutionErrors,
handleJSFunctionExecutionErrorLog,
logJSVarCreatedEvent,
logSuccessfulBindings,
@ -341,16 +341,15 @@ export function* evaluateAndExecuteDynamicTrigger(
triggerMeta,
},
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { errors = [] } = response as any;
const { errors = [] } = response;
const transformedErrors: EvaluationError[] = yield call(
transformTriggerEvalErrors,
errors,
);
yield call(dynamicTriggerErrorHandler, transformedErrors);
if (transformedErrors.length) {
yield fork(showExecutionErrors, transformedErrors);
}
yield fork(logDynamicTriggerExecution, {
dynamicTrigger,
errors: transformedErrors,

View File

@ -55,14 +55,15 @@ function* handleInstallationFailure(
text: `Failed to install library script at ${url}`,
});
toast.show(message || `Failed to install library script at ${url}`, {
kind: "error",
});
const applicationid: ReturnType<typeof getCurrentApplicationId> =
yield select(getCurrentApplicationId);
yield put({
type: ReduxActionErrorTypes.INSTALL_LIBRARY_FAILED,
payload: { url, show: false },
payload: {
url,
show: true,
message: message || `Failed to install library script at ${url}`,
},
});
AnalyticsUtil.logEvent("INSTALL_LIBRARY", {
url,
@ -247,7 +248,16 @@ function* uninstallLibrarySaga(action: ReduxAction<JSLibrary>) {
if (!isValidResponse) {
yield put({
type: ReduxActionErrorTypes.UNINSTALL_LIBRARY_FAILED,
payload: accessor,
payload: {
show: true,
accessor,
error: {
message: createMessage(
customJSLibraryMessages.UNINSTALL_FAILED,
name,
),
},
},
});
AnalyticsUtil.logEvent("UNINSTALL_LIBRARY", {
url: action.payload.url,
@ -270,12 +280,19 @@ function* uninstallLibrarySaga(action: ReduxAction<JSLibrary>) {
accessor,
);
if (!success) {
toast.show(
createMessage(customJSLibraryMessages.UNINSTALL_FAILED, name),
{
kind: "error",
yield put({
type: ReduxActionErrorTypes.UNINSTALL_LIBRARY_FAILED,
payload: {
accessor,
show: true,
error: {
message: createMessage(
customJSLibraryMessages.UNINSTALL_FAILED,
name,
),
},
},
);
});
}
try {
@ -297,8 +314,18 @@ function* uninstallLibrarySaga(action: ReduxAction<JSLibrary>) {
success: true,
});
} catch (e) {
toast.show(createMessage(customJSLibraryMessages.UNINSTALL_FAILED, name), {
kind: "error",
yield put({
type: ReduxActionErrorTypes.UNINSTALL_LIBRARY_FAILED,
payload: {
accessor,
show: true,
error: {
message: createMessage(
customJSLibraryMessages.UNINSTALL_FAILED,
name,
),
},
},
});
AnalyticsUtil.logEvent("UNINSTALL_LIBRARY", {
url: action.payload.url,

View File

@ -86,7 +86,6 @@ import { UserCancelledActionExecutionError } from "sagas/ActionExecution/errorUt
import type { EventLocation } from "ee/utils/analyticsUtilTypes";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { checkAndLogErrorsIfCyclicDependency } from "./helper";
import { toast } from "@appsmith/ads";
import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers";
import {
getJSActionPathNameToDisplay,
@ -371,11 +370,16 @@ function* handleJSObjectNameChangeSuccessSaga(
);
yield take(ReduxActionTypes.FETCH_JS_ACTIONS_FOR_PAGE_SUCCESS);
if (!actionObj) {
// Error case, log to sentry
toast.show(createMessage(ERROR_JS_COLLECTION_RENAME_FAIL, ""), {
kind: "error",
yield put({
type: ReduxActionErrorTypes.SAVE_JS_COLLECTION_NAME_ERROR,
payload: {
actionId,
show: true,
error: {
message: createMessage(ERROR_JS_COLLECTION_RENAME_FAIL, ""),
},
},
});
return;
}

View File

@ -103,6 +103,7 @@ export function* lintTreeSaga(payload: LintTreeSagaRequestData) {
yield call(logLatestLintPropertyErrors, {
errors,
dataTree: unevalTree,
configTree,
});
}

View File

@ -311,6 +311,7 @@ export function* resizeModalSaga(resizeAction: ReduxAction<ModalWidgetResize>) {
payload: {
action: WidgetReduxActionTypes.WIDGET_RESIZE,
error,
logToDebugger: true,
},
});
}

View File

@ -374,16 +374,15 @@ function* BindWidgetToDatasource(
isMock: datasource.isMock,
formType: otherFields?.formType,
});
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
toast.show(e.message, {
hideProgressBar: false,
kind: "error",
});
} catch (e: unknown) {
yield put({
type: ReduxActionTypes.BIND_WIDGET_TO_DATASOURCE_ERROR,
payload: {
show: true,
error: {
message: e instanceof Error ? e.message : "Failed to Bind to widget",
},
},
});
}

View File

@ -8,7 +8,6 @@ import {
ReduxActionTypes,
} from "ee/constants/ReduxActionConstants";
import { getCurrentApplication } from "ee/selectors/applicationSelectors";
import { toast } from "@appsmith/ads";
import { getFlexLayersForSelectedWidgets } from "layoutSystems/autolayout/utils/AutoLayoutUtils";
import type { FlexLayer } from "layoutSystems/autolayout/utils/types";
import type { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
@ -76,13 +75,13 @@ export function* partialExportSaga(action: ReduxAction<PartialExportParams>) {
});
}
} catch (e) {
toast.show(createMessage(ERROR_IN_EXPORTING_APP), {
kind: "error",
});
yield put({
type: ReduxActionErrorTypes.PARTIAL_EXPORT_ERROR,
payload: {
error: "Error exporting application",
show: true,
error: {
message: createMessage(ERROR_IN_EXPORTING_APP),
},
},
});
}

View File

@ -35,12 +35,12 @@ import { isWidgetPropertyNamePath } from "utils/widgetEvalUtils";
import type { ActionEntityConfig } from "ee/entities/DataTree/types";
import type { SuccessfulBindings } from "utils/SuccessfulBindingsMap";
import SuccessfulBindingMap from "utils/SuccessfulBindingsMap";
import { logActionExecutionError } from "./ActionExecution/errorUtils";
import { getCurrentWorkspaceId } from "ee/selectors/selectedWorkspaceSelectors";
import { getInstanceId } from "ee/selectors/tenantSelectors";
import type { EvalTreeResponseData } from "workers/Evaluation/types";
import { endSpan, startRootSpan } from "UITelemetry/generateTraces";
import { getCollectionNameToDisplay } from "ee/utils/actionExecutionUtils";
import { showToastOnExecutionError } from "./ActionExecution/errorUtils";
let successfulBindingsMap: SuccessfulBindingMap | undefined;
@ -57,14 +57,24 @@ export function* logJSVarCreatedEvent(
});
}
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function* dynamicTriggerErrorHandler(errors: any[]) {
if (errors.length > 0) {
for (const error of errors) {
const errorMessage =
error.errorMessage.message.message || error.errorMessage.message;
yield call(logActionExecutionError, errorMessage, true);
export function* showExecutionErrors(errors: EvaluationError[]) {
const appMode: APP_MODE = yield select(getAppMode);
for (const error of errors) {
const errorMessage = get(
error,
"errorMessage.message.message",
error.errorMessage.message,
);
yield call(
showToastOnExecutionError,
errorMessage,
appMode === APP_MODE.EDIT,
);
// Add it to the logs tab when in edit mode
if (appMode === APP_MODE.EDIT) {
AppsmithConsole.error({
text: errorMessage,
});
}
}
}

View File

@ -1,6 +1,6 @@
import { Severity } from "entities/AppsmithConsole";
import LOG_TYPE from "entities/AppsmithConsole/logtype";
import type { DataTree } from "entities/DataTree/dataTreeTypes";
import type { ConfigTree, DataTree } from "entities/DataTree/dataTreeTypes";
import { isEmpty } from "lodash";
import AppsmithConsole from "utils/AppsmithConsole";
import { getEntityNameAndPropertyPath } from "ee/workers/Evaluation/evaluationUtils";
@ -11,11 +11,13 @@ import type { ENTITY_TYPE } from "ee/entities/AppsmithConsole/utils";
// We currently only log lint errors in JSObjects
export function* logLatestLintPropertyErrors({
configTree,
dataTree,
errors,
}: {
errors: LintErrorsStore;
configTree: ConfigTree;
dataTree: DataTree;
errors: LintErrorsStore;
}) {
const errorsToAdd = [];
const errorsToRemove = [];
@ -23,8 +25,10 @@ export function* logLatestLintPropertyErrors({
for (const path of Object.keys(errors)) {
const { entityName, propertyPath } = getEntityNameAndPropertyPath(path);
const entity = dataTree[entityName];
const config = configTree[entityName];
// only log lint errors in JSObjects
if (!isLintErrorLoggingEnabledForEntity(entity)) continue;
if (!isLintErrorLoggingEnabledForEntity(entity, propertyPath, config))
continue;
// only log lint errors (not warnings)
const lintErrorsInPath = errors[path].filter(
(error) => error.severity === Severity.ERROR,

View File

@ -7,7 +7,6 @@ import {
takeEvery,
fork,
} from "redux-saga/effects";
import * as Sentry from "@sentry/react";
import type { ApplicationPayload } from "entities/Application";
import type {
ReduxAction,
@ -70,7 +69,6 @@ import { fetchDynamicValuesSaga } from "./FormEvaluationSaga";
import type { FormEvalOutput } from "reducers/evaluationReducers/formEvaluationReducer";
import { validateResponse } from "./ErrorSagas";
import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil";
import { toast } from "@appsmith/ads";
import type { CreateDatasourceSuccessAction } from "actions/datasourceActions";
import { createDefaultActionPayloadWithPluginDefaults } from "./ActionSagas";
import { DB_NOT_SUPPORTED } from "ee/utils/Environments";
@ -494,18 +492,16 @@ function* handleNameChangeSuccessSaga(
yield take(ReduxActionTypes.FETCH_ACTIONS_FOR_PAGE_SUCCESS);
if (!actionObj) {
// Error case, log to sentry
toast.show(createMessage(ERROR_ACTION_RENAME_FAIL, ""), {
kind: "error",
});
Sentry.captureException(
new Error(createMessage(ERROR_ACTION_RENAME_FAIL, "")),
{
extra: {
actionId: actionId,
yield put({
type: ReduxActionErrorTypes.SAVE_ACTION_NAME_ERROR,
payload: {
show: true,
error: {
message: createMessage(ERROR_ACTION_RENAME_FAIL, ""),
},
logToSentry: true,
},
);
});
return;
}
if (actionObj.pluginType === PluginType.DB) {

View File

@ -434,6 +434,7 @@ export function* addChildSaga(
payload: {
action: WidgetReduxActionTypes.WIDGET_ADD_CHILD,
error,
logToDebugger: true,
},
});
}
@ -533,6 +534,7 @@ function* addUIEntitySaga(addEntityAction: ReduxAction<WidgetAddChild>) {
payload: {
action: WidgetReduxActionTypes.WIDGET_ADD_CHILD,
error,
logToDebugger: true,
},
});
}

View File

@ -340,6 +340,7 @@ export function* deleteSaga(deleteAction: ReduxAction<WidgetDelete>) {
payload: {
action: WidgetReduxActionTypes.WIDGET_DELETE,
error,
logToDebugger: true,
},
});
}
@ -481,6 +482,7 @@ function* deleteAllSelectedWidgetsSaga(
payload: {
action: WidgetReduxActionTypes.WIDGET_DELETE,
error,
logToDebugger: true,
},
});
}

View File

@ -281,6 +281,7 @@ export function* resizeSaga(resizeAction: ReduxAction<WidgetResize>) {
payload: {
action: WidgetReduxActionTypes.WIDGET_RESIZE,
error,
logToDebugger: true,
},
});
}
@ -1644,6 +1645,7 @@ function* pasteWidgetSaga(action: ReduxAction<PasteWidgetReduxAction>) {
payload: {
action: ReduxActionTypes.PASTE_COPIED_WIDGET_INIT,
error,
logToDebugger: true,
},
});
}

View File

@ -7,7 +7,6 @@ import {
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import type { LogActionPayload, Log } from "entities/AppsmithConsole";
import { Severity, LOG_CATEGORY } from "entities/AppsmithConsole";
import moment from "moment";
import store from "store";
import { isEmpty } from "lodash";
@ -29,7 +28,7 @@ function log(ev: Log) {
}
function getTimeStamp() {
return moment().format("HH:mm:ss");
return Date.now().toString();
}
function addLogs(logs: Log[]) {
@ -90,7 +89,7 @@ function addErrors(errors: ErrorObject[]) {
const refinedErrors = errors.map((error) => ({
...error.payload,
severity: error.severity ?? Severity.ERROR,
timestamp: Date.now().toString(),
timestamp: getTimeStamp(),
occurrenceCount: 1,
category: error.category ?? LOG_CATEGORY.PLATFORM_GENERATED,
isExpanded: false,