diff --git a/app/client/cypress/support/commands.js b/app/client/cypress/support/commands.js index 48092fe5fcff..748a66f601ad 100644 --- a/app/client/cypress/support/commands.js +++ b/app/client/cypress/support/commands.js @@ -936,7 +936,6 @@ Cypress.Commands.add("CreationOfUniqueAPIcheck", (apiname) => { .type(apiname, { force: true, delay: 500 }) .should("have.value", apiname); cy.get(".error-message").should(($x) => { - console.log($x); expect($x).contain(apiname.concat(" is already being used.")); }); cy.get(apiwidget.apiTxt).blur(); @@ -1022,14 +1021,12 @@ Cypress.Commands.add("CreateApiAndValidateUniqueEntityName", (apiname) => { .type(apiname, { force: true }) .should("have.value", apiname); cy.get(".t--nameOfApi .error-message").should(($x) => { - console.log($x); expect($x).contain(apiname.concat(" is already being used.")); }); }); Cypress.Commands.add("validateMessage", (value) => { cy.get(".bp3-popover-content").should(($x) => { - console.log($x); expect($x).contain(value.concat(" is already being used.")); }); }); diff --git a/app/client/src/actions/datasourceActions.ts b/app/client/src/actions/datasourceActions.ts index 612693496a4e..85d63beb2146 100644 --- a/app/client/src/actions/datasourceActions.ts +++ b/app/client/src/actions/datasourceActions.ts @@ -208,7 +208,7 @@ export type executeDatasourceQuerySuccessPayload = { isExecutionSuccess: boolean; }; }; -type errorPayload = unknown; +type errorPayload = string; export type executeDatasourceQueryReduxAction = ReduxActionWithCallbacks< executeDatasourceQueryRequest, diff --git a/app/client/src/actions/pageActions.tsx b/app/client/src/actions/pageActions.tsx index bac1de361d54..bdd0b56dc208 100644 --- a/app/client/src/actions/pageActions.tsx +++ b/app/client/src/actions/pageActions.tsx @@ -353,6 +353,7 @@ export const generateTemplateToUpdatePage = ({ datasourceId, mode, pageId, + pluginSpecificParams, searchColumn, tableName, }: GenerateTemplatePageRequest): ReduxActionWithExtraParams => { @@ -365,6 +366,7 @@ export const generateTemplateToUpdatePage = ({ applicationId, columns, searchColumn, + pluginSpecificParams, }, extraParams: { mode, diff --git a/app/client/src/api/PageApi.tsx b/app/client/src/api/PageApi.tsx index b6fa34c78f84..cb143d75c10d 100644 --- a/app/client/src/api/PageApi.tsx +++ b/app/client/src/api/PageApi.tsx @@ -122,6 +122,7 @@ export interface GenerateTemplatePageRequest { columns?: string[]; searchColumn?: string; mode?: string; + pluginSpecificParams?: Record; } export type GenerateTemplatePageRequestResponse = ApiResponse & { diff --git a/app/client/src/components/ads/Dropdown.tsx b/app/client/src/components/ads/Dropdown.tsx index 9a81086a535b..1b882a8737c7 100644 --- a/app/client/src/components/ads/Dropdown.tsx +++ b/app/client/src/components/ads/Dropdown.tsx @@ -81,9 +81,8 @@ export interface RenderDropdownOptionType { optionClickHandler?: (dropdownOption: DropdownOption) => void; } -export const DropdownContainer = styled.div<{ width: string; height: string }>` +export const DropdownContainer = styled.div<{ width: string }>` width: ${(props) => props.width}; - height: ${(props) => props.height}; position: relative; `; @@ -113,6 +112,7 @@ const Selected = styled.div<{ height: string; bgColor?: string; hasError?: boolean; + isLoading?: boolean; }>` padding: ${(props) => props.theme.spaces[2]}px ${(props) => props.theme.spaces[3]}px; @@ -132,7 +132,8 @@ const Selected = styled.div<{ justify-content: space-between; width: 100%; height: ${(props) => props.height}; - cursor: pointer; + cursor: ${(props) => + props.disabled || props.isLoading ? "not-allowed" : "pointer"}; ${(props) => props.isOpen ? `border: 1px solid ${ @@ -310,7 +311,7 @@ const SelectedIcon = styled(Icon)` const ErrorMsg = styled.span` ${(props) => getTypographyByKey(props, "p3")}; color: ${Colors.POMEGRANATE2}; - margin-top: 8px; + margin-top: ${(props) => props.theme.spaces[3]}px; `; const ErrorLabel = styled.span` @@ -321,7 +322,7 @@ const ErrorLabel = styled.span` const HelperText = styled.span` ${(props) => getTypographyByKey(props, "p3")}; color: ${Colors.GRAY}; - margin-top: 8px; + margin-top: ${(props) => props.theme.spaces[3]}px; `; function DefaultDropDownValueNode({ @@ -491,12 +492,20 @@ export default function Dropdown(props: DropdownProps) { const disabled = props.disabled || isLoading || !!errorMsg; const downIconColor = errorMsg ? Colors.POMEGRANATE2 : Colors.DARK_GRAY; + const dropdownHeight = props.height ? props.height : "38px"; + + const onClickHandler = () => { + if (!props.disabled) { + setIsOpen(!isOpen); + } + }; + const dropdownTrigger = props.dropdownTriggerIcon ? ( setIsOpen(!isOpen)} + onClick={onClickHandler} > {props.dropdownTriggerIcon} @@ -507,9 +516,10 @@ export default function Dropdown(props: DropdownProps) { className={props.className} disabled={props.disabled} hasError={!!errorMsg} - height={props.height || "38px"} + height={dropdownHeight} + isLoading={isLoading} isOpen={isOpen} - onClick={() => setIsOpen(!isOpen)} + onClick={onClickHandler} > @@ -548,7 +557,7 @@ export default function Dropdown(props: DropdownProps) { boundary="scrollParent" isOpen={isOpen && !disabled} minimal - onInteraction={(state) => setIsOpen(state)} + onInteraction={(state) => !disabled && setIsOpen(state)} popoverClassName={props.className} position={Position.BOTTOM_LEFT} > diff --git a/app/client/src/components/ads/TextInput.tsx b/app/client/src/components/ads/TextInput.tsx index 7aa0b1cf5077..bc5060f766e5 100644 --- a/app/client/src/components/ads/TextInput.tsx +++ b/app/client/src/components/ads/TextInput.tsx @@ -41,6 +41,7 @@ export type TextInputProps = CommonComponentProps & { placeholder?: string; fill?: boolean; defaultValue?: string; + value?: string; validator?: (value: string) => { isValid: boolean; message: string }; onChange?: (value: string) => void; readOnly?: boolean; diff --git a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/GeneratePageForm.tsx b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/GeneratePageForm.tsx index 0a07f5af587b..727390968dc7 100644 --- a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/GeneratePageForm.tsx +++ b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/GeneratePageForm.tsx @@ -11,7 +11,6 @@ import { getGenerateCRUDEnabledPluginMap, getIsFetchingSinglePluginForm, getDatasourcesStructure, - getIsExecutingDatasourceQuery, } from "selectors/entitiesSelector"; import { Datasource } from "entities/Datasource"; @@ -30,10 +29,16 @@ import { getIsGeneratingTemplatePage } from "selectors/pageListSelectors"; import DataSourceOption from "../DataSourceOption"; import { convertToQueryParams } from "constants/routes"; import { IconName, IconSize } from "components/ads/Icon"; -import GoogleSheetForm from "../GoogleSheetForm"; +import GoogleSheetForm from "./GoogleSheetForm"; import { GENERATE_PAGE_FORM_TITLE } from "constants/messages"; import { GenerateCRUDEnabledPluginMap } from "api/PluginApi"; -import { useDatasourceOptions, useS3BucketList } from "./hooks"; +import { + useDatasourceOptions, + useSheetsList, + useSpreadSheets, + useSheetColumnHeaders, + useS3BucketList, +} from "./hooks"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { AppState } from "reducers/index"; import { @@ -45,11 +50,28 @@ import { DROPDOWN_DIMENSION, ALLOWED_SEARCH_DATATYPE, } from "../constants"; - +import Tooltip from "components/ads/Tooltip"; import { Bold, Label, SelectWrapper } from "./styles"; +import { GeneratePagePayload } from "./types"; +import Icon from "components/ads/Icon"; // ---------- Styles ---------- +const RoundBg = styled.div` + width: 16px; + height: 16px; + border-radius: 16px; + background-color: ${Colors.GRAY}; + display: flex; + justify-content: center; + align-items: center; +`; + +const TooltipWrapper = styled.div` + margin-top: 2px; + margin-left: 6px; +`; + const Wrapper = styled.div` display: flex; flex-direction: column; @@ -90,15 +112,49 @@ const Title = styled.p` font-size: 24px; `; +const Row = styled.p` + display: flex; + flex-direction: row; + justify-content: flex-start; +`; + // Constants const datasourceIcon: IconName = "tables"; +const columnIcon: IconName = "column"; const GENERATE_PAGE_MODE = { NEW: "NEW", // a new page is created for the template. (new pageId created) REPLACE_EMPTY: "REPLACE_EMPTY", // current page's content (DSL) is updated to template DSL. (same pageId) }; +// + +function GeneratePageSubmitBtn({ + disabled, + isLoading, + onSubmit, + showSubmitButton, +}: { + onSubmit: () => void; + isLoading: boolean; + showSubmitButton: boolean; + disabled: boolean; +}) { + return showSubmitButton ? ( + + ) : null; +} + // ---------- GeneratePageForm Component ---------- function GeneratePageForm() { @@ -159,8 +215,6 @@ function GeneratePageForm() { return false; }); - const isExecutingDatasourceQuery = useSelector(getIsExecutingDatasourceQuery); - const [selectedTable, selectTable] = useState( DEFAULT_DROPDOWN_OPTION, ); @@ -201,16 +255,18 @@ function GeneratePageForm() { setSelectedTableColumnOptions([]); selectTable(DEFAULT_DROPDOWN_OPTION); selectColumn(DEFAULT_DROPDOWN_OPTION); - - switch (pluginPackageName) { - case PLUGIN_PACKAGE_NAME.S3: - fetchBucketList({ selectedDatasource: dataSourceObj }); - break; - case PLUGIN_PACKAGE_NAME.GOOGLE_SHEETS: - break; - default: { - if (dataSourceObj.id) { - dispatch(fetchDatasourceStructure(dataSourceObj.id, true)); + setSelectedDatasourceIsInvalid(false); + if (dataSourceObj.id) { + switch (pluginPackageName) { + case PLUGIN_PACKAGE_NAME.S3: + fetchBucketList({ selectedDatasource: dataSourceObj }); + break; + case PLUGIN_PACKAGE_NAME.GOOGLE_SHEETS: + break; + default: { + if (dataSourceObj.id) { + dispatch(fetchDatasourceStructure(dataSourceObj.id, true)); + } } } } @@ -224,6 +280,8 @@ function GeneratePageForm() { selectTable, selectColumn, dispatch, + setSelectedDatasourceIsInvalid, + selectedDatasource, generateCRUDSupportedPlugin, ], ); @@ -236,8 +294,8 @@ function GeneratePageForm() { selectColumn(DEFAULT_DROPDOWN_OPTION); if (!isGoogleSheetPlugin && !isS3Plugin) { const { data } = TableObj; - const columnIcon: IconName = "column"; - if (data.columns && Array.isArray(data.columns)) { + + if (Array.isArray(data.columns)) { const newSelectedTableColumnOptions: DropdownOption[] = []; data.columns.map((column) => { if ( @@ -288,6 +346,15 @@ function GeneratePageForm() { generateCRUDSupportedPlugin, }); + const spreadSheetsProps = useSpreadSheets({ + setSelectedDatasourceTableOptions, + setSelectedDatasourceIsInvalid, + }); + + const sheetsListProps = useSheetsList(); + + const sheetColumnsHeaderProps = useSheetColumnHeaders(); + useEffect(() => { if (isS3Plugin && bucketList && bucketList.length) { const tables = bucketList.map((bucketName) => ({ @@ -300,7 +367,7 @@ function GeneratePageForm() { })); setSelectedDatasourceTableOptions(tables); } - }, [bucketList, isS3Plugin]); + }, [bucketList, isS3Plugin, setSelectedDatasourceTableOptions]); useEffect(() => { if ( @@ -359,7 +426,12 @@ function GeneratePageForm() { } } } - }, [dataSourceOptions, datasourceIdToBeSelected, onSelectDataSource]); + }, [ + dataSourceOptions, + datasourceIdToBeSelected, + onSelectDataSource, + setDatasourceIdToBeSelected, + ]); useEffect(() => { if (querySearch) { @@ -380,7 +452,7 @@ function GeneratePageForm() { history.replace(redirectURL); } } - }, [querySearch]); + }, [querySearch, setDatasourceIdToBeSelected]); const routeToCreateNewDatasource = () => { AnalyticsUtil.logEvent("GEN_CRUD_PAGE_CREATE_NEW_DATASOURCE"); @@ -393,22 +465,39 @@ function GeneratePageForm() { ); }; - const handleFormSubmit = () => { + const generatePageAction = (data: GeneratePagePayload) => { + let extraParams = {}; + if (data.pluginSpecificParams) { + extraParams = { + pluginSpecificParams: data.pluginSpecificParams, + }; + } + + const payload = { + applicationId: currentApplicationId || "", + pageId: + currentMode.current === GENERATE_PAGE_MODE.NEW + ? "" + : currentPageId || "", + columns: data.columns || [], + searchColumn: data.searchColumn, + tableName: data.tableName, + datasourceId: selectedDatasource.id || "", + mode: currentMode.current, + ...extraParams, + }; + AnalyticsUtil.logEvent("GEN_CRUD_PAGE_FORM_SUBMIT"); - dispatch( - generateTemplateToUpdatePage({ - applicationId: currentApplicationId || "", - pageId: - currentMode.current === GENERATE_PAGE_MODE.NEW - ? "" - : currentPageId || "", - columns: [], - searchColumn: selectedColumn.value, - tableName: selectedTable.value || "", - datasourceId: selectedDatasource.id || "", - mode: currentMode.current, - }), - ); + dispatch(generateTemplateToUpdatePage(payload)); + }; + + const handleFormSubmit = () => { + const payload = { + columns: [], + searchColumn: selectedColumn.value, + tableName: selectedTable.value || "", + }; + generatePageAction(payload); }; const goToEditDatasource = () => { @@ -436,15 +525,13 @@ function GeneratePageForm() { PluginFormInputFieldMap[selectedDatasourcePluginPackageName] ? PluginFormInputFieldMap[selectedDatasourcePluginPackageName] : PluginFormInputFieldMap.DEFAULT; - const tableLabel = pluginField.TABLE; - const columnLabel = pluginField.COLUMN; let tableDropdownErrorMsg = ""; const fetchingDatasourceConfigs = isFetchingDatasourceStructure || (isFetchingBucketList && isS3Plugin) || - ((isFetchingSheetPluginForm || isExecutingDatasourceQuery) && + ((isFetchingSheetPluginForm || spreadSheetsProps.isFetchingSpreadsheets) && isGoogleSheetPlugin); const fetchingDatasourceConfigError = @@ -454,7 +541,7 @@ function GeneratePageForm() { if (!fetchingDatasourceConfigs) { if (datasourceTableOptions.length === 0) { - tableDropdownErrorMsg = `Couldn't find any ${tableLabel}, Please select another datasource`; + tableDropdownErrorMsg = `Couldn't find any ${pluginField.TABLE}, Please select another datasource`; } if (fetchingDatasourceConfigError) { tableDropdownErrorMsg = `Failed fetching datasource structure, Please check your datasource configuration`; @@ -462,16 +549,19 @@ function GeneratePageForm() { } const showEditDatasourceBtn = - !fetchingDatasourceConfigs && - fetchingDatasourceConfigError && + !isFetchingDatasourceStructure && + (selectedDatasourceIsInvalid || !isValidDatasourceConfig) && !!selectedDatasource.value; - const showSubmitButton = selectedTable.value && !showEditDatasourceBtn; - - const showSearchableColumnDropdown = + const showSearchableColumn = !!selectedTable.value && PLUGIN_PACKAGE_NAME.S3 !== selectedDatasourcePluginPackageName; + const showSubmitButton = selectedTable.value && !showEditDatasourceBtn; + !fetchingDatasourceConfigs && + fetchingDatasourceConfigError && + !!selectedDatasource.value; + return (
@@ -507,7 +597,8 @@ function GeneratePageForm() { {selectedDatasource.value ? ( )} {!isGoogleSheetPlugin ? ( - showSearchableColumnDropdown && ( - - - - - ) + <> + {showSearchableColumn && ( + + + Select a searchable {pluginField.COLUMN} from +  {selectedTable.label} + + + + + + + + + + + )} + + ) : ( void; + disabled: boolean; + isLoading: boolean; + }) => ( + + )} selectedDatasource={selectedDatasource} selectedSpreadsheet={selectedTable} - setSelectedDatasourceIsInvalid={setSelectedDatasourceIsInvalid} - setSelectedDatasourceTableOptions={ - setSelectedDatasourceTableOptions - } + sheetColumnsHeaderProps={sheetColumnsHeaderProps} + sheetsListProps={sheetsListProps} + spreadSheetsProps={spreadSheetsProps} /> )} - {showSubmitButton ? ( - - ) : null}
); diff --git a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/GoogleSheetForm.tsx b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/GoogleSheetForm.tsx new file mode 100644 index 000000000000..66a3202fd920 --- /dev/null +++ b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/GoogleSheetForm.tsx @@ -0,0 +1,376 @@ +import React, { useState, useEffect, ReactElement, useCallback } from "react"; +import { useSelector, useDispatch } from "react-redux"; +import { getEditorConfig } from "selectors/entitiesSelector"; +import { AppState } from "reducers/index"; +import Dropdown, { DropdownOption } from "components/ads/Dropdown"; +import { fetchPluginFormConfig } from "actions/pluginActions"; +import { DROPDOWN_DIMENSION, DEFAULT_DROPDOWN_OPTION } from "../constants"; +import { SelectWrapper, Label, Bold } from "./styles"; +import TextInput from "components/ads/TextInput"; +import { GeneratePagePayload } from "./types"; +import { getSheetUrl } from "./hooks"; +import Tooltip from "components/ads/Tooltip"; +import styled from "styled-components"; +import { + UseSheetListReturn, + UseSpreadSheetsReturn, + UseSheetColumnHeadersReturn, +} from "./hooks"; +import Icon, { IconSize } from "components/ads/Icon"; +import { Colors } from "constants/Colors"; +import { getTypographyByKey } from "constants/DefaultTheme"; +import { debounce } from "lodash"; +import Text, { TextType, FontWeight } from "components/ads/Text"; + +type Props = { + googleSheetPluginId: string; + selectedDatasource: DropdownOption; + selectedSpreadsheet: DropdownOption; + generatePageAction: (payload: GeneratePagePayload) => void; + renderSubmitButton: ({ + disabled, + isLoading, + onSubmit, + }: { + onSubmit: () => void; + disabled: boolean; + isLoading: boolean; + }) => ReactElement; + sheetsListProps: UseSheetListReturn; + spreadSheetsProps: UseSpreadSheetsReturn; + sheetColumnsHeaderProps: UseSheetColumnHeadersReturn; +}; + +// styles + +const RoundBg = styled.div` + width: 16px; + height: 16px; + border-radius: 16px; + background-color: ${Colors.GRAY}; + display: flex; + justify-content: center; + align-items: center; +`; + +const Row = styled.div` + display: flex; + flex-direction: row; + justify-content: flex-start; +`; + +const ColumnName = styled.span` + ${(props) => `${getTypographyByKey(props, "p3")}`}; + color: ${Colors.GRAY}; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +const ColumnInfoWrapper = styled.div` + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; + padding: 0px 8px; + margin-bottom: 10px; + width: ${DROPDOWN_DIMENSION.WIDTH}; + overflow: hidden; + flex-wrap: wrap; +`; + +const ColumnNameWrapper = styled.div` + display: flex; +`; + +const TooltipWrapper = styled.div` + margin-top: 2px; +`; + +const RowHeading = styled.p` + ${(props) => `${getTypographyByKey(props, "p1")}`}; + margin-right: 10px; +`; + +// As TextInput with dataType as number allows `e` as input, hence adding a number validator +// to check for only whole numbers. +export function isNumberValidator(value: string) { + const isValid = (/^\d+$/.test(value) && Number(value) > 0) || value === ""; + return { + isValid: isValid, + message: !isValid ? "Only numeric value allowed" : "", + }; +} + +// constants + +const MAX_COLUMNS_VISIBLE = 3; + +// ---------- GoogleSheetForm Component ------- + +function GoogleSheetForm(props: Props) { + const { + generatePageAction, + googleSheetPluginId, + renderSubmitButton, + selectedDatasource, + selectedSpreadsheet, + sheetColumnsHeaderProps, + sheetsListProps, + spreadSheetsProps, + } = props; + + const { fetchSheetsList, isFetchingSheetsList, sheetsList } = sheetsListProps; + const { fetchAllSpreadsheets } = spreadSheetsProps; + const { + columnHeaderList, + fetchColumnHeaderList, + isFetchingColumnHeaderList, + } = sheetColumnsHeaderProps; + + const [tableHeaderIndex, setTableHeaderIndex] = useState("1"); + const [selectedSheet, setSelectedSheet] = useState( + DEFAULT_DROPDOWN_OPTION, + ); + const dispatch = useDispatch(); + + const googleSheetEditorConfig = useSelector((state: AppState) => + getEditorConfig(state, googleSheetPluginId), + ); + + const [sheetQueryRequest, setSheetQueryRequest] = useState< + Record + >({}); + + useEffect(() => { + // Check if google sheet editor config is fetched. + // if not, fetch it. + + if (!googleSheetEditorConfig) { + dispatch( + fetchPluginFormConfig({ + pluginId: selectedDatasource.data?.pluginId, + }), + ); + } + }, [googleSheetEditorConfig]); + + useEffect(() => { + if (googleSheetEditorConfig && googleSheetEditorConfig[0]) { + const requestObject: Record = {}; + const configs = googleSheetEditorConfig[0]?.children; + if (Array.isArray(configs)) { + for (let index = 0; index < configs.length; index += 2) { + const keyConfig = configs[index]; + const valueConfig = configs[index + 1]; + if (keyConfig && valueConfig) { + const key = keyConfig?.initialValue; + const value = valueConfig?.initialValue || ""; + if (key) requestObject[key] = value; + } + } + } + setSheetQueryRequest(requestObject); + } + }, [googleSheetEditorConfig]); + + useEffect(() => { + // On change of datasource selection + // if googleSheetEditorConfig if fetched then get all spreadsheets + if ( + selectedDatasource.value && + selectedDatasource.id && + googleSheetEditorConfig + ) { + fetchAllSpreadsheets({ + selectedDatasourceId: selectedDatasource.id, + requestObject: sheetQueryRequest, + }); + } + }, [selectedDatasource.value, googleSheetEditorConfig, dispatch]); + + // When user selects a spreadsheet + // Fetch all sheets inside that spreadsheet + useEffect(() => { + if ( + selectedDatasource.value && + selectedDatasource.id && + selectedSpreadsheet.value && + selectedSpreadsheet.id + ) { + setSelectedSheet(DEFAULT_DROPDOWN_OPTION); + fetchSheetsList({ + requestObject: sheetQueryRequest, + selectedDatasourceId: selectedDatasource.id, + selectedSpreadsheetId: selectedSpreadsheet.id, + }); + } + }, [ + selectedSpreadsheet.id, + selectedSpreadsheet.value, + selectedDatasource.id, + selectedDatasource.value, + dispatch, + fetchSheetsList, + ]); + + const onSelectSheetOption = ( + sheetValue: string | undefined, + sheetObj: DropdownOption | undefined, + ) => { + if (sheetValue && sheetObj) { + setSelectedSheet(sheetObj); + if (selectedDatasource.id && selectedSpreadsheet.id) { + fetchColumnHeaderList({ + selectedDatasourceId: selectedDatasource.id, + selectedSpreadsheetId: selectedSpreadsheet.id, + sheetName: sheetValue, + tableHeaderIndex, + requestObject: sheetQueryRequest, + }); + } + } + }; + + const onSubmit = () => { + if (selectedSpreadsheet.id) { + const columns: string[] = []; + columnHeaderList.forEach(({ value }) => { + if (value) columns.push(value); + }); + const payload = { + columns, + searchColumn: "", + tableName: selectedSheet.value || "", + pluginSpecificParams: { + sheetUrl: getSheetUrl(selectedSpreadsheet.id), + tableHeaderIndex, + sheetName: selectedSheet.value, + }, + }; + generatePageAction(payload); + } + }; + + const debouncedFetchColumns = useCallback( + debounce((value: string) => { + if ( + selectedDatasource.id && + selectedSpreadsheet.id && + selectedSheet.value + ) { + fetchColumnHeaderList({ + selectedDatasourceId: selectedDatasource.id, + selectedSpreadsheetId: selectedSpreadsheet.id, + sheetName: selectedSheet.value, + tableHeaderIndex: value, + requestObject: sheetQueryRequest, + }); + } + }, 200), + [selectedSheet, selectedDatasource, selectedSheet], + ); + + const tableHeaderIndexChangeHandler = (value: string) => { + if (isNumberValidator(value).isValid) { + setTableHeaderIndex(value); + debouncedFetchColumns(value); + } + }; + + return ( + <> + {selectedSpreadsheet.value ? ( + + + + + ) : null} + + {selectedSheet.value ? ( + <> + + + Table Header Index + + + + + + + + + + + + + {columnHeaderList.length ? ( + <> + + Column Headers fetched : {" "} + + {columnHeaderList + .slice(0, MAX_COLUMNS_VISIBLE) + .map((column, index) => ( + + {column.label} + {columnHeaderList.length - 1 === index ? null : ( + + )} + + ))} + {columnHeaderList.length > MAX_COLUMNS_VISIBLE ? ( + + and +{columnHeaderList.length - MAX_COLUMNS_VISIBLE} more. + + ) : ( + "" + )} + + ) : ( + No columns found + )} + + + ) : null} + + {selectedSheet.value && columnHeaderList.length + ? renderSubmitButton({ + onSubmit, + disabled: !columnHeaderList.length || isFetchingColumnHeaderList, + isLoading: isFetchingColumnHeaderList, + }) + : null} + + ); +} + +export default GoogleSheetForm; diff --git a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/hooks.ts b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/hooks.ts index 8c0fc81e932c..e18293f467d6 100644 --- a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/hooks.ts +++ b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/hooks.ts @@ -3,10 +3,13 @@ import { DropdownOptions } from "../constants"; import { Datasource } from "entities/Datasource"; import { GenerateCRUDEnabledPluginMap } from "api/PluginApi"; import { CONNECT_NEW_DATASOURCE_OPTION_ID } from "../DataSourceOption"; -import { useDispatch } from "react-redux"; -import { executeDatasourceQuery } from "actions/datasourceActions"; -import { ResponseMeta } from "api/ApiResponses"; +import { + executeDatasourceQuery, + executeDatasourceQuerySuccessPayload, +} from "actions/datasourceActions"; import { DropdownOption } from "components/ads/Dropdown"; +import { useDispatch } from "react-redux"; +import { isObject } from "lodash"; export const FAKE_DATASOURCE_OPTION = { CONNECT_NEW_DATASOURCE_OPTION: { @@ -64,22 +67,412 @@ export const useDatasourceOptions = ({ return dataSourceOptions; }; +const GOOGLE_SHEET_METHODS = { + GET_ALL_SPREADSHEETS: "LIST", // Get all the spreadsheets + GET_ALL_SHEETS: "INFO", // fetch all the sub-sheets + GET_ALL_COLUMNS: "GET", // Get column names +}; + +const demoRequest: Record = { + method: "", + sheetUrl: "", + range: "", + spreadsheetName: "", + tableHeaderIndex: "1", + queryFormat: "ROWS", + rowLimit: "", + sheetName: "", + rowOffset: "", + rowObject: "", + rowObjects: "", + rowIndex: "", + deleteFormat: "SHEET", +}; + +type FetchAllSpreadSheets = { + selectedDatasourceId: string; + requestObject?: Record; +}; + +export type UseSpreadSheetsReturn = { + fetchAllSpreadsheets: ({ + requestObject, + selectedDatasourceId, + }: FetchAllSpreadSheets) => void; + isFetchingSpreadsheets: boolean; + failedFetchingSpreadsheets: boolean; +}; + +export const useSpreadSheets = ({ + setSelectedDatasourceIsInvalid, + setSelectedDatasourceTableOptions, +}: { + setSelectedDatasourceIsInvalid: (isInvalid: boolean) => void; + setSelectedDatasourceTableOptions: (tableOptions: DropdownOptions) => void; +}): UseSpreadSheetsReturn => { + const dispatch = useDispatch(); + + // const [spreadsheetsList, setSpreadsheets] = useState([]); + + const [isFetchingSpreadsheets, setIsFetchingSpreadsheets] = useState( + false, + ); + const [failedFetchingSpreadsheets, setFailedFetchingSpreadsheets] = useState< + boolean + >(false); + + // TODO :- Create loading state and set Loading state false on success or error + const onFetchAllSpreadsheetFailure = useCallback(() => { + setIsFetchingSpreadsheets(false); + setFailedFetchingSpreadsheets(true); + }, [setIsFetchingSpreadsheets]); + + const onFetchAllSpreadsheetSuccess = useCallback( + ( + payload: executeDatasourceQuerySuccessPayload< + Array<{ id: string; name: string }> + >, + ) => { + setIsFetchingSpreadsheets(false); + + const tableOptions: DropdownOptions = []; + if (payload.data && payload.data.body) { + const spreadSheets = payload.data.body; + + if (Array.isArray(spreadSheets)) { + spreadSheets.map(({ id, name }) => { + tableOptions.push({ + id, + label: name, + value: name, + }); + setSelectedDatasourceTableOptions(tableOptions); + }); + } else { + // to handle error like "401 Unauthorized" + setSelectedDatasourceIsInvalid(true); + } + } + }, + [ + setSelectedDatasourceIsInvalid, + setSelectedDatasourceTableOptions, + setIsFetchingSpreadsheets, + ], + ); + + const fetchAllSpreadsheets = useCallback( + ({ requestObject, selectedDatasourceId }: FetchAllSpreadSheets) => { + setIsFetchingSpreadsheets(true); + setFailedFetchingSpreadsheets(false); + + let requestData = { ...demoRequest }; + if (isObject(requestObject) && Object.keys(requestObject).length) { + requestData = { ...requestObject }; + } + requestData.method = GOOGLE_SHEET_METHODS.GET_ALL_SPREADSHEETS; + const formattedRequestData = Object.entries( + requestData, + ).map(([dataKey, dataValue]) => ({ key: dataKey, value: dataValue })); + dispatch( + executeDatasourceQuery({ + payload: { + datasourceId: selectedDatasourceId, + data: formattedRequestData, + }, + onSuccessCallback: onFetchAllSpreadsheetSuccess, + onErrorCallback: onFetchAllSpreadsheetFailure, + }), + ); + }, + [ + onFetchAllSpreadsheetSuccess, + onFetchAllSpreadsheetFailure, + setIsFetchingSpreadsheets, + setFailedFetchingSpreadsheets, + ], + ); + + return { + fetchAllSpreadsheets, + // spreadsheetsList, + isFetchingSpreadsheets, + failedFetchingSpreadsheets, + }; +}; + +// Types + +export interface GridProperties { + rowCount: number; + columnCount: number; +} + +export interface Sheet { + sheetId: number; + title: string; + index: number; + sheetType: string; + gridProperties: GridProperties; +} + +export type Sheets = Sheet[]; + +export const getSheetUrl = (sheetId: string): string => + `https://docs.google.com/spreadsheets/d/${sheetId}/edit#gid=0`; + +export type FetchSheetsList = { + selectedDatasourceId: string; + selectedSpreadsheetId: string; + requestObject?: Record; +}; + +export type UseSheetListReturn = { + sheetsList: DropdownOption[]; + isFetchingSheetsList: boolean; + failedFetchingSheetsList: boolean; + fetchSheetsList: ({ + requestObject, + selectedDatasourceId, + selectedSpreadsheetId, + }: FetchSheetsList) => void; +}; + +export const useSheetsList = (): UseSheetListReturn => { + const dispatch = useDispatch(); + + const [sheetsList, setSheetsList] = useState([]); + + const [isFetchingSheetsList, setIsFetchingSheetsList] = useState( + false, + ); + const [failedFetchingSheetsList, setFailedFetchingSheetsList] = useState< + boolean + >(false); + + const onFetchAllSheetFailure = useCallback(() => { + setIsFetchingSheetsList(false); + setFailedFetchingSheetsList(true); + }, [setIsFetchingSheetsList]); + + const onFetchAllSheetSuccess = useCallback( + ( + payload: executeDatasourceQuerySuccessPayload<{ + sheets: Sheets; + name: string; + id: string; + }>, + ) => { + setIsFetchingSheetsList(false); + const sheetOptions: DropdownOptions = []; + + if (payload.data && payload.data.body) { + const responseBody = payload.data.body; + if (isObject(responseBody)) { + const { sheets = [] } = responseBody; + if (Array.isArray(sheets)) { + sheets.map(({ title }) => { + sheetOptions.push({ + id: title, + label: title, + value: title, + }); + setSheetsList(sheetOptions); + }); + } else { + // to handle error like "401 Unauthorized" + } + } + } + }, + [setSheetsList, setIsFetchingSheetsList], + ); + + const fetchSheetsList = useCallback( + ({ + requestObject, + selectedDatasourceId, + selectedSpreadsheetId, + }: FetchSheetsList) => { + setSheetsList([]); + setIsFetchingSheetsList(true); + setFailedFetchingSheetsList(false); + + let requestData = { ...demoRequest }; + if (isObject(requestObject) && Object.keys(requestObject).length) { + requestData = { ...requestObject }; + } + requestData.method = GOOGLE_SHEET_METHODS.GET_ALL_SHEETS; + requestData.sheetUrl = getSheetUrl(selectedSpreadsheetId); + const formattedRequestData = Object.entries( + requestData, + ).map(([dataKey, dataValue]) => ({ key: dataKey, value: dataValue })); + dispatch( + executeDatasourceQuery({ + payload: { + datasourceId: selectedDatasourceId, + data: formattedRequestData, + }, + onSuccessCallback: onFetchAllSheetSuccess, + onErrorCallback: onFetchAllSheetFailure, + }), + ); + }, + [ + setSheetsList, + onFetchAllSheetSuccess, + onFetchAllSheetFailure, + setIsFetchingSheetsList, + setFailedFetchingSheetsList, + ], + ); + + return { + sheetsList, + isFetchingSheetsList, + failedFetchingSheetsList, + fetchSheetsList, + }; +}; + +export type FetchColumnHeaderListParams = { + selectedDatasourceId: string; + selectedSpreadsheetId: string; + sheetName: string; + tableHeaderIndex: string; + requestObject?: Record; +}; + +export type UseSheetColumnHeadersReturn = { + columnHeaderList: DropdownOption[]; + isFetchingColumnHeaderList: boolean; + errorFetchingColumnHeaderList: string; + fetchColumnHeaderList: ({ + selectedDatasourceId, + selectedSpreadsheetId, + sheetName, + tableHeaderIndex, + }: FetchColumnHeaderListParams) => void; +}; + +export const useSheetColumnHeaders = () => { + const dispatch = useDispatch(); + + const [columnHeaderList, setColumnHeaderList] = useState( + [], + ); + + const [isFetchingColumnHeaderList, setIsFetchingColumnHeaderList] = useState< + boolean + >(false); + const [ + errorFetchingColumnHeaderList, + setErrorFetchingColumnHeaderList, + ] = useState(""); + + const onFetchColumnHeadersFailure = useCallback( + (error: string) => { + setIsFetchingColumnHeaderList(false); + setErrorFetchingColumnHeaderList(error); + }, + [setErrorFetchingColumnHeaderList, setIsFetchingColumnHeaderList], + ); + + const onFetchColumnHeadersSuccess = useCallback( + ( + payload: executeDatasourceQuerySuccessPayload[]>, + ) => { + setIsFetchingColumnHeaderList(false); + const columnHeaders: DropdownOptions = []; + + if (payload.data && payload.data.body) { + const responseBody = payload.data.body; + if (Array.isArray(responseBody) && responseBody.length) { + const headersObject = responseBody[0]; + delete headersObject.rowIndex; + const headers = Object.keys(headersObject); + if (Array.isArray(headers) && headers.length) { + headers.map((header, index) => { + columnHeaders.push({ + id: `${header}_${index}`, + label: header, + value: header, + }); + }); + setColumnHeaderList(columnHeaders); + } + } else { + let error = "Failed fetching Column headers"; + if (typeof responseBody === "string") { + error = responseBody; + } + setColumnHeaderList([]); + setErrorFetchingColumnHeaderList(error); + } + } + }, + [ + setColumnHeaderList, + setIsFetchingColumnHeaderList, + setErrorFetchingColumnHeaderList, + ], + ); + + const fetchColumnHeaderList = useCallback( + (params: FetchColumnHeaderListParams) => { + setIsFetchingColumnHeaderList(true); + setErrorFetchingColumnHeaderList(""); + + let requestData = { ...demoRequest }; + if ( + isObject(params.requestObject) && + Object.keys(params.requestObject).length + ) { + requestData = { ...params.requestObject }; + } + requestData.method = GOOGLE_SHEET_METHODS.GET_ALL_COLUMNS; + requestData.sheetUrl = getSheetUrl(params.selectedSpreadsheetId); + requestData.tableHeaderIndex = params.tableHeaderIndex; + requestData.rowLimit = "1"; + requestData.rowOffset = "0"; + requestData.sheetName = params.sheetName; + + const formattedRequestData = Object.entries( + requestData, + ).map(([dataKey, dataValue]) => ({ key: dataKey, value: dataValue })); + dispatch( + executeDatasourceQuery({ + payload: { + datasourceId: params.selectedDatasourceId, + data: formattedRequestData, + }, + onSuccessCallback: onFetchColumnHeadersSuccess, + onErrorCallback: onFetchColumnHeadersFailure, + }), + ); + }, + [ + onFetchColumnHeadersSuccess, + onFetchColumnHeadersFailure, + setIsFetchingColumnHeaderList, + setErrorFetchingColumnHeaderList, + ], + ); + + return { + columnHeaderList, + isFetchingColumnHeaderList, + errorFetchingColumnHeaderList, + fetchColumnHeaderList, + }; +}; + const payload = [ { value: "LIST_BUCKETS", }, ]; -export type executeDatasourceQuerySuccessPayload = { - responseMeta: ResponseMeta; - data: { - body: { bucketList: string[] }; - headers: Record; - statusCode: string; - isExecutionSuccess: boolean; - }; -}; - export const useS3BucketList = () => { const dispatch = useDispatch(); @@ -91,12 +484,18 @@ export const useS3BucketList = () => { boolean >(false); const onFetchBucketSuccess = useCallback( - (payload: executeDatasourceQuerySuccessPayload) => { + ( + payload: executeDatasourceQuerySuccessPayload<{ + bucketList: Array; + }>, + ) => { setIsFetchingBucketList(false); if (payload.data && payload.data.body) { const payloadBody = payload.data.body; - const { bucketList: list = [] } = payloadBody; - setBucketList(list); + if (Array.isArray(payloadBody.bucketList)) { + const { bucketList: list = [] } = payloadBody; + setBucketList(list); + } } }, [setBucketList, setIsFetchingBucketList], diff --git a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/styles.ts b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/styles.ts index 7817dde0db9a..0cf64ae120b1 100644 --- a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/styles.ts +++ b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/styles.ts @@ -2,8 +2,10 @@ import styled from "styled-components"; import { getTypographyByKey } from "constants/DefaultTheme"; export const SelectWrapper = styled.div<{ width: string }>` + display: inline-block; margin: 10px; max-width: ${(props) => props.width}; + width: 100%; `; export const Label = styled.p` diff --git a/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/types.ts b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/types.ts new file mode 100644 index 000000000000..a57f200be93e --- /dev/null +++ b/app/client/src/pages/Editor/GeneratePage/components/GeneratePageForm/types.ts @@ -0,0 +1,6 @@ +export type GeneratePagePayload = { + tableName: string; + columns?: string[]; + searchColumn?: string; + pluginSpecificParams?: Record; +}; diff --git a/app/client/src/pages/Editor/GeneratePage/components/GoogleSheetForm.tsx b/app/client/src/pages/Editor/GeneratePage/components/GoogleSheetForm.tsx deleted file mode 100644 index 81e36f5d271a..000000000000 --- a/app/client/src/pages/Editor/GeneratePage/components/GoogleSheetForm.tsx +++ /dev/null @@ -1,299 +0,0 @@ -import React, { useState, useEffect, useCallback } from "react"; -import { useSelector, useDispatch } from "react-redux"; -import { getEditorConfig } from "selectors/entitiesSelector"; -import { AppState } from "reducers/index"; -import Dropdown, { DropdownOption } from "components/ads/Dropdown"; -import { fetchPluginFormConfig } from "actions/pluginActions"; -import { - executeDatasourceQuery, - executeDatasourceQuerySuccessPayload, -} from "../../../../actions/datasourceActions"; -import { - DropdownOptions, - DROPDOWN_DIMENSION, - DEFAULT_DROPDOWN_OPTION, -} from "./constants"; -import { SelectWrapper, Label, Bold } from "./GeneratePageForm/styles"; -import log from "loglevel"; - -const GOOGLE_SHEET_METHODS = { - GET_ALL_SPREADSHEETS: "LIST", // Get all the spreadsheets - GET_ALL_SHEETS: "INFO", // fetch all the sub-sheets - GET_ALL_COLUMNS: "GET", // Get column names -}; - -const demoRequest = { - method: "", - sheetUrl: "", - range: "", - spreadsheetName: "", - tableHeaderIndex: "1", - queryFormat: "ROWS", - rowLimit: "", - sheetsName: "", - rowOffset: "", - rowObject: "", - rowObjects: "", - rowIndex: "", - deleteFormat: "SHEET", -}; - -const getSheetUrl = (sheetId: string): string => - `https://docs.google.com/spreadsheets/d/${sheetId}/edit#gid=0`; - -// Types - -export interface GridProperties { - rowCount: number; - columnCount: number; -} - -export interface Sheet { - sheetId: number; - title: string; - index: number; - sheetType: string; - gridProperties: GridProperties; -} - -export type Sheets = Sheet[]; - -type Props = { - googleSheetPluginId: string; - selectedDatasource: DropdownOption; - setSelectedDatasourceIsInvalid: (isInvalid: boolean) => void; - setSelectedDatasourceTableOptions: React.Dispatch< - React.SetStateAction - >; - selectedSpreadsheet: DropdownOption; -}; - -// ---------- GoogleSheetForm Component ------- - -function GoogleSheetForm(props: Props) { - const { - googleSheetPluginId, - selectedDatasource, - selectedSpreadsheet, - setSelectedDatasourceIsInvalid, - setSelectedDatasourceTableOptions, - } = props; - - const [sheetsList, setSheetsList] = useState([]); - - const [selectedSheet, setSelectedSheet] = useState( - DEFAULT_DROPDOWN_OPTION, - ); - const dispatch = useDispatch(); - - const googleSheetEditorConfig = useSelector((state: AppState) => - getEditorConfig(state, googleSheetPluginId), - ); - - // TODO :- Create loading state and set Loading state false on success or error - const onFetchAllSpreadsheetFailure = (error: any) => { - log.error(error); - }; - - const onFetchAllSpreadsheetSuccess = useCallback( - ( - payload: executeDatasourceQuerySuccessPayload< - Array<{ id: string; name: string }> - >, - ) => { - const tableOptions: DropdownOptions = []; - if (payload.data && payload.data.body) { - const spreadSheets = payload.data.body; - - if (Array.isArray(spreadSheets)) { - spreadSheets.map(({ id, name }) => { - tableOptions.push({ - id, - label: name, - value: name, - }); - setSelectedDatasourceTableOptions(tableOptions); - }); - } else { - // to handle error like "401 Unauthorized" - setSelectedDatasourceIsInvalid(true); - } - } - }, - [setSelectedDatasourceIsInvalid, setSelectedDatasourceTableOptions], - ); - - useEffect(() => { - // Check if google sheet editor config is fetched. - // if not, fetch it. - - if (!googleSheetEditorConfig) { - dispatch( - fetchPluginFormConfig({ - pluginId: selectedDatasource.data?.pluginId, - }), - ); - } - }, [googleSheetEditorConfig]); - - useEffect(() => { - // On change of datasource selection - // if googleSheetEditorConfig if fetched then get all spreadsheets - - if ( - selectedDatasource.value && - selectedDatasource.id && - googleSheetEditorConfig - ) { - const requestData = { ...demoRequest }; - requestData.method = GOOGLE_SHEET_METHODS.GET_ALL_SPREADSHEETS; - const formattedRequestData = Object.entries( - requestData, - ).map(([dataKey, dataValue]) => ({ key: dataKey, value: dataValue })); - dispatch( - executeDatasourceQuery({ - payload: { - datasourceId: selectedDatasource.id, - data: formattedRequestData, - }, - onSuccessCallback: onFetchAllSpreadsheetSuccess, - onErrorCallback: onFetchAllSpreadsheetFailure, - }), - ); - } - }, [selectedDatasource.value, googleSheetEditorConfig, dispatch]); - - // TODO :- Create loading state and set Loading state false on success or error - const onFetchAllSheetFailure = (error: any) => { - log.error(error); - }; - - const onFetchAllSheetSuccess = useCallback( - ( - payload: executeDatasourceQuerySuccessPayload<{ - sheets: Sheets; - name: string; - id: string; - }>, - ) => { - const sheetOptions: DropdownOptions = []; - if (payload.data && payload.data.body) { - const responseBody = payload.data.body; - const { sheets = [] } = responseBody; - if (Array.isArray(sheets)) { - sheets.map(({ title }) => { - sheetOptions.push({ - id: title, - label: title, - value: title, - }); - setSheetsList(sheetOptions); - }); - } else { - // to handle error like "401 Unauthorized" - } - } - }, - [setSelectedDatasourceIsInvalid, setSelectedDatasourceTableOptions], - ); - - // When user selects a spreadsheet - // Fetch all sheets inside that spreadsheet - useEffect(() => { - if ( - selectedDatasource.value && - selectedDatasource.id && - selectedSpreadsheet.value && - selectedSpreadsheet.id - ) { - const requestData = { ...demoRequest }; - requestData.method = GOOGLE_SHEET_METHODS.GET_ALL_SHEETS; - requestData.sheetUrl = getSheetUrl(selectedSpreadsheet.id); - const formattedRequestData = Object.entries( - requestData, - ).map(([dataKey, dataValue]) => ({ key: dataKey, value: dataValue })); - dispatch( - executeDatasourceQuery({ - payload: { - datasourceId: selectedDatasource.id, - data: formattedRequestData, - }, - onSuccessCallback: onFetchAllSheetSuccess, - onErrorCallback: onFetchAllSheetFailure, - }), - ); - } - }, [ - selectedSpreadsheet.id, - selectedSpreadsheet.value, - selectedDatasource.id, - selectedDatasource.value, - dispatch, - ]); - - const onSelectSheetOption = ( - sheetValue: string | undefined, - sheetObj: DropdownOption | undefined, - ) => { - if (sheetValue && sheetObj) { - setSelectedSheet(sheetObj); - } - }; - - const onSelectColumn = () => { - // - }; - - const selectedColumn = DEFAULT_DROPDOWN_OPTION; - - const selectedTableColumnOptions: DropdownOptions = []; - - return ( -
- {selectedSpreadsheet.value ? ( - - - - - ) : null} - - {selectedSheet.value && ( - - - - - - )} -
- ); -} - -export default GoogleSheetForm; diff --git a/app/client/src/pages/Editor/GeneratePage/index.tsx b/app/client/src/pages/Editor/GeneratePage/index.tsx index 321904843e10..0cdf18e69084 100644 --- a/app/client/src/pages/Editor/GeneratePage/index.tsx +++ b/app/client/src/pages/Editor/GeneratePage/index.tsx @@ -9,8 +9,8 @@ import Text, { TextType } from "components/ads/Text"; const Container = styled.div` display: flex; flex-direction: column; - justify-content: center; - align-items: center; + overflow-y: auto; + height: 100%; `; const HeadingContainer = styled.div` @@ -35,6 +35,7 @@ const SubHeading = styled.p` ${(props) => getTypographyByKey(props, "p1")}; margin: 20px 0px; color: ${Colors.BLACK}; + text-align: center; `; const Back = styled.span` diff --git a/app/client/src/selectors/entitiesSelector.ts b/app/client/src/selectors/entitiesSelector.ts index 29e036a79168..dab6a675f4f6 100644 --- a/app/client/src/selectors/entitiesSelector.ts +++ b/app/client/src/selectors/entitiesSelector.ts @@ -17,7 +17,6 @@ import { CanvasWidgetsReduxState } from "../reducers/entityReducers/canvasWidget import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; import { AppStoreState } from "reducers/entityReducers/appReducer"; import { GenerateCRUDEnabledPluginMap } from "../api/PluginApi"; -import { PLUGIN_PACKAGE_NAME } from "pages/Editor/GeneratePage/components/constants"; import { APP_MODE } from "entities/App"; @@ -257,10 +256,7 @@ export const getGenerateCRUDEnabledPluginMap = createSelector( (plugins) => { const pluginIdGenerateCRUDPageEnabled: GenerateCRUDEnabledPluginMap = {}; plugins.map((plugin) => { - if ( - plugin.generateCRUDPageComponent && - plugin.packageName !== PLUGIN_PACKAGE_NAME.GOOGLE_SHEETS - ) { + if (plugin.generateCRUDPageComponent) { pluginIdGenerateCRUDPageEnabled[plugin.id] = plugin.packageName; } });