diff --git a/app/client/src/pages/Editor/QueryEditor/Form.tsx b/app/client/src/pages/Editor/QueryEditor/Form.tsx index 3d1d914017..765dd1a143 100644 --- a/app/client/src/pages/Editor/QueryEditor/Form.tsx +++ b/app/client/src/pages/Editor/QueryEditor/Form.tsx @@ -10,7 +10,6 @@ import { ColumnsDirective, ColumnDirective, } from "@syncfusion/ej2-react-grids"; -import ReactJson from "react-json-view"; import styled, { createGlobalStyle } from "styled-components"; import { Popover } from "@blueprintjs/core"; import history from "utils/history"; @@ -29,6 +28,8 @@ import { RestAction } from "api/ActionAPI"; import { QUERY_EDITOR_FORM_NAME } from "constants/forms"; import { PLUGIN_PACKAGE_POSTGRES } from "constants/QueryEditorConstants"; import "@syncfusion/ej2-react-grids/styles/material.css"; +import { Colors } from "constants/Colors"; +import JSONViewer from "./JSONViewer"; const QueryFormContainer = styled.div` font-size: 20px; @@ -178,6 +179,11 @@ const StyledGridComponent = styled(GridComponent)` } `; +const ErrorMessage = styled.p` + font-size: 14px; + color: ${Colors.RED}; +`; + type QueryFormProps = { isCreating: boolean; onDeleteClick: () => void; @@ -194,6 +200,7 @@ type QueryFormProps = { executedQueryData: any; applicationId: string; selectedPluginPackage: string; + runErrorMessage: string | undefined; pageId: string; location: { state: any; @@ -223,6 +230,7 @@ const QueryEditorForm: React.FC = (props: Props) => { selectedPluginPackage, createTemplate, isCreating, + runErrorMessage, } = props; const [showTemplateMenu, setMenuVisibility] = useState(true); @@ -251,6 +259,7 @@ const QueryEditorForm: React.FC = (props: Props) => { ); } + return (
@@ -411,6 +420,13 @@ const QueryEditorForm: React.FC = (props: Props) => { )} + {runErrorMessage && ( + <> +

Query error

+ {runErrorMessage} + + )} + {executedQueryData && dataSources.length && (

Query response

@@ -435,16 +451,7 @@ const QueryEditorForm: React.FC = (props: Props) => { ) : ( - + )}
diff --git a/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx b/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx new file mode 100644 index 0000000000..43306d43f5 --- /dev/null +++ b/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx @@ -0,0 +1,61 @@ +import React from "react"; +import ReactJson from "react-json-view"; +import styled from "styled-components"; +import { Card } from "@blueprintjs/core"; + +const OutputContainer = styled.div` + background: #f5f6f7; + border: 1px solid #d0d7dd; + box-sizing: border-box; + border-radius: 4px; + padding: 6px; +`; + +const Record = styled(Card)` + margin: 5px; +`; + +type JSONOutputProps = { + src: []; +}; + +type Props = JSONOutputProps; + +class JSONOutput extends React.Component { + render() { + const { src } = this.props; + const reactJsonProps = { + name: null, + enableClipboard: false, + displayObjectSize: false, + displayDataTypes: false, + style: { + fontSize: "14px", + }, + }; + + if (!src.length) { + return ( + + + + + + ); + } + + return ( + + {src.map((record, index) => { + return ( + + + + ); + })} + + ); + } +} + +export default JSONOutput; diff --git a/app/client/src/pages/Editor/QueryEditor/Templates.tsx b/app/client/src/pages/Editor/QueryEditor/Templates.tsx index b302520349..43841e514d 100644 --- a/app/client/src/pages/Editor/QueryEditor/Templates.tsx +++ b/app/client/src/pages/Editor/QueryEditor/Templates.tsx @@ -42,7 +42,7 @@ const Templates: Record = { create: `INSERT INTO users( id, name, gender, avatar, email, address, role) VALUES (?, ?, ?, ?, ?, ?, ?);`, - read: "SELECT * FROM users LIMIT 10 ORDER BY id", + read: "SELECT * FROM users ORDER BY id LIMIT 10", delete: `DELETE FROM users WHERE id=?`, update: `UPDATE users Set status='APPROVED' diff --git a/app/client/src/pages/Editor/QueryEditor/index.tsx b/app/client/src/pages/Editor/QueryEditor/index.tsx index a0e7d42b97..a74c00d970 100644 --- a/app/client/src/pages/Editor/QueryEditor/index.tsx +++ b/app/client/src/pages/Editor/QueryEditor/index.tsx @@ -45,6 +45,7 @@ type QueryPageProps = { submitForm: (name: string) => void; createAction: (values: RestAction) => void; runAction: (action: RestAction, actionId: string) => void; + runErrorMessage: Record; deleteAction: (id: string) => void; updateAction: (data: RestAction) => void; createTemplate: (template: string) => void; @@ -91,6 +92,7 @@ class QueryEditor extends React.Component { selectedPluginPackage, apiPane, isCreating, + runErrorMessage, } = this.props; const { applicationId, pageId } = this.props.match.params; @@ -139,6 +141,7 @@ class QueryEditor extends React.Component { DATASOURCES_OPTIONS={DATASOURCES_OPTIONS} selectedPluginPackage={selectedPluginPackage} executedQueryData={executedQueryData[queryId]} + runErrorMessage={runErrorMessage[queryId]} /> ) : ( { } const mapStateToProps = (state: AppState): any => { + const { runErrorMessage } = state.ui.queryPane; const formData = getFormValues(QUERY_EDITOR_FORM_NAME)(state) as RestAction; const initialValues = getFormInitialValues(QUERY_EDITOR_FORM_NAME)( state, @@ -167,6 +171,7 @@ const mapStateToProps = (state: AppState): any => { ); return { + runErrorMessage, apiPane: state.ui.apiPane, pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS), dataSources: getDataSources(state), diff --git a/app/client/src/reducers/uiReducers/queryPaneReducer.ts b/app/client/src/reducers/uiReducers/queryPaneReducer.ts index 97be99adf3..0e1823eae4 100644 --- a/app/client/src/reducers/uiReducers/queryPaneReducer.ts +++ b/app/client/src/reducers/uiReducers/queryPaneReducer.ts @@ -5,6 +5,7 @@ import { ReduxAction, } from "constants/ReduxActionConstants"; import { RestAction } from "api/ActionAPI"; +import _ from "lodash"; const initialState: QueryPaneReduxState = { isFetching: false, @@ -13,6 +14,7 @@ const initialState: QueryPaneReduxState = { isSaving: {}, isDeleting: {}, runQuerySuccessData: {}, + runErrorMessage: {}, lastUsed: "", }; @@ -22,6 +24,7 @@ export interface QueryPaneReduxState { isSaving: Record; isDeleting: Record; runQuerySuccessData: {}; + runErrorMessage: Record; lastUsed: string; isCreating: boolean; } @@ -134,6 +137,8 @@ const queryPaneReducer = createReducer(initialState, { state: any, action: ReduxAction<{ actionId: string; data: object }>, ) => { + const { actionId } = action.payload; + return { ...state, isRunning: { @@ -144,17 +149,24 @@ const queryPaneReducer = createReducer(initialState, { ...state.runQuerySuccessData, [action.payload.actionId]: action.payload.data, }, + runErrorMessage: _.omit(state.runErrorMessage, [actionId]), }; }, [ReduxActionErrorTypes.RUN_QUERY_ERROR]: ( state: any, - action: ReduxAction<{ actionId: string }>, + action: ReduxAction<{ actionId: string; message: string }>, ) => { + const { actionId, message } = action.payload; + return { ...state, isRunning: { ...state.isRunning, - [action.payload.actionId]: false, + [actionId]: false, + }, + runErrorMessage: { + ...state.runError, + [actionId]: message, }, }; }, diff --git a/app/client/src/sagas/QueryPaneSagas.ts b/app/client/src/sagas/QueryPaneSagas.ts index c2c7dfc79c..4606c7fdac 100644 --- a/app/client/src/sagas/QueryPaneSagas.ts +++ b/app/client/src/sagas/QueryPaneSagas.ts @@ -246,6 +246,7 @@ export function* executeQuerySaga( type: ReduxActionErrorTypes.RUN_QUERY_ERROR, payload: { actionId: actionPayload.payload.actionId, + message: error.message, show: false, }, });