Skip to content

Commit

Permalink
feat: Added warning message in response pane while prepared statement…
Browse files Browse the repository at this point in the history
… is on (appsmithorg#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 appsmithorg#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: debc9f3
> <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 -->
  • Loading branch information
albinAppsmith authored and Shivam-z committed Sep 26, 2024
1 parent 8aaaeac commit f285638
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 2 deletions.
6 changes: 6 additions & 0 deletions app/client/src/ce/constants/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
};
235 changes: 235 additions & 0 deletions app/client/src/pages/Editor/QueryEditor/QueryResponseTab.test.tsx
Original file line number Diff line number Diff line change
@@ -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();
});
});
48 changes: 46 additions & 2 deletions app/client/src/pages/Editor/QueryEditor/QueryResponseTab.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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";
Expand All @@ -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``;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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>
Expand Down

0 comments on commit f285638

Please sign in to comment.