-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: module instance link in debugger (#3900)
## Description When a module instance is executed; under the hood the public entity of the module is triggered and the evaluation is only aware of the entity and not the instance. So whenever an error is raised, the error logs contain the info around the underlying entity and not the module instance. To bridge that gap; a helper transformer function is introduced that would transform the entities to the right format if it belongs to a module instance. Fixes #31813 ## Automation /ok-to-test tags="@tag.All" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!IMPORTANT] > Workflow run: <https://github.com/appsmithorg/appsmith-ee/actions/runs/8627876403> > Commit: `7e760125d2c9135130706ea70d8f7f403fc4201a` > Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=8627876403&attempt=2" target="_blank">Click here!</a> > All cypress tests have passed 🎉🎉🎉 <!-- end of auto-generated comment: Cypress test results -->
- Loading branch information
1 parent
046c86d
commit c31881a
Showing
6 changed files
with
408 additions
and
9 deletions.
There are no files selected for viewing
20 changes: 13 additions & 7 deletions
20
app/client/src/ee/components/editorComponents/Debugger/ErrorLogs/getLogIconForEntity.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,30 @@ | ||
export * from "ce/components/editorComponents/Debugger/ErrorLogs/getLogIconForEntity"; | ||
import React from "react"; | ||
import type { LogItemProps } from "components/editorComponents/Debugger/ErrorLogs/ErrorLogItem"; | ||
import type { IconEntityMapper } from "ce/components/editorComponents/Debugger/ErrorLogs/getLogIconForEntity"; | ||
import { getIconForEntity as CE_getIconForEntity } from "ce/components/editorComponents/Debugger/ErrorLogs/getLogIconForEntity"; | ||
import { importRemixIcon } from "@design-system/widgets-old"; | ||
import { ENTITY_TYPE } from "@appsmith/entities/DataTree/types"; | ||
import { getModuleIcon } from "pages/Editor/utils"; | ||
import { useSelector } from "react-redux"; | ||
import { getModuleById } from "@appsmith/selectors/modulesSelector"; | ||
import { getModuleInstanceById } from "@appsmith/selectors/moduleInstanceSelectors"; | ||
|
||
const GuideLineIcon = importRemixIcon( | ||
async () => import("remixicon-react/GuideLineIcon"), | ||
); | ||
|
||
export const getIconForEntity: Record< | ||
string, | ||
(props: LogItemProps, pluginImages: Record<string, string>) => any | ||
> = { | ||
export const getIconForEntity: IconEntityMapper = { | ||
...CE_getIconForEntity, | ||
[ENTITY_TYPE.MODULE_INPUT]: () => { | ||
return <GuideLineIcon />; | ||
}, | ||
[ENTITY_TYPE.MODULE_INSTANCE]: (props, pluginImages) => { | ||
return getModuleIcon(undefined, pluginImages); | ||
[ENTITY_TYPE.MODULE_INSTANCE]: (props) => { | ||
const moduleInstance = useSelector((state) => | ||
getModuleInstanceById(state, props.id || ""), | ||
); | ||
const module = useSelector((state) => | ||
getModuleById(state, moduleInstance?.sourceModuleId || ""), | ||
); | ||
return getModuleIcon(module, props.pluginImages) || null; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
import { | ||
ENTITY_TYPE, | ||
PLATFORM_ERROR, | ||
} from "@appsmith/entities/AppsmithConsole/utils"; | ||
import { runSaga } from "redux-saga"; | ||
import { transformAddErrorLogsSaga } from "./helpers"; | ||
import { Severity, type Log, LOG_CATEGORY } from "entities/AppsmithConsole"; | ||
import { klona } from "klona"; | ||
import { set } from "lodash"; | ||
import { MODULE_TYPE } from "@appsmith/constants/ModuleConstants"; | ||
|
||
const queryModuleInstanceErrorLog: Log = { | ||
id: "queryInstanceActionId", | ||
iconId: "644b84d980127e0eff78a732", | ||
logType: 2, | ||
environmentName: "Production", | ||
text: "Execution failed with status SQLSTATE: 42601", | ||
source: { | ||
type: ENTITY_TYPE.ACTION, | ||
name: "QueryModule31", | ||
id: "queryInstanceActionId", | ||
}, | ||
messages: [ | ||
{ | ||
message: { | ||
name: "PluginExecutionError", | ||
message: "ERROR: syntax error at end of input\n Position: 35", | ||
}, | ||
type: PLATFORM_ERROR.PLUGIN_EXECUTION, | ||
subType: "INTERNAL_ERROR", | ||
}, | ||
], | ||
state: { | ||
actionId: "queryInstanceActionId", | ||
requestedAt: 1712125304920, | ||
requestParams: { | ||
Query: { | ||
value: 'SELECT * FROM public."users" LIMIT;', | ||
substitutedParams: {}, | ||
}, | ||
}, | ||
}, | ||
pluginErrorDetails: { | ||
title: "Query execution error", | ||
errorType: "INTERNAL_ERROR", | ||
appsmithErrorCode: "PE-PGS-5000", | ||
appsmithErrorMessage: "Your PostgreSQL query failed to execute.", | ||
downstreamErrorCode: "SQLSTATE: 42601", | ||
downstreamErrorMessage: | ||
"ERROR: syntax error at end of input\n Position: 35", | ||
}, | ||
severity: Severity.ERROR, | ||
timestamp: "1712125307046", | ||
occurrenceCount: 1, | ||
category: LOG_CATEGORY.PLATFORM_GENERATED, | ||
isExpanded: false, | ||
}; | ||
|
||
const jsModuleInstanceErrorLog: Log = { | ||
id: "moduleInstanceJSCollectionId-actionId", | ||
logType: 5, | ||
text: "JS Function execution failed: JSModule11.myFun1", | ||
messages: [ | ||
{ | ||
message: { | ||
name: "TypeError", | ||
message: "x.asdkljas is not a function", | ||
}, | ||
type: PLATFORM_ERROR.JS_FUNCTION_EXECUTION, | ||
subType: "PARSE", | ||
}, | ||
], | ||
source: { | ||
id: "moduleInstanceJSCollectionId", | ||
name: "JSModule11", | ||
type: ENTITY_TYPE.JSACTION, | ||
propertyPath: "myFun1", | ||
}, | ||
severity: Severity.ERROR, | ||
timestamp: "1712132302018", | ||
occurrenceCount: 1, | ||
category: LOG_CATEGORY.PLATFORM_GENERATED, | ||
isExpanded: false, | ||
}; | ||
|
||
const DEFAULT_STATE = { | ||
entities: { | ||
moduleInstances: { | ||
queryModuleInstanceId: { | ||
id: "queryModuleInstanceId", | ||
type: MODULE_TYPE.QUERY, | ||
sourceModuleId: "queryModuleId", | ||
name: "QueryModule31", | ||
contextType: "PAGE", | ||
contextId: "65fc1233b48e3e52a6d91d3b", | ||
applicationId: "65fc1233b48e3e52a6d91d37", | ||
workspaceId: "65fc11fdb48e3e52a6d91d30", | ||
}, | ||
jsModuleInstanceId: { | ||
id: "jsModuleInstanceId", | ||
type: MODULE_TYPE.JS, | ||
sourceModuleId: "jsModuleId", | ||
name: "JSModule11", | ||
contextType: "PAGE", | ||
contextId: "65fc1233b48e3e52a6d91d3b", | ||
applicationId: "65fc1233b48e3e52a6d91d37", | ||
workspaceId: "65fc11fdb48e3e52a6d91d30", | ||
}, | ||
}, | ||
moduleInstanceEntities: { | ||
actions: [ | ||
{ | ||
config: { | ||
id: "queryInstanceActionId", | ||
moduleInstanceId: "queryModuleInstanceId", | ||
}, | ||
}, | ||
], | ||
jsCollections: [ | ||
{ | ||
config: { | ||
id: "moduleInstanceJSCollectionId", | ||
moduleInstanceId: "jsModuleInstanceId", | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
}; | ||
|
||
const widgetErrorLog = { | ||
id: "j1vz86pd0v-defaultText", | ||
iconId: "j1vz86pd0v", | ||
logType: 5, | ||
text: "The value at defaultText is invalid", | ||
messages: [ | ||
{ | ||
message: { | ||
name: "SyntaxError", | ||
message: "Unexpected token '('", | ||
}, | ||
type: "PARSE", | ||
}, | ||
{ | ||
message: { | ||
name: "TypeError", | ||
message: "This value must be string", | ||
}, | ||
type: "VALIDATION", | ||
}, | ||
], | ||
source: { | ||
id: "j1vz86pd0v", | ||
name: "Input1", | ||
type: ENTITY_TYPE.WIDGET, | ||
propertyPath: "defaultText", | ||
pluginType: "INPUT_WIDGET_V2", | ||
}, | ||
analytics: { | ||
widgetType: "INPUT_WIDGET_V2", | ||
}, | ||
} as unknown as Log; | ||
|
||
const moduleInputErrorLog = { | ||
id: "6603c72ce98dd96ec6fde480-input1", | ||
iconId: "QUERY_MODULE", | ||
logType: 5, | ||
text: "The value at input1 is invalid", | ||
messages: [ | ||
{ | ||
message: { | ||
name: "ReferenceError", | ||
message: "sss is not defined", | ||
}, | ||
type: "PARSE", | ||
}, | ||
], | ||
source: { | ||
id: "6603c72ce98dd96ec6fde480", | ||
name: "inputs", | ||
type: ENTITY_TYPE.MODULE_INPUT, | ||
propertyPath: "input1", | ||
}, | ||
analytics: {}, | ||
} as unknown as Log; | ||
|
||
describe("transformAddErrorLogsSaga", () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it("transforms logs with ENTITY_TYPE.ACTION belonging to a module instance", async () => { | ||
const logs: Log[] = [queryModuleInstanceErrorLog]; | ||
const result = await runSaga( | ||
{ | ||
getState: () => DEFAULT_STATE, | ||
}, | ||
transformAddErrorLogsSaga, | ||
logs, | ||
).toPromise(); | ||
|
||
const expectedResult = klona(logs); | ||
expectedResult[0].id = "queryModuleInstanceId"; | ||
if (expectedResult[0].source) { | ||
expectedResult[0].source.name = "QueryModule31"; | ||
expectedResult[0].source.type = ENTITY_TYPE.MODULE_INSTANCE; | ||
expectedResult[0].source.id = "queryModuleInstanceId"; | ||
} | ||
|
||
expect(result).toEqual(expectedResult); | ||
}); | ||
|
||
it("doesn't transform logs with ENTITY_TYPE.ACTION not belonging to a module instance", async () => { | ||
const actionLog = klona(queryModuleInstanceErrorLog); | ||
actionLog.id = "action-id"; | ||
set(actionLog, "source.id", "action-id"); | ||
const logs: Log[] = [actionLog]; | ||
const result = await runSaga( | ||
{ | ||
getState: () => DEFAULT_STATE, | ||
}, | ||
transformAddErrorLogsSaga, | ||
logs, | ||
).toPromise(); | ||
|
||
expect(result).toEqual(logs); | ||
}); | ||
|
||
it("transforms logs with ENTITY_TYPE.JSACTION belonging to a module instance", async () => { | ||
const logs: Log[] = [jsModuleInstanceErrorLog]; | ||
const result = await runSaga( | ||
{ | ||
getState: () => DEFAULT_STATE, | ||
}, | ||
transformAddErrorLogsSaga, | ||
logs, | ||
).toPromise(); | ||
|
||
const expectedResult = klona(logs); | ||
if (expectedResult[0].source) { | ||
expectedResult[0].source.name = "JSModule11"; | ||
expectedResult[0].source.type = ENTITY_TYPE.MODULE_INSTANCE; | ||
expectedResult[0].source.id = "jsModuleInstanceId"; | ||
} | ||
|
||
expect(result).toEqual(expectedResult); | ||
}); | ||
|
||
it("doesn't transform logs with ENTITY_TYPE.JSACTION not belonging to a module instance", async () => { | ||
const logs: Log[] = [widgetErrorLog, moduleInputErrorLog]; | ||
const result = await runSaga( | ||
{ | ||
getState: () => DEFAULT_STATE, | ||
}, | ||
transformAddErrorLogsSaga, | ||
logs, | ||
).toPromise(); | ||
|
||
expect(result).toEqual(logs); | ||
}); | ||
|
||
it("doesn't transform logs for any other entity type than JSACTION and ACTION", async () => {}); | ||
}); |
Oops, something went wrong.