diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index c66f5498df..f39ad4d368 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -1571,8 +1571,7 @@ export const RECONNECT_BUTTON_TEXT = () => "RECONNECT"; export const SAVE_BUTTON_TEXT = () => "SAVE"; export const SAVE_AND_AUTHORIZE_BUTTON_TEXT = () => "SAVE AND AUTHORIZE"; export const DISCARD_POPUP_DONT_SAVE_BUTTON_TEXT = () => "DON'T SAVE"; -export const GSHEET_AUTHORISED_FILE_IDS_KEY = () => - "Google sheets authorised file ids key"; +export const GSHEET_AUTHORISED_FILE_IDS_KEY = () => "userAuthorizedSheetIds"; export const GOOGLE_SHEETS_INFO_BANNER_MESSAGE = () => "Appsmith will require access to your google drive to access google sheets."; export const GOOGLE_SHEETS_AUTHORIZE_DATASOURCE = () => "Authorize Datasource"; diff --git a/app/client/src/components/formControls/BaseControl.tsx b/app/client/src/components/formControls/BaseControl.tsx index b312ace0c5..84c97f6a6f 100644 --- a/app/client/src/components/formControls/BaseControl.tsx +++ b/app/client/src/components/formControls/BaseControl.tsx @@ -20,7 +20,12 @@ export type ComparisonOperations = | "GREATER" | "IN" | "NOT_IN" - | "FEATURE_FLAG"; + | "FEATURE_FLAG" + | "VIEW_MODE"; + +export enum ComparisonOperationsEnum { + VIEW_MODE = "VIEW_MODE", +} export type HiddenType = boolean | Condition | ConditionObject; diff --git a/app/client/src/components/formControls/utils.ts b/app/client/src/components/formControls/utils.ts index 3be307ffda..3f53d3d7b7 100644 --- a/app/client/src/components/formControls/utils.ts +++ b/app/client/src/components/formControls/utils.ts @@ -65,6 +65,7 @@ export const caculateIsHidden = ( values: any, hiddenConfig?: HiddenType, featureFlags?: FeatureFlags, + viewMode?: boolean, ) => { if (!!hiddenConfig && !isBoolean(hiddenConfig)) { let valueAtPath; @@ -102,6 +103,9 @@ export const caculateIsHidden = ( // and show new configs if feature flag is enabled, if disabled/ not present, // previous config would be shown as is return !!featureFlags && featureFlags[flagValue] === value; + case "VIEW_MODE": + // This can be used to decide which form controls to show in view mode or edit mode depending on the value. + return viewMode === value; default: return true; } @@ -112,13 +116,14 @@ export const isHidden = ( values: any, hiddenConfig?: HiddenType, featureFlags?: FeatureFlags, + viewMode?: boolean, ) => { if (!!hiddenConfig && !isBoolean(hiddenConfig)) { if ("conditionType" in hiddenConfig) { //check if nested conditions exist return isHiddenConditionsEvaluation(values, hiddenConfig); } else { - return caculateIsHidden(values, hiddenConfig, featureFlags); + return caculateIsHidden(values, hiddenConfig, featureFlags, viewMode); } } return !!hiddenConfig; diff --git a/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx b/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx index 0ca2aad3f3..afea324991 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/Connected.tsx @@ -2,12 +2,10 @@ import React from "react"; import { useSelector } from "react-redux"; import { useParams } from "react-router"; import type { AppState } from "@appsmith/reducers"; -import { isNil } from "lodash"; import { getDatasource, getPlugin } from "selectors/entitiesSelector"; import { Colors } from "constants/Colors"; import { HeaderIcons } from "icons/HeaderIcons"; import styled from "styled-components"; -import RenderDatasourceInformation from "./DatasourceSection"; import NewActionButton from "./NewActionButton"; import { hasCreateDatasourceActionPermission } from "@appsmith/utils/permissionHelpers"; @@ -28,16 +26,8 @@ const Header = styled.div` justify-content: space-between; `; -const Wrapper = styled.div` - display: flex; - flex-direction: column; - border-bottom: 1px solid #d0d7dd; - padding: 24px 20px; -`; - function Connected({ errorComponent, - hideDatasourceRenderSection = false, showDatasourceSavedText = true, }: { errorComponent?: JSX.Element | null; @@ -50,10 +40,6 @@ function Connected({ getDatasource(state, params.datasourceId), ); - const datasourceFormConfigs = useSelector( - (state: AppState) => state.entities.plugins.formConfigs, - ); - const plugin = useSelector((state: AppState) => getPlugin(state, datasource?.pluginId ?? ""), ); @@ -67,11 +53,8 @@ function Connected({ ...pagePermissions, ]); - const currentFormConfig: Array = - datasourceFormConfigs[datasource?.pluginId ?? ""]; - return ( - + <> {showDatasourceSavedText && (
@@ -91,17 +74,7 @@ function Connected({
)} {errorComponent} -
- {!isNil(currentFormConfig) && - !isNil(datasource) && - !hideDatasourceRenderSection ? ( - - ) : undefined} -
-
+ ); } diff --git a/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx b/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx index 659cfe756b..8e18a7a191 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx @@ -34,6 +34,7 @@ import Debugger, { } from "./Debugger"; import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; import { showDebuggerFlag } from "selectors/debuggerSelectors"; +import DatasourceInformation from "./DatasourceSection"; import { DocsLink, openDoc } from "../../../constants/DocumentationLinks"; const { cloudHosting } = getAppsmithConfigs(); @@ -86,6 +87,13 @@ export const Form = styled.form` flex: 1; `; +const ViewModeWrapper = styled.div` + display: flex; + flex-direction: column; + border-bottom: 1px solid #d0d7dd; + padding: 24px 20px; +`; + class DatasourceDBEditor extends JSONtoForm { componentDidUpdate(prevProps: Props) { if (prevProps.datasourceId !== this.props.datasourceId) { @@ -125,6 +133,7 @@ class DatasourceDBEditor extends JSONtoForm { datasourceButtonConfiguration, datasourceDeleteTrigger, datasourceId, + formConfig, formData, messages, pluginType, @@ -200,7 +209,20 @@ class DatasourceDBEditor extends JSONtoForm { {""} )} - {viewMode && } + {viewMode && ( + + +
+ {!_.isNil(formConfig) && !_.isNil(datasource) ? ( + + ) : undefined} +
+
+ )} {/* Render datasource form call-to-actions */} {datasource && ( { renderKVArray = (children: Array) => { try { @@ -85,11 +87,12 @@ export default class RenderDatasourceInformation extends React.Component<{ }; renderDatasourceSection(section: any) { - const { datasource } = this.props; + const { datasource, viewMode } = this.props; return ( {map(section.children, (section) => { - if (isHidden(datasource, section.hidden)) return null; + if (isHidden(datasource, section.hidden, undefined, viewMode)) + return null; if ("children" in section) { if (isKVArray(section.children)) { return this.renderKVArray(section.children); @@ -123,6 +126,15 @@ export default class RenderDatasourceInformation extends React.Component<{ } } + if ( + !value && + !!viewMode && + "comparison" in section.hidden && + section.hidden.comparison === ComparisonOperationsEnum.VIEW_MODE + ) { + value = section.initialValue; + } + if (!value || (isArray(value) && value.length < 1)) { return; } diff --git a/app/client/src/pages/Editor/DataSourceEditor/JSONtoForm.tsx b/app/client/src/pages/Editor/DataSourceEditor/JSONtoForm.tsx index 60124d7d74..fd4e35d374 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/JSONtoForm.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/JSONtoForm.tsx @@ -246,7 +246,14 @@ export class JSONtoForm< // hides features/configs that are hidden behind feature flag // TODO: remove hidden config property as well as this param, // when feature flag is removed - if (isHidden(this.props.formData, section.hidden, this.props?.featureFlags)) + if ( + isHidden( + this.props.formData, + section.hidden, + this.props?.featureFlags, + false, // viewMode is false here. + ) + ) return null; return ( { return section.children.map( (formControlOrSection: ControlProps, idx: number) => { - if (isHidden(props.formData, section.hidden)) return null; + if (isHidden(props.formData, section.hidden, undefined, false)) + return null; if (formControlOrSection.hasOwnProperty("children")) { return renderEachConfig(formName)(formControlOrSection); } else { diff --git a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx index 12b6a35a85..bc8d8b10f3 100644 --- a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx +++ b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @@ -29,7 +29,6 @@ import { } from "../DataSourceEditor/JSONtoForm"; import { getConfigInitialValues } from "components/formControls/utils"; import Connected from "../DataSourceEditor/Connected"; - import { getCurrentApplicationId, getGsheetProjectID, @@ -71,6 +70,8 @@ import { getDatasourceErrorMessage } from "./errorUtils"; import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; import { DocumentationLink } from "../QueryEditor/EditorJSONtoForm"; import GoogleSheetFilePicker from "./GoogleSheetFilePicker"; +import DatasourceInformation from "./../DataSourceEditor/DatasourceSection"; +import styled from "styled-components"; interface StateProps extends JSONtoFormProps { applicationId: string; @@ -133,6 +134,13 @@ type State = { navigation(): void; }; +const ViewModeWrapper = styled.div` + display: flex; + flex-direction: column; + border-bottom: 1px solid #d0d7dd; + padding: 24px 20px; +`; + class DatasourceSaaSEditor extends JSONtoForm { constructor(props: Props) { super(props); @@ -272,6 +280,7 @@ class DatasourceSaaSEditor extends JSONtoForm { datasourceId, documentationLink, featureFlags, + formConfig, formData, gsheetProjectID, gsheetToken, @@ -410,20 +419,32 @@ class DatasourceSaaSEditor extends JSONtoForm { )} {viewMode && ( - + + ) : null + } + showDatasourceSavedText={!isGoogleSheetPlugin} + /> +
+ {!_.isNil(formConfig) && + !_.isNil(datasource) && + !hideDatasourceSection ? ( + - ) : null - } - hideDatasourceRenderSection={hideDatasourceSection} - showDatasourceSavedText={!isGoogleSheetPlugin} - /> + ) : undefined} +
+ )} {/* Render datasource form call-to-actions */} {datasource && ( diff --git a/app/client/src/sagas/DatasourcesSagas.ts b/app/client/src/sagas/DatasourcesSagas.ts index 40726d386b..99a4e177a5 100644 --- a/app/client/src/sagas/DatasourcesSagas.ts +++ b/app/client/src/sagas/DatasourcesSagas.ts @@ -1213,7 +1213,8 @@ function* filePickerActionCallbackSaga( // Once users selects/cancels the file selection, // Sending sheet ids selected as part of datasource // config properties in order to save it in database - set(datasource, "datasourceConfiguration.properties[0]", { + // using the second index specifically for file ids. + set(datasource, "datasourceConfiguration.properties[1]", { key: createMessage(GSHEET_AUTHORISED_FILE_IDS_KEY), value: fileIds, }); diff --git a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/utils/SheetsUtil.java b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/utils/SheetsUtil.java index 30ca8d94f8..cae59d4c7f 100644 --- a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/utils/SheetsUtil.java +++ b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/utils/SheetsUtil.java @@ -15,6 +15,7 @@ import com.appsmith.external.models.DatasourceConfiguration; public class SheetsUtil { private static final String FILE_SPECIFIC_DRIVE_SCOPE = "https://www.googleapis.com/auth/drive.file"; + private static final int USER_AUTHORIZED_SHEET_IDS_INDEX = 1; static Pattern COLUMN_NAME_PATTERN = Pattern.compile("[a-zA-Z]+"); public static int getColumnNumber(String columnName) { @@ -33,11 +34,11 @@ public class SheetsUtil { public static Set getUserAuthorizedSheetIds(DatasourceConfiguration datasourceConfiguration) { OAuth2 oAuth2 = (OAuth2) datasourceConfiguration.getAuthentication(); if (!isEmpty(datasourceConfiguration.getProperties()) - && datasourceConfiguration.getProperties().get(0) != null - && datasourceConfiguration.getProperties().get(0).getValue() != null + && datasourceConfiguration.getProperties().get(USER_AUTHORIZED_SHEET_IDS_INDEX) != null + && datasourceConfiguration.getProperties().get(USER_AUTHORIZED_SHEET_IDS_INDEX).getValue() != null && oAuth2.getScope() != null && oAuth2.getScope().contains(FILE_SPECIFIC_DRIVE_SCOPE)) { - ArrayList temp = (ArrayList) datasourceConfiguration.getProperties().get(0).getValue(); + ArrayList temp = (ArrayList) datasourceConfiguration.getProperties().get(USER_AUTHORIZED_SHEET_IDS_INDEX).getValue(); return new HashSet(temp); } return null; diff --git a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json index 96e279ace1..5fe2a428cb 100644 --- a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json +++ b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json @@ -72,6 +72,17 @@ "hidden": true, "initialValue": "authorization_code" }, + { + "label": "Account", + "configProperty": "datasourceConfiguration.properties[0].value", + "controlType": "INPUT_TEXT", + "isRequired": false, + "hidden": { + "comparison": "VIEW_MODE", + "value": false + }, + "initialValue": "Authorize datasource to fetch account name" + }, { "label": "Permissions | Scope", "configProperty": "datasourceConfiguration.authentication.scopeString",