From f28b9bd20b0403e1a00a6978d407423c34395b51 Mon Sep 17 00:00:00 2001 From: Pranav Kanade Date: Thu, 8 Jul 2021 12:47:56 +0530 Subject: [PATCH] [Fix] create new api not working from saved google sheet state (#5681) * fix show proper icons for queries * Using query creation action creator for google sheet * Properly setting up action config, if data source is of type api * minor loading state fixed * fixed warnings * Handling the action for apis as well * Re introduced the new query btn for google sheets --- .../Editor/DataSourceEditor/Connected.tsx | 91 +++++++------------ .../RestAPIDatasourceForm.tsx | 1 + .../Editor/Explorer/Actions/ActionsGroup.tsx | 4 +- .../IntegrationEditor/ActiveDataSources.tsx | 53 +++++++---- .../IntegrationEditor/DatasourceCard.tsx | 21 +++-- .../Editor/SaaSEditor/DatasourceForm.tsx | 78 ++++++++++------ 6 files changed, 136 insertions(+), 112 deletions(-) diff --git a/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx b/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx index b5bab0dbdd..524b401e27 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx @@ -7,21 +7,19 @@ import Button from "components/ads/Button"; import { getDatasource, getPlugin } from "selectors/entitiesSelector"; import { Colors } from "constants/Colors"; import { HeaderIcons } from "icons/HeaderIcons"; -import history from "utils/history"; import styled from "styled-components"; import { createActionRequest } from "actions/actionActions"; -import { INTEGRATION_EDITOR_URL, INTEGRATION_TABS } from "constants/routes"; -import { createNewApiName, createNewQueryName } from "utils/AppsmithUtils"; +import { createNewQueryName } from "utils/AppsmithUtils"; import { getCurrentPageId } from "selectors/editorSelectors"; -import { DEFAULT_API_ACTION_CONFIG } from "constants/ApiEditorConstants"; -import { ApiActionConfig, PluginType, QueryAction } from "entities/Action"; +import { ApiActionConfig, Action } from "entities/Action"; import { renderDatasourceSection } from "./DatasourceSection"; -import { Toaster } from "components/ads/Toast"; -import { Variant } from "components/ads/common"; import { OnboardingStep } from "constants/OnboardingConstants"; import { inOnboarding } from "sagas/OnboardingSagas"; import OnboardingIndicator from "components/editorComponents/Onboarding/Indicator"; -import { createMessage, ERROR_ADD_API_INVALID_URL } from "constants/messages"; +import { Toaster } from "components/ads/Toast"; +import { Variant } from "components/ads/common"; +import { ERROR_ADD_API_INVALID_URL } from "constants/messages"; +import { DEFAULT_API_ACTION_CONFIG } from "constants/ApiEditorConstants"; const ConnectedText = styled.div` color: ${Colors.OXFORD_BLUE}; @@ -75,13 +73,32 @@ function Connected() { const datasourceFormConfigs = useSelector( (state: AppState) => state.entities.plugins.formConfigs, ); + const plugin = useSelector((state: AppState) => getPlugin(state, datasource?.pluginId ?? ""), ); - const isDBDatasource = plugin?.type === PluginType.DB; const createQueryAction = useCallback(() => { const newQueryName = createNewQueryName(actions, currentPageId || ""); + + if ( + plugin?.type === "API" && + (!datasource || + !datasource.datasourceConfiguration || + !datasource.datasourceConfiguration.url) + ) { + Toaster.show({ + text: ERROR_ADD_API_INVALID_URL(), + variant: Variant.danger, + }); + return; + } + + const headers = datasource?.datasourceConfiguration?.headers ?? []; + const defaultApiActionConfig: ApiActionConfig = { + ...DEFAULT_API_ACTION_CONFIG, + headers: headers.length ? headers : DEFAULT_API_ACTION_CONFIG.headers, + }; let payload = { name: newQueryName, pageId: currentPageId, @@ -89,12 +106,13 @@ function Connected() { datasource: { id: datasource?.id, }, - actionConfiguration: {}, + actionConfiguration: plugin?.type === "API" ? defaultApiActionConfig : {}, eventData: { actionType: "Query", from: "datasource-pane", }, - } as Partial; // TODO: refactor later. Handle case for undefined datasource before we reach here. + } as Partial; + if (datasource) if (isInOnboarding) { // If in onboarding and tooltip is being shown @@ -108,55 +126,8 @@ function Connected() { } dispatch(createActionRequest(payload)); - history.push( - INTEGRATION_EDITOR_URL( - params.applicationId, - currentPageId, - INTEGRATION_TABS.ACTIVE, - ), - ); }, [dispatch, actions, currentPageId, params.applicationId, datasource]); - const createApiAction = useCallback(() => { - const newApiName = createNewApiName(actions, currentPageId || ""); - const headers = datasource?.datasourceConfiguration?.headers ?? []; - const defaultApiActionConfig: ApiActionConfig = { - ...DEFAULT_API_ACTION_CONFIG, - headers: headers.length ? headers : DEFAULT_API_ACTION_CONFIG.headers, - }; - - if (!datasource?.datasourceConfiguration?.url) { - Toaster.show({ - text: createMessage(ERROR_ADD_API_INVALID_URL), - variant: Variant.danger, - }); - - return; - } - - dispatch( - createActionRequest({ - name: newApiName, - pageId: currentPageId, - pluginId: datasource.pluginId, - datasource: { - id: datasource.id, - }, - eventData: { - actionType: "API", - from: "datasource-pane", - }, - actionConfiguration: defaultApiActionConfig, - }), - ); - history.push( - INTEGRATION_EDITOR_URL( - params.applicationId, - currentPageId, - INTEGRATION_TABS.NEW, - ), - ); - }, [dispatch, actions, currentPageId, params.applicationId, datasource]); const currentFormConfig: Array = datasourceFormConfigs[datasource?.pluginId ?? ""]; @@ -177,8 +148,8 @@ function Connected() { diff --git a/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx b/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx index 4d845758d0..f8e87121cb 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx @@ -281,6 +281,7 @@ class DatasourceRestAPIEditor extends React.Component { text: "Unable to create API. Try adding a url to the datasource", variant: Variant.danger, }); + return; } const newApiName = createNewApiName(actions, pageId || ""); diff --git a/app/client/src/pages/Editor/Explorer/Actions/ActionsGroup.tsx b/app/client/src/pages/Editor/Explorer/Actions/ActionsGroup.tsx index aeb2c439a3..85371dc187 100644 --- a/app/client/src/pages/Editor/Explorer/Actions/ActionsGroup.tsx +++ b/app/client/src/pages/Editor/Explorer/Actions/ActionsGroup.tsx @@ -30,7 +30,9 @@ export const ExplorerActionsGroup = memo((props: ExplorerActionsGroupProps) => { const icon = props.config?.getIcon( action.config, - props.plugins[action.config.datasource.pluginId], + props.plugins[ + action.config.pluginId || action.config.datasource.pluginId + ], ); return ( & { eventData: any }) => void; + createAction: (data: Partial & { eventData: any }) => void; actions: ActionDataState; isCreating: boolean; location: { @@ -67,11 +64,30 @@ type ActiveDataSourceProps = { }; class ActiveDataSources extends React.Component { - handleCreateNewQuery = (dataSource: Datasource) => { + handleCreateNewQuery = (dataSource: Datasource, pluginType: PluginType) => { const { actions, pageId } = this.props; + + if ( + pluginType === "API" && + (!dataSource || + !dataSource.datasourceConfiguration || + !dataSource.datasourceConfiguration.url) + ) { + Toaster.show({ + text: "Unable to create API. Try adding a url to the datasource", + variant: Variant.danger, + }); + return; + } if (pageId) { const newQueryName = createNewQueryName(actions, pageId); + const headers = dataSource?.datasourceConfiguration?.headers ?? []; + const defaultApiActionConfig: ApiActionConfig = { + ...DEFAULT_API_ACTION_CONFIG, + headers: headers.length ? headers : DEFAULT_API_ACTION_CONFIG.headers, + }; + this.props.createAction({ name: newQueryName, pageId, @@ -84,7 +100,7 @@ class ActiveDataSources extends React.Component { dataSource: dataSource.name, }, pluginId: dataSource.pluginId, - actionConfiguration: {}, + actionConfiguration: pluginType === "API" ? defaultApiActionConfig : {}, }); } }; @@ -92,13 +108,13 @@ class ActiveDataSources extends React.Component { render() { const { dataSources, isCreating } = this.props; - if (isCreating) { - return ( - - - - ); - } + // if (isCreating) { + // return ( + // + // + // + // ); + // } if (dataSources.length === 0) { return ( @@ -123,6 +139,7 @@ class ActiveDataSources extends React.Component { return ( @@ -138,7 +155,7 @@ const mapStateToProps = (state: AppState) => ({ }); const mapDispatchToProps = (dispatch: any) => ({ - createAction: (data: Partial & { eventData: any }) => { + createAction: (data: Partial & { eventData: any }) => { dispatch(createActionRequest(data)); }, }); diff --git a/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx b/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx index 4455f86a2f..36fc8f9a68 100644 --- a/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx +++ b/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx @@ -1,7 +1,7 @@ import { Datasource } from "entities/Datasource"; import { isStoredDatasource, PluginType } from "entities/Action"; import Button, { Category } from "components/ads/Button"; -import React, { useMemo } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import { isNil, keyBy } from "lodash"; import { useDispatch, useSelector } from "react-redux"; import { Colors } from "constants/Colors"; @@ -94,14 +94,16 @@ const ButtonsWrapper = styled.div` type DatasourceCardProps = { datasource: Datasource; - onCreateQuery: (datasource: Datasource) => void; + onCreateQuery: (datasource: Datasource, pluginType: PluginType) => void; + isCreating?: boolean; }; function DatasourceCard(props: DatasourceCardProps) { const dispatch = useDispatch(); + const [isSelected, setIsSelected] = useState(false); const pluginImages = useSelector(getPluginImages); const params = useParams<{ applicationId: string; pageId: string }>(); - const { datasource } = props; + const { datasource, isCreating } = props; const datasourceFormConfigs = useSelector( (state: AppState) => state.entities.plugins.formConfigs, ); @@ -119,7 +121,7 @@ function DatasourceCard(props: DatasourceCardProps) { return state.entities.plugins.list; }); const pluginGroups = useMemo(() => keyBy(plugins, "id"), [plugins]); - const editDatasource = () => { + const editDatasource = useCallback(() => { const plugin = pluginGroups[datasource.pluginId]; if (plugin && plugin.type === PluginType.SAAS) { history.push( @@ -146,7 +148,13 @@ function DatasourceCard(props: DatasourceCardProps) { ), ); } - }; + }, [datasource.id, params]); + + const onCreateNewQuery = useCallback(() => { + setIsSelected(true); + const plugin = pluginGroups[datasource.pluginId]; + props.onCreateQuery(datasource, plugin.type); + }, []); return ( @@ -176,7 +184,8 @@ function DatasourceCard(props: DatasourceCardProps) { props.onCreateQuery(datasource)} + isLoading={isCreating && isSelected} + onClick={onCreateNewQuery} text="New Query" /> diff --git a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx index 831f729190..678d716728 100644 --- a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx +++ b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @@ -19,7 +19,7 @@ import { redirectAuthorizationCode, updateDatasource, } from "actions/datasourceActions"; -import { createNewApiName } from "utils/AppsmithUtils"; +import { createNewQueryName } from "utils/AppsmithUtils"; import { createActionRequest } from "actions/actionActions"; import { ActionDataState } from "reducers/entityReducers/actionsReducer"; import { @@ -38,7 +38,7 @@ import { } from "constants/messages"; import { Variant } from "components/ads/common"; import { Toaster } from "components/ads/Toast"; -import { PluginType, SaaSAction } from "entities/Action"; +import { Action, PluginType } from "entities/Action"; import AnalyticsUtil from "utils/AnalyticsUtil"; import Connected from "../DataSourceEditor/Connected"; import { Colors } from "constants/Colors"; @@ -58,7 +58,7 @@ interface DispatchFunctions { updateDatasource: (formData: any, onSuccess?: ReduxAction) => void; deleteDatasource: (id: string, onSuccess?: ReduxAction) => void; getOAuthAccessToken: (id: string) => void; - createAction: (data: Partial) => void; + createAction: (data: Partial) => void; } type DatasourceSaaSEditorProps = StateProps & @@ -90,6 +90,18 @@ const EditDatasourceButton = styled(AdsButton)` } `; +const NewQueryBtn = styled(AdsButton)` + padding: 10px 20px; + &&&& { + height: 36px; + //max-width: 120px; + width: auto; + } + span > svg > path { + stroke: white; + } +`; + class DatasourceSaaSEditor extends JSONtoForm { componentDidMount() { super.componentDidMount(); @@ -122,34 +134,39 @@ class DatasourceSaaSEditor extends JSONtoForm { this.props.updateDatasource(normalizedValues, onSuccess); }; - createApiAction = () => { - const { - actions, - formData, - match: { - params: { pageId }, - }, - } = this.props; - const newApiName = createNewApiName(actions, pageId || ""); - - this.save( - createActionRequest({ - name: newApiName, - pageId: pageId, - pluginId: formData.pluginId, - datasource: { - id: formData.id, - }, - }), - ); - }; - render() { const { formConfig } = this.props; const content = this.renderDataSourceConfigForm(formConfig); return this.renderForm(content); } + createQueryAction = () => { + const { + actions, + datasource, + match: { + params: { pageId }, + }, + } = this.props; + const newQueryName = createNewQueryName(actions, pageId || ""); + + const payload = { + name: newQueryName, + pageId: pageId, + pluginId: datasource?.pluginId, + datasource: { + id: datasource?.id, + }, + actionConfiguration: {}, + eventData: { + actionType: "Query", + from: "datasource-pane", + }, + } as Partial; + + this.props.createAction(payload); + }; + renderDataSourceConfigForm = (sections: any) => { const { deleteDatasource, @@ -173,7 +190,7 @@ class DatasourceSaaSEditor extends JSONtoForm { - {viewMode && ( + {viewMode ? ( { }} text="EDIT" /> + ) : ( + )} {!viewMode ? ( @@ -277,7 +301,7 @@ const mapDispatchToProps = (dispatch: any): DispatchFunctions => { dispatch(updateDatasource(formData, onSuccess)), getOAuthAccessToken: (datasourceId: string) => dispatch(getOAuthAccessToken(datasourceId)), - createAction: (data: Partial) => { + createAction: (data: Partial) => { dispatch(createActionRequest(data)); }, };