feat: Added warning message in response pane while prepared statement is on (#36407)

## Description

Added warning message in response pane to show that use prepared
statement is turned on. This will be showing up only if there is an
error.

Fixes #36326 

## Automation

/ok-to-test tags="@tag.Sanity, @tag.Datasource"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/10987691166>
> Commit: debc9f34515ee9303ac8e96d59cb8b59a6c5ecbf
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10987691166&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Sanity, @tag.Datasource`
> Spec:
> <hr>Mon, 23 Sep 2024 05:25:23 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced a warning message for users regarding prepared statements
that may cause query errors.
- Added a mechanism to navigate users to the settings page for resolving
issues related to prepared statements.
- Enhanced the Query Response Tab with contextual warnings and improved
user guidance.

- **Bug Fixes**
- Improved error handling related to prepared statements in the query
response.

- **Tests**
- Added comprehensive unit tests for the Query Response Tab to ensure
correct behavior of the prepared statement warning under various
conditions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
albinAppsmith 2024-09-23 19:27:43 +05:30 committed by GitHub
parent cd3472ac1d
commit 12986df894
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 287 additions and 2 deletions

View File

@ -2503,3 +2503,9 @@ export const EMPTY_DATASOURCE_TOOLTIP_SIDEBUTTON = () =>
"Create a datasource to power your app with data.";
export const FIELD_REQUIRED_MESSAGE = () => `This field is required`;
export const PREPARED_STATEMENT_WARNING = {
MESSAGE: () =>
"Prepared Statements are currently enabled, which may be causing the query error. Turn them off and try running the query again",
LINK: () => "Open settings",
};

View File

@ -0,0 +1,235 @@
import React from "react";
import { render } from "@testing-library/react";
import { Provider } from "react-redux";
import configureStore from "redux-mock-store";
import QueryResponseTab from "./QueryResponseTab";
import { ENTITY_TYPE } from "ee/entities/AppsmithConsole/utils";
import type { Action } from "entities/Action";
import { unitTestBaseMockStore } from "layoutSystems/common/dropTarget/unitTestUtils";
import { EditorViewMode } from "ee/entities/IDE/constants";
import { lightTheme } from "selectors/themeSelectors";
import { ThemeProvider } from "styled-components";
import { BrowserRouter as Router } from "react-router-dom";
// Mock store
const mockStore = configureStore([]);
const defaultProps = {
actionName: "Test Action",
actionSource: {
name: "test source",
id: "test-source-id",
type: ENTITY_TYPE.ACTION,
},
currentActionConfig: {
id: "test-action-id",
name: "Test Action",
actionConfiguration: { pluginSpecifiedTemplates: [{ value: true }] },
userPermissions: ["execute"],
} as Action,
isRunning: false,
onRunClick: jest.fn(),
runErrorMessage: "",
};
const storeData = {
...unitTestBaseMockStore,
evaluations: {
tree: {},
},
entities: {
plugins: {
list: [],
},
datasources: {
structure: {},
},
},
ui: {
...unitTestBaseMockStore.ui,
users: {
featureFlag: {
data: {},
overriddenFlags: {},
},
},
ide: {
view: EditorViewMode.FullScreen,
},
debugger: {
context: {
errorCount: 0,
},
},
queryPane: {
debugger: {
open: true,
responseTabHeight: 200,
selectedTab: "response",
},
},
},
};
describe("QueryResponseTab", () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let store: any;
beforeEach(() => {
store = mockStore(storeData);
});
/** Test use prepared statement warning **/
it("1. Prepared statement warning should not be showing", () => {
const { container } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<QueryResponseTab {...defaultProps} />
</Router>
</ThemeProvider>
</Provider>,
);
// Check if the prepared statement warning is not showing
expect(
container.querySelector("[data-testid='t--prepared-statement-warning']"),
).toBeNull();
});
it("2. Check if prepared statement warning is not showing while running the query", () => {
const { container } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<QueryResponseTab {...defaultProps} isRunning />
</Router>
</ThemeProvider>
</Provider>,
);
// Check if the prepared statement warning is showing
expect(
container.querySelector("[data-testid='t--prepared-statement-warning']"),
).toBeNull();
});
it("3. Check if prepared statement warning is not showing when run is successful", () => {
store = mockStore({
...storeData,
entities: {
...storeData.entities,
actions: [
{
config: {
id: "test-action-id",
name: "Test Action",
},
isLoading: false,
data: {
body: [{ key: "value" }],
isExecutionSuccess: true,
},
},
],
},
});
const { container } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<QueryResponseTab {...defaultProps} />
</Router>
</ThemeProvider>
</Provider>,
);
// Check if the prepared statement warning is showing
expect(
container.querySelector("[data-testid='t--prepared-statement-warning']"),
).toBeNull();
});
it("4. Check if prepared statement warning is showing when run is failed", () => {
store = mockStore({
...storeData,
entities: {
...storeData.entities,
actions: [
{
config: {
id: "test-action-id",
name: "Test Action",
},
isLoading: false,
data: {
body: "ERROR: relation 'userssss' does not exist Position: 15",
isExecutionSuccess: false,
},
},
],
},
});
const { container } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<QueryResponseTab {...defaultProps} />
</Router>
</ThemeProvider>
</Provider>,
);
// Check if the prepared statement warning is showing
expect(
container.querySelector("[data-testid='t--prepared-statement-warning']"),
).not.toBeNull();
});
it("5. Check if prepared statement warning is not showing when prepared statement is turned off", () => {
store = mockStore({
...storeData,
entities: {
...storeData.entities,
actions: [
{
config: {
id: "test-action-id",
name: "Test Action",
},
isLoading: false,
data: {
body: "ERROR: relation 'userssss' does not exist Position: 15",
isExecutionSuccess: false,
},
},
],
},
});
const props = {
...defaultProps,
currentActionConfig: {
...defaultProps.currentActionConfig,
actionConfiguration: { pluginSpecifiedTemplates: [{ value: false }] },
} as Action,
};
const { container } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<QueryResponseTab {...props} />
</Router>
</ThemeProvider>
</Provider>,
);
// Check if the prepared statement warning is showing
expect(
container.querySelector("[data-testid='t--prepared-statement-warning']"),
).toBeNull();
});
});

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useCallback, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import ReactJson from "react-json-view";
import {
@ -13,7 +13,12 @@ import LogAdditionalInfo from "components/editorComponents/Debugger/ErrorLogs/co
import LogHelper from "components/editorComponents/Debugger/ErrorLogs/components/LogHelper";
import LOG_TYPE from "entities/AppsmithConsole/logtype";
import { JsonWrapper } from "components/editorComponents/Debugger/ErrorLogs/components/LogCollapseData";
import { Callout, Flex, SegmentedControl } from "@appsmith/ads";
import {
Callout,
Flex,
SegmentedControl,
type CalloutLinkProps,
} from "@appsmith/ads";
import styled from "styled-components";
import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
@ -32,6 +37,12 @@ import ActionExecutionInProgressView from "components/editorComponents/ActionExe
import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig";
import BindDataButton from "./BindDataButton";
import { getQueryPaneDebuggerState } from "selectors/queryPaneSelectors";
import { setQueryPaneConfigSelectedTabIndex } from "actions/queryPaneActions";
import { EDITOR_TABS } from "constants/QueryEditorConstants";
import {
createMessage,
PREPARED_STATEMENT_WARNING,
} from "ee/constants/messages";
const HelpSection = styled.div``;
@ -151,6 +162,7 @@ const QueryResponseTab = (props: Props) => {
let error = runErrorMessage;
let hintMessages: Array<string> = [];
let showPreparedStatementWarning = false;
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let output: Record<string, any>[] | null = null;
@ -189,8 +201,31 @@ const QueryResponseTab = (props: Props) => {
error = "";
hintMessages = actionResponse.messages;
}
const { pluginSpecifiedTemplates } =
currentActionConfig.actionConfiguration;
if (
error &&
pluginSpecifiedTemplates &&
pluginSpecifiedTemplates.length > 0 &&
pluginSpecifiedTemplates[0].value === true
) {
showPreparedStatementWarning = true;
}
}
const navigateToSettings = useCallback(() => {
dispatch(setQueryPaneConfigSelectedTabIndex(EDITOR_TABS.SETTINGS));
}, []);
const preparedStatementCalloutLinks: CalloutLinkProps[] = [
{
onClick: navigateToSettings,
children: createMessage(PREPARED_STATEMENT_WARNING.LINK),
},
];
if (isRunning) {
return (
<ActionExecutionInProgressView
@ -202,6 +237,15 @@ const QueryResponseTab = (props: Props) => {
return (
<ResponseContentWrapper isError={!!error}>
{showPreparedStatementWarning && (
<Callout
data-testid="t--prepared-statement-warning"
kind="warning"
links={preparedStatementCalloutLinks}
>
{createMessage(PREPARED_STATEMENT_WARNING.MESSAGE)}
</Callout>
)}
{error && (
<ResponseTabErrorContainer>
<ResponseTabErrorContent>