Merge branch 'fix/queryPane' into 'release'

Fix/query pane

- Show mongo execute response in seperate cards for each record
- Update postgres read template
- Show query execute error message in the UI.

See merge request theappsmith/internal-tools-client!595
This commit is contained in:
Arpit Mohan 2020-05-16 07:22:25 +00:00
commit be113dd069
6 changed files with 98 additions and 15 deletions

View File

@ -10,7 +10,6 @@ import {
ColumnsDirective, ColumnsDirective,
ColumnDirective, ColumnDirective,
} from "@syncfusion/ej2-react-grids"; } from "@syncfusion/ej2-react-grids";
import ReactJson from "react-json-view";
import styled, { createGlobalStyle } from "styled-components"; import styled, { createGlobalStyle } from "styled-components";
import { Popover, Icon } from "@blueprintjs/core"; import { Popover, Icon } from "@blueprintjs/core";
import { components, MenuListComponentProps } from "react-select"; import { components, MenuListComponentProps } from "react-select";
@ -29,8 +28,9 @@ import { Datasource } from "api/DatasourcesApi";
import { RestAction } from "api/ActionAPI"; import { RestAction } from "api/ActionAPI";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms"; import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
import { PLUGIN_PACKAGE_POSTGRES } from "constants/QueryEditorConstants"; import { PLUGIN_PACKAGE_POSTGRES } from "constants/QueryEditorConstants";
import { Colors } from "constants/Colors";
import "@syncfusion/ej2-react-grids/styles/material.css"; import "@syncfusion/ej2-react-grids/styles/material.css";
import { Colors } from "constants/Colors";
import JSONViewer from "./JSONViewer";
const QueryFormContainer = styled.div` const QueryFormContainer = styled.div`
font-size: 20px; font-size: 20px;
@ -180,6 +180,10 @@ const StyledGridComponent = styled(GridComponent)`
} }
`; `;
const ErrorMessage = styled.p`
font-size: 14px;
color: ${Colors.RED};
`;
const CreateDatasource = styled.div` const CreateDatasource = styled.div`
height: 44px; height: 44px;
display: flex; display: flex;
@ -212,6 +216,7 @@ type QueryFormProps = {
executedQueryData: any; executedQueryData: any;
applicationId: string; applicationId: string;
selectedPluginPackage: string; selectedPluginPackage: string;
runErrorMessage: string | undefined;
pageId: string; pageId: string;
location: { location: {
state: any; state: any;
@ -241,6 +246,7 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
selectedPluginPackage, selectedPluginPackage,
createTemplate, createTemplate,
isCreating, isCreating,
runErrorMessage,
} = props; } = props;
const [showTemplateMenu, setMenuVisibility] = useState(true); const [showTemplateMenu, setMenuVisibility] = useState(true);
@ -446,6 +452,13 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
</NoDataSourceContainer> </NoDataSourceContainer>
)} )}
{runErrorMessage && (
<>
<p className="statementTextArea">Query error</p>
<ErrorMessage>{runErrorMessage}</ErrorMessage>
</>
)}
{executedQueryData && dataSources.length && ( {executedQueryData && dataSources.length && (
<ResponseContainer> <ResponseContainer>
<p className="statementTextArea">Query response</p> <p className="statementTextArea">Query response</p>
@ -470,16 +483,7 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
</ColumnsDirective> </ColumnsDirective>
</StyledGridComponent> </StyledGridComponent>
) : ( ) : (
<ReactJson <JSONViewer src={executedQueryData.body} />
src={executedQueryData.body}
name={null}
enableClipboard={false}
displayObjectSize={false}
displayDataTypes={false}
style={{
fontSize: "14px",
}}
/>
)} )}
</ResponseContent> </ResponseContent>
</ResponseContainer> </ResponseContainer>

View File

@ -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<Props> {
render() {
const { src } = this.props;
const reactJsonProps = {
name: null,
enableClipboard: false,
displayObjectSize: false,
displayDataTypes: false,
style: {
fontSize: "14px",
},
};
if (!src.length) {
return (
<OutputContainer>
<Record>
<ReactJson src={src} {...reactJsonProps} />
</Record>
</OutputContainer>
);
}
return (
<OutputContainer>
{src.map((record, index) => {
return (
<Record key={index}>
<ReactJson src={record} {...reactJsonProps} />
</Record>
);
})}
</OutputContainer>
);
}
}
export default JSONOutput;

View File

@ -42,7 +42,7 @@ const Templates: Record<string, any> = {
create: `INSERT INTO users( create: `INSERT INTO users(
id, name, gender, avatar, email, address, role) id, name, gender, avatar, email, address, role)
VALUES (?, ?, ?, ?, ?, ?, ?);`, 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=?`, delete: `DELETE FROM users WHERE id=?`,
update: `UPDATE users update: `UPDATE users
Set status='APPROVED' Set status='APPROVED'

View File

@ -45,6 +45,7 @@ type QueryPageProps = {
submitForm: (name: string) => void; submitForm: (name: string) => void;
createAction: (values: RestAction) => void; createAction: (values: RestAction) => void;
runAction: (action: RestAction, actionId: string) => void; runAction: (action: RestAction, actionId: string) => void;
runErrorMessage: Record<string, string>;
deleteAction: (id: string) => void; deleteAction: (id: string) => void;
updateAction: (data: RestAction) => void; updateAction: (data: RestAction) => void;
createTemplate: (template: string) => void; createTemplate: (template: string) => void;
@ -91,6 +92,7 @@ class QueryEditor extends React.Component<Props> {
selectedPluginPackage, selectedPluginPackage,
apiPane, apiPane,
isCreating, isCreating,
runErrorMessage,
} = this.props; } = this.props;
const { applicationId, pageId } = this.props.match.params; const { applicationId, pageId } = this.props.match.params;
@ -135,6 +137,7 @@ class QueryEditor extends React.Component<Props> {
DATASOURCES_OPTIONS={DATASOURCES_OPTIONS} DATASOURCES_OPTIONS={DATASOURCES_OPTIONS}
selectedPluginPackage={selectedPluginPackage} selectedPluginPackage={selectedPluginPackage}
executedQueryData={executedQueryData[queryId]} executedQueryData={executedQueryData[queryId]}
runErrorMessage={runErrorMessage[queryId]}
/> />
) : ( ) : (
<QueryHomeScreen <QueryHomeScreen
@ -152,6 +155,7 @@ class QueryEditor extends React.Component<Props> {
} }
const mapStateToProps = (state: AppState): any => { const mapStateToProps = (state: AppState): any => {
const { runErrorMessage } = state.ui.queryPane;
const formData = getFormValues(QUERY_EDITOR_FORM_NAME)(state) as RestAction; const formData = getFormValues(QUERY_EDITOR_FORM_NAME)(state) as RestAction;
const initialValues = getFormInitialValues(QUERY_EDITOR_FORM_NAME)( const initialValues = getFormInitialValues(QUERY_EDITOR_FORM_NAME)(
state, state,
@ -163,6 +167,7 @@ const mapStateToProps = (state: AppState): any => {
); );
return { return {
runErrorMessage,
apiPane: state.ui.apiPane, apiPane: state.ui.apiPane,
pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS), pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS),
dataSources: getDataSources(state), dataSources: getDataSources(state),

View File

@ -5,6 +5,7 @@ import {
ReduxAction, ReduxAction,
} from "constants/ReduxActionConstants"; } from "constants/ReduxActionConstants";
import { RestAction } from "api/ActionAPI"; import { RestAction } from "api/ActionAPI";
import _ from "lodash";
const initialState: QueryPaneReduxState = { const initialState: QueryPaneReduxState = {
isFetching: false, isFetching: false,
@ -13,6 +14,7 @@ const initialState: QueryPaneReduxState = {
isSaving: {}, isSaving: {},
isDeleting: {}, isDeleting: {},
runQuerySuccessData: {}, runQuerySuccessData: {},
runErrorMessage: {},
lastUsed: "", lastUsed: "",
}; };
@ -22,6 +24,7 @@ export interface QueryPaneReduxState {
isSaving: Record<string, boolean>; isSaving: Record<string, boolean>;
isDeleting: Record<string, boolean>; isDeleting: Record<string, boolean>;
runQuerySuccessData: {}; runQuerySuccessData: {};
runErrorMessage: Record<string, string>;
lastUsed: string; lastUsed: string;
isCreating: boolean; isCreating: boolean;
} }
@ -134,6 +137,8 @@ const queryPaneReducer = createReducer(initialState, {
state: any, state: any,
action: ReduxAction<{ actionId: string; data: object }>, action: ReduxAction<{ actionId: string; data: object }>,
) => { ) => {
const { actionId } = action.payload;
return { return {
...state, ...state,
isRunning: { isRunning: {
@ -144,17 +149,24 @@ const queryPaneReducer = createReducer(initialState, {
...state.runQuerySuccessData, ...state.runQuerySuccessData,
[action.payload.actionId]: action.payload.data, [action.payload.actionId]: action.payload.data,
}, },
runErrorMessage: _.omit(state.runErrorMessage, [actionId]),
}; };
}, },
[ReduxActionErrorTypes.RUN_QUERY_ERROR]: ( [ReduxActionErrorTypes.RUN_QUERY_ERROR]: (
state: any, state: any,
action: ReduxAction<{ actionId: string }>, action: ReduxAction<{ actionId: string; message: string }>,
) => { ) => {
const { actionId, message } = action.payload;
return { return {
...state, ...state,
isRunning: { isRunning: {
...state.isRunning, ...state.isRunning,
[action.payload.actionId]: false, [actionId]: false,
},
runErrorMessage: {
...state.runError,
[actionId]: message,
}, },
}; };
}, },

View File

@ -246,6 +246,7 @@ export function* executeQuerySaga(
type: ReduxActionErrorTypes.RUN_QUERY_ERROR, type: ReduxActionErrorTypes.RUN_QUERY_ERROR,
payload: { payload: {
actionId: actionPayload.payload.actionId, actionId: actionPayload.payload.actionId,
message: error.message,
show: false, show: false,
}, },
}); });