fix: gsheet preview data UI using tabs for preview and configuration (#28318)
This commit is contained in:
parent
8dab2c84e6
commit
72c4b4d996
|
|
@ -1903,6 +1903,11 @@ export const ERR_FETCHING_DATASOURCE_PREVIEW_DATA = () =>
|
||||||
export const FETCHING_DATASOURCE_PREVIEW_DATA = () => "Loading data";
|
export const FETCHING_DATASOURCE_PREVIEW_DATA = () => "Loading data";
|
||||||
export const SCHEMA_PREVIEW_NO_DATA = () =>
|
export const SCHEMA_PREVIEW_NO_DATA = () =>
|
||||||
"No data records to show or the table header begins with an index other than 1";
|
"No data records to show or the table header begins with an index other than 1";
|
||||||
|
export const GSHEET_SPREADSHEET_LABEL = () => "Spreadsheets";
|
||||||
|
export const GSHEET_SPREADSHEET_LOADING = () => "Loading Spreadsheets";
|
||||||
|
export const GSHEET_SHEET_LOADING = () => "Loading Sheets";
|
||||||
|
export const GSHEET_DATA_LOADING = () => "Loading attributes";
|
||||||
|
export const GSHEET_SEARCH_PLACEHOLDER = () => "Search for spreadsheet";
|
||||||
|
|
||||||
//Layout Conversion flow
|
//Layout Conversion flow
|
||||||
export const CONVERT = () => "Convert layout";
|
export const CONVERT = () => "Convert layout";
|
||||||
|
|
@ -2161,6 +2166,8 @@ export const COMMUNITY_TEMPLATES = {
|
||||||
export const EMPTY_TABLE_TITLE_TEXT = () => "Empty table";
|
export const EMPTY_TABLE_TITLE_TEXT = () => "Empty table";
|
||||||
export const EMPTY_TABLE_MESSAGE_TEXT = () =>
|
export const EMPTY_TABLE_MESSAGE_TEXT = () =>
|
||||||
"There are no data records to show";
|
"There are no data records to show";
|
||||||
|
export const LOADING_RECORDS_TITLE_TEXT = () => "Loading records";
|
||||||
|
export const LOADING_RECORDS_MESSAGE_TEXT = () => "This may take a few seconds";
|
||||||
export const EMPTY_TABLE_SVG_ALT_TEXT = () => "Empty table image";
|
export const EMPTY_TABLE_SVG_ALT_TEXT = () => "Empty table image";
|
||||||
|
|
||||||
export const DATA_PANE_TITLE = () => "Datasources in your Workspace";
|
export const DATA_PANE_TITLE = () => "Datasources in your Workspace";
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,8 @@ export type DATASOURCE_SCHEMA_EVENTS =
|
||||||
| "GSHEET_PREVIEW_DATA_SHOWN"
|
| "GSHEET_PREVIEW_DATA_SHOWN"
|
||||||
| "DATASOURCE_GENERATE_PAGE_BUTTON_CLICKED"
|
| "DATASOURCE_GENERATE_PAGE_BUTTON_CLICKED"
|
||||||
| "DATASOURCE_PREVIEW_TABLE_CHANGE"
|
| "DATASOURCE_PREVIEW_TABLE_CHANGE"
|
||||||
| "DATASOURCE_PREVIEW_DATA_SHOWN";
|
| "DATASOURCE_PREVIEW_DATA_SHOWN"
|
||||||
|
| "GSHEET_SPREADSHEET_SEARCH";
|
||||||
|
|
||||||
type WALKTHROUGH_EVENTS = "WALKTHROUGH_DISMISSED" | "WALKTHROUGH_SHOWN";
|
type WALKTHROUGH_EVENTS = "WALKTHROUGH_DISMISSED" | "WALKTHROUGH_SHOWN";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
|
||||||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||||
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
||||||
import { getHasManagePagePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
import { getHasManagePagePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
||||||
|
import type { Datasource } from "entities/Datasource";
|
||||||
import { DatasourceStructureContext } from "entities/Datasource";
|
import { DatasourceStructureContext } from "entities/Datasource";
|
||||||
|
|
||||||
const SCHEMA_GUIDE_GIF = `${ASSETS_CDN_URL}/schema.gif`;
|
const SCHEMA_GUIDE_GIF = `${ASSETS_CDN_URL}/schema.gif`;
|
||||||
|
|
@ -152,7 +153,7 @@ const Placeholder = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DataStructureListWrapper = styled.div`
|
const DataStructureListWrapper = styled.div`
|
||||||
overflow-y: auto;
|
overflow-y: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -176,7 +177,7 @@ interface CollapsibleProps {
|
||||||
label: string;
|
label: string;
|
||||||
CustomLabelComponent?: (props: any) => JSX.Element;
|
CustomLabelComponent?: (props: any) => JSX.Element;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
datasourceId?: string;
|
datasource?: Partial<Datasource>;
|
||||||
containerRef?: MutableRefObject<HTMLDivElement | null>;
|
containerRef?: MutableRefObject<HTMLDivElement | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +190,7 @@ export function Collapsible({
|
||||||
children,
|
children,
|
||||||
containerRef,
|
containerRef,
|
||||||
CustomLabelComponent,
|
CustomLabelComponent,
|
||||||
datasourceId,
|
datasource,
|
||||||
expand = true,
|
expand = true,
|
||||||
label,
|
label,
|
||||||
}: CollapsibleProps) {
|
}: CollapsibleProps) {
|
||||||
|
|
@ -220,7 +221,7 @@ export function Collapsible({
|
||||||
/>
|
/>
|
||||||
{!!CustomLabelComponent ? (
|
{!!CustomLabelComponent ? (
|
||||||
<CustomLabelComponent
|
<CustomLabelComponent
|
||||||
datasourceId={datasourceId}
|
datasource={datasource}
|
||||||
onRefreshCallback={() => handleCollapse(true)}
|
onRefreshCallback={() => handleCollapse(true)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -427,7 +428,7 @@ function ActionSidebar({
|
||||||
<Collapsible
|
<Collapsible
|
||||||
CustomLabelComponent={DatasourceStructureHeader}
|
CustomLabelComponent={DatasourceStructureHeader}
|
||||||
containerRef={schemaRef}
|
containerRef={schemaRef}
|
||||||
datasourceId={datasourceId}
|
datasource={{ id: datasourceId }}
|
||||||
expand={!showSuggestedWidgets}
|
expand={!showSuggestedWidgets}
|
||||||
label="Schema"
|
label="Schema"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -181,9 +181,11 @@ export function renderDatasourceSection(
|
||||||
if (
|
if (
|
||||||
!value &&
|
!value &&
|
||||||
!!viewMode &&
|
!!viewMode &&
|
||||||
!!section.hidden &&
|
(!section.hidden ||
|
||||||
|
(!!section.hidden &&
|
||||||
"comparison" in section.hidden &&
|
"comparison" in section.hidden &&
|
||||||
section.hidden.comparison === ComparisonOperationsEnum.VIEW_MODE
|
section.hidden.comparison ===
|
||||||
|
ComparisonOperationsEnum.VIEW_MODE))
|
||||||
) {
|
) {
|
||||||
value = section.initialValue;
|
value = section.initialValue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,16 @@ export const ResizerContentContainer = styled.div`
|
||||||
border-bottom: 1px solid var(--ads-v2-color-border);
|
border-bottom: 1px solid var(--ads-v2-color-border);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.db-form-resizer-content.db-form-resizer-content-show-tabs {
|
&.db-form-resizer-content.db-form-resizer-content-show-tabs,
|
||||||
|
&.saas-form-resizer-content.saas-form-resizer-content-show-tabs {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
& .t--ds-form-header {
|
& .t--ds-form-header {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.saas-form-resizer-content.saas-form-resizer-content-show-tabs form {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
border-top: none;
|
border-top: none;
|
||||||
.db-form-content-container {
|
.db-form-content-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -871,16 +871,9 @@ class DatasourceEditorRouter extends React.Component<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldShowTabs = () => {
|
shouldShowTabs = () => {
|
||||||
const {
|
const { isEnabledForDSViewModeSchema, isPluginAllowedToPreviewData } =
|
||||||
isEnabledForDSViewModeSchema,
|
this.props;
|
||||||
isPluginAllowedToPreviewData,
|
return isEnabledForDSViewModeSchema && isPluginAllowedToPreviewData;
|
||||||
pluginDatasourceForm,
|
|
||||||
} = this.props;
|
|
||||||
const isRestAPI =
|
|
||||||
pluginDatasourceForm === DatasourceComponentTypes.RestAPIDatasourceForm;
|
|
||||||
return (
|
|
||||||
isEnabledForDSViewModeSchema && isPluginAllowedToPreviewData && !isRestAPI
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
renderTabsForViewMode = () => {
|
renderTabsForViewMode = () => {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@ import DatasourceViewModeSchema from "./DatasourceViewModeSchema";
|
||||||
import { getCurrentEnvironmentId } from "@appsmith/selectors/environmentSelectors";
|
import { getCurrentEnvironmentId } from "@appsmith/selectors/environmentSelectors";
|
||||||
import { isEnvironmentValid } from "@appsmith/utils/Environments";
|
import { isEnvironmentValid } from "@appsmith/utils/Environments";
|
||||||
import type { Datasource } from "entities/Datasource";
|
import type { Datasource } from "entities/Datasource";
|
||||||
import { isGoogleSheetPluginDS } from "utils/editorContextUtils";
|
import {
|
||||||
import { getPluginNameFromId } from "@appsmith/selectors/entitiesSelector";
|
isDatasourceAuthorizedForQueryCreation,
|
||||||
|
isGoogleSheetPluginDS,
|
||||||
|
} from "utils/editorContextUtils";
|
||||||
|
import { getPlugin } from "@appsmith/selectors/entitiesSelector";
|
||||||
import GoogleSheetSchema from "./GoogleSheetSchema";
|
import GoogleSheetSchema from "./GoogleSheetSchema";
|
||||||
|
|
||||||
const TabsContainer = styled(Tabs)`
|
const TabsContainer = styled(Tabs)`
|
||||||
|
|
@ -55,14 +58,22 @@ const DatasourceTabs = (props: DatasourceTabProps) => {
|
||||||
const setDatasourceViewModeFlagClick = (value: boolean) => {
|
const setDatasourceViewModeFlagClick = (value: boolean) => {
|
||||||
dispatch(setDatasourceViewModeFlag(value));
|
dispatch(setDatasourceViewModeFlag(value));
|
||||||
};
|
};
|
||||||
const pluginName = useSelector((state) =>
|
const plugin = useSelector((state) =>
|
||||||
getPluginNameFromId(state, props.datasource.pluginId),
|
getPlugin(state, props.datasource.pluginId),
|
||||||
);
|
);
|
||||||
const isGoogleSheetPlugin = isGoogleSheetPluginDS(pluginName);
|
const isGoogleSheetPlugin = isGoogleSheetPluginDS(plugin?.packageName);
|
||||||
|
const isPluginAuthorized =
|
||||||
|
!!plugin && !!props.datasource
|
||||||
|
? isDatasourceAuthorizedForQueryCreation(
|
||||||
|
props.datasource,
|
||||||
|
plugin,
|
||||||
|
currentEnvironmentId,
|
||||||
|
)
|
||||||
|
: false;
|
||||||
return (
|
return (
|
||||||
<TabsContainer
|
<TabsContainer
|
||||||
defaultValue={
|
defaultValue={
|
||||||
isDatasourceValid
|
isDatasourceValid || isPluginAuthorized
|
||||||
? VIEW_MODE_TABS.VIEW_DATA
|
? VIEW_MODE_TABS.VIEW_DATA
|
||||||
: VIEW_MODE_TABS.CONFIGURATIONS
|
: VIEW_MODE_TABS.CONFIGURATIONS
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,10 @@ import React, { memo, useEffect, useState, useContext } from "react";
|
||||||
import EntityPlaceholder from "../Explorer/Entity/Placeholder";
|
import EntityPlaceholder from "../Explorer/Entity/Placeholder";
|
||||||
import DatasourceStructure from "./DatasourceStructure";
|
import DatasourceStructure from "./DatasourceStructure";
|
||||||
import { SearchInput, Text } from "design-system";
|
import { SearchInput, Text } from "design-system";
|
||||||
import styled from "styled-components";
|
|
||||||
import { getIsFetchingDatasourceStructure } from "@appsmith/selectors/entitiesSelector";
|
import { getIsFetchingDatasourceStructure } from "@appsmith/selectors/entitiesSelector";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import type { AppState } from "@appsmith/reducers";
|
import type { AppState } from "@appsmith/reducers";
|
||||||
import DatasourceStructureLoadingContainer from "./DatasourceStructureLoadingContainer";
|
import ItemLoadingIndicator from "./ItemLoadingIndicator";
|
||||||
import DatasourceStructureNotFound from "./DatasourceStructureNotFound";
|
import DatasourceStructureNotFound from "./DatasourceStructureNotFound";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
import { PluginName } from "entities/Action";
|
import { PluginName } from "entities/Action";
|
||||||
|
|
@ -23,6 +22,7 @@ import WalkthroughContext from "components/featureWalkthrough/walkthroughContext
|
||||||
import { setFeatureWalkthroughShown } from "utils/storage";
|
import { setFeatureWalkthroughShown } from "utils/storage";
|
||||||
import { FEATURE_WALKTHROUGH_KEYS } from "constants/WalkthroughConstants";
|
import { FEATURE_WALKTHROUGH_KEYS } from "constants/WalkthroughConstants";
|
||||||
import { SCHEMA_SECTION_ID } from "entities/Action";
|
import { SCHEMA_SECTION_ID } from "entities/Action";
|
||||||
|
import { DatasourceStructureSearchContainer } from "./SchemaViewModeCSS";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
datasourceId: string;
|
datasourceId: string;
|
||||||
|
|
@ -50,15 +50,6 @@ export const SCHEMALESS_PLUGINS: Array<string> = [
|
||||||
PluginName.OPEN_AI,
|
PluginName.OPEN_AI,
|
||||||
];
|
];
|
||||||
|
|
||||||
const DatasourceStructureSearchContainer = styled.div`
|
|
||||||
margin-bottom: 8px;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 10;
|
|
||||||
background: white;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Container = (props: Props) => {
|
const Container = (props: Props) => {
|
||||||
const isLoading = useSelector((state: AppState) =>
|
const isLoading = useSelector((state: AppState) =>
|
||||||
getIsFetchingDatasourceStructure(state, props.datasourceId),
|
getIsFetchingDatasourceStructure(state, props.datasourceId),
|
||||||
|
|
@ -113,7 +104,7 @@ const Container = (props: Props) => {
|
||||||
|
|
||||||
const filteredDastasourceStructure =
|
const filteredDastasourceStructure =
|
||||||
props.datasourceStructure.tables.filter((table) =>
|
props.datasourceStructure.tables.filter((table) =>
|
||||||
table.name.includes(value),
|
table.name.toLowerCase().includes(value.toLowerCase()),
|
||||||
);
|
);
|
||||||
|
|
||||||
setDatasourceStructure({ tables: filteredDastasourceStructure });
|
setDatasourceStructure({ tables: filteredDastasourceStructure });
|
||||||
|
|
@ -129,7 +120,9 @@ const Container = (props: Props) => {
|
||||||
view = (
|
view = (
|
||||||
<>
|
<>
|
||||||
{props.context !== DatasourceStructureContext.EXPLORER && (
|
{props.context !== DatasourceStructureContext.EXPLORER && (
|
||||||
<DatasourceStructureSearchContainer>
|
<DatasourceStructureSearchContainer
|
||||||
|
className={`t--search-container--${props.context.toLowerCase()}`}
|
||||||
|
>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
className="datasourceStructure-search"
|
className="datasourceStructure-search"
|
||||||
endIcon="close"
|
endIcon="close"
|
||||||
|
|
@ -137,7 +130,7 @@ const Container = (props: Props) => {
|
||||||
placeholder={createMessage(
|
placeholder={createMessage(
|
||||||
DATASOURCE_STRUCTURE_INPUT_PLACEHOLDER_TEXT,
|
DATASOURCE_STRUCTURE_INPUT_PLACEHOLDER_TEXT,
|
||||||
)}
|
)}
|
||||||
size={"md"}
|
size={"sm"}
|
||||||
startIcon="search"
|
startIcon="search"
|
||||||
type="text"
|
type="text"
|
||||||
/>
|
/>
|
||||||
|
|
@ -199,7 +192,7 @@ const Container = (props: Props) => {
|
||||||
props.context !== DatasourceStructureContext.EXPLORER &&
|
props.context !== DatasourceStructureContext.EXPLORER &&
|
||||||
isLoading
|
isLoading
|
||||||
) {
|
) {
|
||||||
view = <DatasourceStructureLoadingContainer />;
|
view = <ItemLoadingIndicator type="SCHEMA" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,23 @@
|
||||||
import React, { useCallback } from "react";
|
import React, { useCallback } from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { Button, Text } from "design-system";
|
import { Button, Text } from "design-system";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { refreshDatasourceStructure } from "actions/datasourceActions";
|
import { refreshDatasourceStructure } from "actions/datasourceActions";
|
||||||
import { SCHEMA_LABEL, createMessage } from "@appsmith/constants/messages";
|
import {
|
||||||
|
GSHEET_SPREADSHEET_LABEL,
|
||||||
|
SCHEMA_LABEL,
|
||||||
|
createMessage,
|
||||||
|
} from "@appsmith/constants/messages";
|
||||||
|
import type { Datasource } from "entities/Datasource";
|
||||||
import { DatasourceStructureContext } from "entities/Datasource";
|
import { DatasourceStructureContext } from "entities/Datasource";
|
||||||
|
import { getPluginPackageNameFromId } from "@appsmith/selectors/entitiesSelector";
|
||||||
|
import { isGoogleSheetPluginDS } from "utils/editorContextUtils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
datasourceId: string;
|
datasource?: Datasource;
|
||||||
onRefreshCallback?: () => void;
|
onRefreshCallback?: () => void;
|
||||||
paddingBottom?: boolean;
|
paddingBottom?: boolean;
|
||||||
|
refetchFn?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderWrapper = styled.div<{ paddingBottom: boolean }>`
|
const HeaderWrapper = styled.div<{ paddingBottom: boolean }>`
|
||||||
|
|
@ -24,27 +32,41 @@ export default function DatasourceStructureHeader(props: Props) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const dispatchRefresh = useCallback(
|
const dispatchRefresh = useCallback(
|
||||||
(event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||||
|
if (props.datasource?.id) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if (props.refetchFn) {
|
||||||
|
props.refetchFn();
|
||||||
|
} else {
|
||||||
dispatch(
|
dispatch(
|
||||||
refreshDatasourceStructure(
|
refreshDatasourceStructure(
|
||||||
props.datasourceId,
|
props.datasource?.id,
|
||||||
DatasourceStructureContext.QUERY_EDITOR,
|
DatasourceStructureContext.QUERY_EDITOR,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
!!props.onRefreshCallback && props.onRefreshCallback();
|
!!props.onRefreshCallback && props.onRefreshCallback();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[dispatch, props.datasourceId],
|
[dispatch, props.datasource?.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const pluginPackageName = useSelector((state) =>
|
||||||
|
getPluginPackageNameFromId(state, props.datasource?.pluginId || ""),
|
||||||
|
);
|
||||||
|
const isGoogleSheetPlugin = isGoogleSheetPluginDS(pluginPackageName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderWrapper
|
<HeaderWrapper
|
||||||
className="datasourceStructure-header"
|
className="datasourceStructure-header"
|
||||||
paddingBottom={!!props.paddingBottom}
|
paddingBottom={!!props.paddingBottom}
|
||||||
>
|
>
|
||||||
<Text kind="heading-xs" renderAs="h3">
|
<Text kind="heading-xs" renderAs="h3">
|
||||||
{createMessage(SCHEMA_LABEL)}
|
{createMessage(
|
||||||
|
isGoogleSheetPlugin ? GSHEET_SPREADSHEET_LABEL : SCHEMA_LABEL,
|
||||||
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<Button
|
||||||
className="datasourceStructure-refresh"
|
className="datasourceStructure-refresh"
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { createMessage, LOADING_SCHEMA } from "@appsmith/constants/messages";
|
|
||||||
import { Spinner, Text } from "design-system";
|
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
const LoadingContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SpinnerWrapper = styled.div`
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const DatasourceStructureLoadingContainer = () => {
|
|
||||||
return (
|
|
||||||
<LoadingContainer>
|
|
||||||
<SpinnerWrapper>
|
|
||||||
<Spinner size={"sm"} />
|
|
||||||
</SpinnerWrapper>
|
|
||||||
<Text kind="body-m" renderAs="p">
|
|
||||||
{createMessage(LOADING_SCHEMA)}
|
|
||||||
</Text>
|
|
||||||
</LoadingContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DatasourceStructureLoadingContainer;
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import styled from "styled-components";
|
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { DatasourceStructureContainer as DatasourceStructureList } from "./DatasourceStructureContainer";
|
import { DatasourceStructureContainer as DatasourceStructureList } from "./DatasourceStructureContainer";
|
||||||
import {
|
import {
|
||||||
|
|
@ -8,16 +7,10 @@ import {
|
||||||
getNumberOfEntitiesInCurrentPage,
|
getNumberOfEntitiesInCurrentPage,
|
||||||
} from "@appsmith/selectors/entitiesSelector";
|
} from "@appsmith/selectors/entitiesSelector";
|
||||||
import DatasourceStructureHeader from "./DatasourceStructureHeader";
|
import DatasourceStructureHeader from "./DatasourceStructureHeader";
|
||||||
import { MessageWrapper, TableWrapper } from "./GoogleSheetSchema";
|
import { Button } from "design-system";
|
||||||
import { Spinner, Text, Button } from "design-system";
|
|
||||||
import {
|
import {
|
||||||
ERR_FETCHING_DATASOURCE_PREVIEW_DATA,
|
|
||||||
FETCHING_DATASOURCE_PREVIEW_DATA,
|
|
||||||
DATASOURCE_GENERATE_PAGE_BUTTON,
|
DATASOURCE_GENERATE_PAGE_BUTTON,
|
||||||
EMPTY_TABLE_TITLE_TEXT,
|
|
||||||
EMPTY_TABLE_MESSAGE_TEXT,
|
|
||||||
createMessage,
|
createMessage,
|
||||||
EMPTY_TABLE_SVG_ALT_TEXT,
|
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
import Table from "pages/Editor/QueryEditor/Table";
|
import Table from "pages/Editor/QueryEditor/Table";
|
||||||
import { generateTemplateToUpdatePage } from "actions/pageActions";
|
import { generateTemplateToUpdatePage } from "actions/pageActions";
|
||||||
|
|
@ -44,98 +37,22 @@ import {
|
||||||
getHasCreatePagePermission,
|
getHasCreatePagePermission,
|
||||||
hasCreateDSActionPermissionInApp,
|
hasCreateDSActionPermissionInApp,
|
||||||
} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
||||||
import EmptyTableSVG from "assets/images/empty-table-in-display-preview.svg";
|
import RenderInterimDataState from "./RenderInterimDataState";
|
||||||
|
import {
|
||||||
const ViewModeSchemaContainer = styled.div`
|
ButtonContainer,
|
||||||
height: 100%;
|
DataWrapperContainer,
|
||||||
width: 100%;
|
DatasourceDataContainer,
|
||||||
display: flex;
|
DatasourceListContainer,
|
||||||
flex-direction: column;
|
StructureContainer,
|
||||||
`;
|
TableWrapper,
|
||||||
|
ViewModeSchemaContainer,
|
||||||
const DataWrapperContainer = styled.div`
|
} from "./SchemaViewModeCSS";
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StructureContainer = styled.div`
|
|
||||||
height: 100%;
|
|
||||||
width: 25%;
|
|
||||||
padding: var(--ads-v2-spaces-4) var(--ads-v2-spaces-5);
|
|
||||||
padding-left: var(--ads-v2-spaces-7);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
border-right: 1px solid var(--ads-v2-color-gray-300);
|
|
||||||
flex-shrink: 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const DatasourceDataContainer = styled.div`
|
|
||||||
height: 100%;
|
|
||||||
width: 75%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const DatasourceListContainer = styled.div`
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
div {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
div ~ div {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.t--schema-virtuoso-container {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SchemaStateMessageWrapper = styled.div`
|
|
||||||
width: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
img {
|
|
||||||
padding-bottom: var(--ads-v2-spaces-7);
|
|
||||||
}
|
|
||||||
span:first-child {
|
|
||||||
padding-bottom: var(--ads-v2-spaces-2);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ButtonContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-shrink: 0;
|
|
||||||
justify-content: flex-end;
|
|
||||||
border-top: 1px solid var(--ads-v2-color-gray-300);
|
|
||||||
padding: var(--ads-v2-spaces-4);
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
datasource: Datasource;
|
datasource: Datasource;
|
||||||
setDatasourceViewModeFlag: (viewMode: boolean) => void;
|
setDatasourceViewModeFlag: (viewMode: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderEmptyTablePage = () => {
|
|
||||||
return (
|
|
||||||
<SchemaStateMessageWrapper>
|
|
||||||
{/* Render empty table image */}
|
|
||||||
<img alt={createMessage(EMPTY_TABLE_SVG_ALT_TEXT)} src={EmptyTableSVG} />
|
|
||||||
{/* Show description below the image */}
|
|
||||||
{/* Show title */}
|
|
||||||
<Text style={{ fontWeight: "bold" }}>
|
|
||||||
{createMessage(EMPTY_TABLE_TITLE_TEXT)}
|
|
||||||
</Text>
|
|
||||||
{/* Show description */}
|
|
||||||
<Text>{createMessage(EMPTY_TABLE_MESSAGE_TEXT)}</Text>
|
|
||||||
</SchemaStateMessageWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DatasourceViewModeSchema = (props: Props) => {
|
const DatasourceViewModeSchema = (props: Props) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
|
@ -200,6 +117,7 @@ const DatasourceViewModeSchema = (props: Props) => {
|
||||||
if (
|
if (
|
||||||
isDatasourceStructureLoading ||
|
isDatasourceStructureLoading ||
|
||||||
!datasourceStructure ||
|
!datasourceStructure ||
|
||||||
|
!datasourceStructure.tables ||
|
||||||
(datasourceStructure && datasourceStructure?.error)
|
(datasourceStructure && datasourceStructure?.error)
|
||||||
) {
|
) {
|
||||||
setPreviewData([]);
|
setPreviewData([]);
|
||||||
|
|
@ -248,6 +166,10 @@ const DatasourceViewModeSchema = (props: Props) => {
|
||||||
}
|
}
|
||||||
}, [previewData]);
|
}, [previewData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setPreviewData([]);
|
||||||
|
}, [props.datasource.id]);
|
||||||
|
|
||||||
const onEntityTableClick = (table: string) => {
|
const onEntityTableClick = (table: string) => {
|
||||||
AnalyticsUtil.logEvent("DATASOURCE_PREVIEW_TABLE_CHANGE", {
|
AnalyticsUtil.logEvent("DATASOURCE_PREVIEW_TABLE_CHANGE", {
|
||||||
datasourceId: props.datasource.id,
|
datasourceId: props.datasource.id,
|
||||||
|
|
@ -304,10 +226,12 @@ const DatasourceViewModeSchema = (props: Props) => {
|
||||||
<ViewModeSchemaContainer>
|
<ViewModeSchemaContainer>
|
||||||
<DataWrapperContainer>
|
<DataWrapperContainer>
|
||||||
<StructureContainer>
|
<StructureContainer>
|
||||||
|
{props.datasource && (
|
||||||
<DatasourceStructureHeader
|
<DatasourceStructureHeader
|
||||||
datasourceId={props.datasource.id}
|
datasource={props.datasource}
|
||||||
paddingBottom
|
paddingBottom
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<DatasourceListContainer>
|
<DatasourceListContainer>
|
||||||
<DatasourceStructureList
|
<DatasourceStructureList
|
||||||
context={DatasourceStructureContext.DATASOURCE_VIEW_MODE}
|
context={DatasourceStructureContext.DATASOURCE_VIEW_MODE}
|
||||||
|
|
@ -322,31 +246,25 @@ const DatasourceViewModeSchema = (props: Props) => {
|
||||||
</StructureContainer>
|
</StructureContainer>
|
||||||
<DatasourceDataContainer>
|
<DatasourceDataContainer>
|
||||||
<TableWrapper>
|
<TableWrapper>
|
||||||
{isLoading && (
|
{(isLoading || isDatasourceStructureLoading) && (
|
||||||
<MessageWrapper>
|
<RenderInterimDataState state="LOADING" />
|
||||||
<Spinner size="md" />
|
|
||||||
<Text style={{ marginLeft: "8px" }}>
|
|
||||||
{createMessage(FETCHING_DATASOURCE_PREVIEW_DATA)}
|
|
||||||
</Text>
|
|
||||||
</MessageWrapper>
|
|
||||||
)}
|
)}
|
||||||
{!isLoading && failedFetchingPreviewData && (
|
{(!isLoading || !isDatasourceStructureLoading) &&
|
||||||
<MessageWrapper>
|
(failedFetchingPreviewData || previewDataError) && (
|
||||||
<Text color="var(--ads-color-red-500)">
|
<RenderInterimDataState state="FAILED" />
|
||||||
{createMessage(ERR_FETCHING_DATASOURCE_PREVIEW_DATA)}
|
|
||||||
</Text>
|
|
||||||
</MessageWrapper>
|
|
||||||
)}
|
)}
|
||||||
{!isLoading &&
|
{!isLoading &&
|
||||||
|
!isDatasourceStructureLoading &&
|
||||||
!failedFetchingPreviewData &&
|
!failedFetchingPreviewData &&
|
||||||
!previewDataError &&
|
!previewDataError &&
|
||||||
previewData?.length > 0 && <Table data={previewData} />}
|
previewData?.length > 0 && (
|
||||||
{!isLoading &&
|
<Table data={previewData} shouldResize={false} />
|
||||||
!failedFetchingPreviewData &&
|
|
||||||
!previewDataError &&
|
|
||||||
previewData?.length < 1 && (
|
|
||||||
<MessageWrapper>{renderEmptyTablePage()}</MessageWrapper>
|
|
||||||
)}
|
)}
|
||||||
|
{!isLoading &&
|
||||||
|
!isDatasourceStructureLoading &&
|
||||||
|
!failedFetchingPreviewData &&
|
||||||
|
!previewDataError &&
|
||||||
|
!previewData?.length && <RenderInterimDataState state="NODATA" />}
|
||||||
</TableWrapper>
|
</TableWrapper>
|
||||||
</DatasourceDataContainer>
|
</DatasourceDataContainer>
|
||||||
</DataWrapperContainer>
|
</DataWrapperContainer>
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,16 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import type { DropdownOption } from "design-system-old";
|
import type { DropdownOption } from "design-system-old";
|
||||||
import { Button, Option, Select, Spinner, Text } from "design-system";
|
import { Button, SearchInput } from "design-system";
|
||||||
import {
|
import {
|
||||||
useSheetData,
|
useSheetData,
|
||||||
useSheetsList,
|
useSheetsList,
|
||||||
useSpreadSheets,
|
useSpreadSheets,
|
||||||
} from "../GeneratePage/components/GeneratePageForm/hooks";
|
} from "../GeneratePage/components/GeneratePageForm/hooks";
|
||||||
import type {
|
import type { DropdownOptions } from "../GeneratePage/components/constants";
|
||||||
DatasourceTableDropdownOption,
|
import { DEFAULT_DROPDOWN_OPTION } from "../GeneratePage/components/constants";
|
||||||
DropdownOptions,
|
|
||||||
} from "../GeneratePage/components/constants";
|
|
||||||
import {
|
|
||||||
DEFAULT_DROPDOWN_OPTION,
|
|
||||||
DROPDOWN_DIMENSION,
|
|
||||||
} from "../GeneratePage/components/constants";
|
|
||||||
import { SelectWrapper } from "../GeneratePage/components/GeneratePageForm/styles";
|
|
||||||
import { isEmpty } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
import Table from "pages/Editor/QueryEditor/Table";
|
import Table from "pages/Editor/QueryEditor/Table";
|
||||||
import styled from "styled-components";
|
|
||||||
import {
|
import {
|
||||||
getCurrentApplicationId,
|
getCurrentApplicationId,
|
||||||
getPagePermissions,
|
getPagePermissions,
|
||||||
|
|
@ -26,10 +18,8 @@ import {
|
||||||
import { generateTemplateToUpdatePage } from "actions/pageActions";
|
import { generateTemplateToUpdatePage } from "actions/pageActions";
|
||||||
import {
|
import {
|
||||||
createMessage,
|
createMessage,
|
||||||
ERR_FETCHING_DATASOURCE_PREVIEW_DATA,
|
|
||||||
FETCHING_DATASOURCE_PREVIEW_DATA,
|
|
||||||
DATASOURCE_GENERATE_PAGE_BUTTON,
|
DATASOURCE_GENERATE_PAGE_BUTTON,
|
||||||
SCHEMA_PREVIEW_NO_DATA,
|
GSHEET_SEARCH_PLACEHOLDER,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
import { getCurrentApplication } from "@appsmith/selectors/applicationSelectors";
|
import { getCurrentApplication } from "@appsmith/selectors/applicationSelectors";
|
||||||
|
|
@ -41,76 +31,23 @@ import {
|
||||||
getHasCreatePagePermission,
|
getHasCreatePagePermission,
|
||||||
hasCreateDSActionPermissionInApp,
|
hasCreateDSActionPermissionInApp,
|
||||||
} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
||||||
|
import RenderInterimDataState from "./RenderInterimDataState";
|
||||||
export const MessageWrapper = styled.div`
|
import {
|
||||||
display: flex;
|
ButtonContainer,
|
||||||
align-items: center;
|
DataWrapperContainer,
|
||||||
justify-content: center;
|
DatasourceAttributesWrapper,
|
||||||
height: 200px;
|
DatasourceDataContainer,
|
||||||
`;
|
DatasourceListContainer,
|
||||||
|
DatasourceStructureSearchContainer,
|
||||||
export const TableWrapper = styled.div`
|
StructureContainer,
|
||||||
overflow-x: auto;
|
TableWrapper,
|
||||||
height: 100%;
|
ViewModeSchemaContainer,
|
||||||
&& > div {
|
} from "./SchemaViewModeCSS";
|
||||||
width: 100%;
|
import DatasourceStructureHeader from "./DatasourceStructureHeader";
|
||||||
}
|
import Entity from "../Explorer/Entity";
|
||||||
|
import DatasourceField from "./DatasourceField";
|
||||||
&& > ${MessageWrapper} {
|
import { setEntityCollapsibleState } from "actions/editorContextActions";
|
||||||
width: 100%;
|
import ItemLoadingIndicator from "./ItemLoadingIndicator";
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
&& .t--table-response {
|
|
||||||
border: none;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
&& .tableWrap {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
& .table {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
& .table div:first-of-type .tr {
|
|
||||||
background: var(--ads-v2-color-black-5);
|
|
||||||
border-right: none;
|
|
||||||
border-bottom: 1px solid var(--ads-v2-color-black-75);
|
|
||||||
}
|
|
||||||
&& .table div.tbody .tr {
|
|
||||||
background: var(--ads-v2-color-white);
|
|
||||||
border-bottom: 1px solid var(--ads-v2-color-black-75);
|
|
||||||
}
|
|
||||||
&& .table .td,
|
|
||||||
&& .table .th {
|
|
||||||
border-right: none;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
margin-right: 24px;
|
|
||||||
}
|
|
||||||
&& .tableWrap {
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SelectContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
.t--datasource-generate-page {
|
|
||||||
align-self: flex-end;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SelectListWrapper = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 278px;
|
|
||||||
margin-right: 16px;
|
|
||||||
& div {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
datasourceId: string;
|
datasourceId: string;
|
||||||
|
|
@ -122,25 +59,47 @@ const MAX_SHEET_ROWS_LENGTH = 12;
|
||||||
// ---------- GoogleSheetSchema Component -------
|
// ---------- GoogleSheetSchema Component -------
|
||||||
|
|
||||||
function GoogleSheetSchema(props: Props) {
|
function GoogleSheetSchema(props: Props) {
|
||||||
const [datasourceTableOptions, setSelectedDatasourceTableOptions] =
|
const [spreadsheetOptions, setSpreadsheetOptions] = useState<DropdownOptions>(
|
||||||
useState<DropdownOptions>([]);
|
[],
|
||||||
const [selectedDatasourceIsInvalid, setSelectedDatasourceIsInvalid] =
|
);
|
||||||
useState(false);
|
const [sheetOptions, setSheetOptions] = useState<DropdownOptions>([]);
|
||||||
const { fetchAllSpreadsheets, isFetchingSpreadsheets } = useSpreadSheets({
|
const [sheetData, setSheetData] = useState<any>([]);
|
||||||
setSelectedDatasourceTableOptions,
|
|
||||||
setSelectedDatasourceIsInvalid,
|
|
||||||
});
|
|
||||||
const {
|
|
||||||
failedFetchingSheetsList,
|
|
||||||
fetchSheetsList,
|
|
||||||
isFetchingSheetsList,
|
|
||||||
sheetsList,
|
|
||||||
} = useSheetsList();
|
|
||||||
const { fetchSheetData, isFetchingSheetData, sheetData } = useSheetData();
|
|
||||||
const [selectedSpreadsheet, setSelectedSpreadsheet] =
|
const [selectedSpreadsheet, setSelectedSpreadsheet] =
|
||||||
useState<DropdownOption>({});
|
useState<DropdownOption>({});
|
||||||
const [selectedSheet, setSelectedSheet] = useState<DropdownOption>({});
|
const [selectedSheet, setSelectedSheet] = useState<DropdownOption>({});
|
||||||
const [currentSheetData, setCurrentSheetData] = useState<any>();
|
const [searchString, setSearchString] = useState<string>("");
|
||||||
|
const [selectedDatasourceIsInvalid, setSelectedDatasourceIsInvalid] =
|
||||||
|
useState(false);
|
||||||
|
const { fetchAllSpreadsheets, isFetchingSpreadsheets } = useSpreadSheets({
|
||||||
|
setSelectedDatasourceTableOptions: setSpreadsheetOptions,
|
||||||
|
setSelectedDatasourceIsInvalid,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSearch = (value: string) => {
|
||||||
|
setSearchString(value.toLowerCase());
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent("GSHEET_SPREADSHEET_SEARCH", {
|
||||||
|
datasourceId: props.datasourceId,
|
||||||
|
pluginId: props.pluginId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSlicedSheetData = (response: DropdownOptions) => {
|
||||||
|
// Getting the top 12 rows as for experimentation we need to keep this number fixed for preview
|
||||||
|
AnalyticsUtil.logEvent("GSHEET_PREVIEW_DATA_SHOWN", {
|
||||||
|
datasourceId: props.datasourceId,
|
||||||
|
pluginId: props.pluginId,
|
||||||
|
});
|
||||||
|
setSheetData(response.slice(0, MAX_SHEET_ROWS_LENGTH));
|
||||||
|
};
|
||||||
|
|
||||||
|
const { failedFetchingSheetsList, fetchSheetsList, isFetchingSheetsList } =
|
||||||
|
useSheetsList({ setSheetOptions });
|
||||||
|
const { failedFetchingSheetData, fetchSheetData, isFetchingSheetData } =
|
||||||
|
useSheetData({
|
||||||
|
setSheetData: setSlicedSheetData,
|
||||||
|
});
|
||||||
|
|
||||||
const applicationId: string = useSelector(getCurrentApplicationId);
|
const applicationId: string = useSelector(getCurrentApplicationId);
|
||||||
const datasource = useSelector((state) =>
|
const datasource = useSelector((state) =>
|
||||||
getDatasource(state, props.datasourceId),
|
getDatasource(state, props.datasourceId),
|
||||||
|
|
@ -148,101 +107,176 @@ function GoogleSheetSchema(props: Props) {
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
// Fetch spreadsheets if datasourceId present
|
const scrollIntoView = (
|
||||||
useEffect(() => {
|
elementId: string,
|
||||||
|
containerId: string,
|
||||||
|
offset: number = 0,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const element = document.querySelector(elementId);
|
||||||
|
const container = document.querySelector(containerId);
|
||||||
|
if (element && container) {
|
||||||
|
const elementRect = element.getBoundingClientRect();
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const scrollTop = container.scrollTop;
|
||||||
|
|
||||||
|
const scrollAmount =
|
||||||
|
elementRect.top - containerRect.top + scrollTop + offset;
|
||||||
|
|
||||||
|
container.scrollTop = scrollAmount;
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const collapseAccordions = (
|
||||||
|
datasourceId: string,
|
||||||
|
spreadSheet?: string,
|
||||||
|
sheet?: string,
|
||||||
|
collapseSpreadsheet: boolean = true,
|
||||||
|
) => {
|
||||||
|
if (!isEmpty(spreadSheet) && !isEmpty(sheet)) {
|
||||||
|
dispatch(
|
||||||
|
setEntityCollapsibleState(
|
||||||
|
`${datasourceId}-${spreadSheet}-${sheet}`,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!isEmpty(spreadSheet) && collapseSpreadsheet) {
|
||||||
|
dispatch(
|
||||||
|
setEntityCollapsibleState(`${datasourceId}-${spreadSheet}`, false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectSpreadsheetAndToggle = (option: DropdownOption) => {
|
||||||
|
collapseAccordions(
|
||||||
|
datasource?.id || "",
|
||||||
|
selectedSpreadsheet.value,
|
||||||
|
selectedSheet.value,
|
||||||
|
);
|
||||||
|
setSelectedSheet(DEFAULT_DROPDOWN_OPTION);
|
||||||
|
setSheetOptions([]);
|
||||||
|
setSheetData(undefined);
|
||||||
|
dispatch(
|
||||||
|
setEntityCollapsibleState(`${datasource?.id}-${option.value}`, true),
|
||||||
|
);
|
||||||
|
scrollIntoView(
|
||||||
|
`#${CSS.escape(`entity-${datasource?.id}-${option.value}`)}`,
|
||||||
|
".t--gsheet-structure",
|
||||||
|
);
|
||||||
|
setSelectedSpreadsheet(option);
|
||||||
|
fetchSheetsList({
|
||||||
|
requestObject: {},
|
||||||
|
selectedDatasourceId: props.datasourceId,
|
||||||
|
selectedSpreadsheetUrl: option.value || "",
|
||||||
|
pluginId: props.pluginId || "",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectSheetAndToggle = (option: DropdownOption) => {
|
||||||
|
collapseAccordions(
|
||||||
|
datasource?.id || "",
|
||||||
|
selectedSpreadsheet.value,
|
||||||
|
selectedSheet.value,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
dispatch(
|
||||||
|
setEntityCollapsibleState(
|
||||||
|
`${datasource?.id}-${selectedSpreadsheet.value}-${option.value}`,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
scrollIntoView(
|
||||||
|
`#${CSS.escape(
|
||||||
|
`entity-${datasource?.id}-${selectedSpreadsheet.value}-${option.value}`,
|
||||||
|
)}`,
|
||||||
|
".t--gsheet-structure",
|
||||||
|
-30,
|
||||||
|
);
|
||||||
|
setSelectedSheet(option);
|
||||||
|
setSheetData(undefined);
|
||||||
|
fetchSheetData({
|
||||||
|
selectedDatasourceId: datasource?.id || "",
|
||||||
|
selectedSpreadsheetUrl: selectedSpreadsheet.value || "",
|
||||||
|
selectedSheetName: option.value || "",
|
||||||
|
pluginId: props.pluginId || "",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const refetchAllSpreadsheets = () => {
|
||||||
if (!!props.datasourceId && !!props.pluginId) {
|
if (!!props.datasourceId && !!props.pluginId) {
|
||||||
fetchAllSpreadsheets({
|
fetchAllSpreadsheets({
|
||||||
selectedDatasourceId: props.datasourceId,
|
selectedDatasourceId: props.datasourceId,
|
||||||
pluginId: props.pluginId || "",
|
pluginId: props.pluginId || "",
|
||||||
requestObject: {},
|
requestObject: {},
|
||||||
});
|
});
|
||||||
}
|
setSpreadsheetOptions([]);
|
||||||
}, [props.datasourceId, props.pluginId, dispatch]);
|
setSheetOptions([]);
|
||||||
|
setSheetData(undefined);
|
||||||
// When user selects a spreadsheet
|
setSelectedSpreadsheet((ss) => {
|
||||||
// Fetch all sheets inside that spreadsheet
|
setSelectedSheet((s) => {
|
||||||
useEffect(() => {
|
collapseAccordions(datasource?.id || "", ss.value, s.value);
|
||||||
if (!!props.datasourceId && !!props.pluginId && selectedSpreadsheet.value) {
|
return {};
|
||||||
setSelectedSheet(DEFAULT_DROPDOWN_OPTION);
|
});
|
||||||
setCurrentSheetData(undefined);
|
return {};
|
||||||
fetchSheetsList({
|
|
||||||
requestObject: {},
|
|
||||||
selectedDatasourceId: props.datasourceId,
|
|
||||||
selectedSpreadsheetUrl: selectedSpreadsheet.value,
|
|
||||||
pluginId: props.pluginId,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [
|
};
|
||||||
selectedSpreadsheet.value,
|
|
||||||
props.datasourceId,
|
|
||||||
props.pluginId,
|
|
||||||
dispatch,
|
|
||||||
fetchSheetsList,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// When user selects a sheet name
|
// Fetch spreadsheets if datasourceId present
|
||||||
// Fetch all sheet data inside that sheet
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!!props.datasourceId && !!props.pluginId && selectedSheet.value) {
|
fetchAllSpreadsheets({
|
||||||
setCurrentSheetData(undefined);
|
|
||||||
fetchSheetData({
|
|
||||||
selectedDatasourceId: props.datasourceId,
|
selectedDatasourceId: props.datasourceId,
|
||||||
selectedSpreadsheetUrl: selectedSpreadsheet.value || "",
|
|
||||||
selectedSheetName: selectedSheet.value,
|
|
||||||
pluginId: props.pluginId || "",
|
pluginId: props.pluginId || "",
|
||||||
|
requestObject: {},
|
||||||
});
|
});
|
||||||
}
|
}, [props.datasourceId, props.pluginId, dispatch]);
|
||||||
}, [
|
|
||||||
selectedSheet.value,
|
|
||||||
props.datasourceId,
|
|
||||||
props.pluginId,
|
|
||||||
dispatch,
|
|
||||||
fetchSheetData,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Set first spreadsheet as default option in the dropdown
|
// Set first spreadsheet as default option in the dropdown
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (spreadsheetOptions?.length > 0 && isEmpty(selectedSpreadsheet.value)) {
|
||||||
datasourceTableOptions?.length > 0 &&
|
selectSpreadsheetAndToggle(spreadsheetOptions[0]);
|
||||||
isEmpty(selectedSpreadsheet.value)
|
|
||||||
) {
|
|
||||||
setSelectedSpreadsheet(datasourceTableOptions[0]);
|
|
||||||
}
|
}
|
||||||
}, [selectedSpreadsheet, datasourceTableOptions]);
|
}, [selectedSpreadsheet, spreadsheetOptions]);
|
||||||
|
|
||||||
// Set first sheet as default option in the dropdown
|
// Set first sheet as default option in the dropdown
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
sheetsList?.length > 0 &&
|
sheetOptions?.length > 0 &&
|
||||||
isEmpty(selectedSheet.value) &&
|
isEmpty(selectedSheet.value) &&
|
||||||
!isFetchingSheetsList
|
!isFetchingSheetsList &&
|
||||||
|
!isFetchingSpreadsheets
|
||||||
) {
|
) {
|
||||||
setSelectedSheet(sheetsList[0]);
|
selectSheetAndToggle(sheetOptions[0]);
|
||||||
}
|
}
|
||||||
}, [selectedSheet, sheetsList, isFetchingSheetsList]);
|
}, [
|
||||||
|
selectedSheet,
|
||||||
|
sheetOptions,
|
||||||
|
isFetchingSheetsList,
|
||||||
|
isFetchingSpreadsheets,
|
||||||
|
]);
|
||||||
|
|
||||||
// Set current sheet data
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (sheetData) {
|
return () => {
|
||||||
// Getting the top 12 rows as for experimentation we need to keep this number fixed for preview
|
collapseAccordions(
|
||||||
AnalyticsUtil.logEvent("GSHEET_PREVIEW_DATA_SHOWN", {
|
datasource?.id || "",
|
||||||
datasourceId: props.datasourceId,
|
selectedSpreadsheet.value,
|
||||||
pluginId: props.pluginId,
|
selectedSheet.value,
|
||||||
});
|
);
|
||||||
setCurrentSheetData(sheetData.slice(0, MAX_SHEET_ROWS_LENGTH));
|
};
|
||||||
}
|
}, [datasource?.id]);
|
||||||
}, [sheetData]);
|
|
||||||
|
|
||||||
const onSelectSpreadsheet = (
|
const onSelectSpreadsheet = (
|
||||||
table: string | undefined,
|
table: string | undefined,
|
||||||
tableObj: DatasourceTableDropdownOption | undefined,
|
tableObj: DropdownOption | undefined,
|
||||||
) => {
|
) => {
|
||||||
if (table && tableObj) {
|
if (table && tableObj) {
|
||||||
AnalyticsUtil.logEvent("GSHEET_PREVIEW_SPREADSHEET_CHANGE", {
|
AnalyticsUtil.logEvent("GSHEET_PREVIEW_SPREADSHEET_CHANGE", {
|
||||||
datasourceId: props.datasourceId,
|
datasourceId: props.datasourceId,
|
||||||
pluginId: props.pluginId,
|
pluginId: props.pluginId,
|
||||||
});
|
});
|
||||||
setSelectedSpreadsheet(tableObj);
|
selectSpreadsheetAndToggle(tableObj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -255,25 +289,22 @@ function GoogleSheetSchema(props: Props) {
|
||||||
datasourceId: props.datasourceId,
|
datasourceId: props.datasourceId,
|
||||||
pluginId: props.pluginId,
|
pluginId: props.pluginId,
|
||||||
});
|
});
|
||||||
setSelectedSheet(sheetObj);
|
selectSheetAndToggle(sheetObj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isError = selectedDatasourceIsInvalid || failedFetchingSheetsList;
|
const isError =
|
||||||
|
selectedDatasourceIsInvalid ||
|
||||||
|
failedFetchingSheetsList ||
|
||||||
|
failedFetchingSheetData;
|
||||||
const isLoading =
|
const isLoading =
|
||||||
isFetchingSpreadsheets ||
|
isFetchingSpreadsheets || isFetchingSheetsList || isFetchingSheetData;
|
||||||
isFetchingSheetsList ||
|
|
||||||
isFetchingSheetData ||
|
|
||||||
(!isError && !currentSheetData);
|
|
||||||
|
|
||||||
const onGsheetGeneratePage = () => {
|
const onGsheetGeneratePage = () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
applicationId: applicationId || "",
|
applicationId: applicationId || "",
|
||||||
pageId: "",
|
pageId: "",
|
||||||
columns:
|
columns: sheetData?.length > 0 ? Object.keys(sheetData[0]) : [],
|
||||||
!!currentSheetData && currentSheetData.length > 0
|
|
||||||
? Object.keys(currentSheetData[0])
|
|
||||||
: [],
|
|
||||||
searchColumn: "",
|
searchColumn: "",
|
||||||
tableName: selectedSheet?.value || "",
|
tableName: selectedSheet?.value || "",
|
||||||
datasourceId: props.datasourceId || "",
|
datasourceId: props.datasourceId || "",
|
||||||
|
|
@ -312,76 +343,144 @@ function GoogleSheetSchema(props: Props) {
|
||||||
pagePermissions,
|
pagePermissions,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const refreshSpreadSheetButton = (option: DropdownOption) => (
|
||||||
|
<Button
|
||||||
|
isIconButton
|
||||||
|
kind="tertiary"
|
||||||
|
onClick={() => selectSpreadsheetAndToggle(option)}
|
||||||
|
startIcon="refresh"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const showGeneratePageBtn =
|
const showGeneratePageBtn =
|
||||||
!isLoading &&
|
!isLoading &&
|
||||||
!isError &&
|
!isError &&
|
||||||
currentSheetData &&
|
sheetData?.length &&
|
||||||
canCreateDatasourceActions &&
|
canCreateDatasourceActions &&
|
||||||
canCreatePages;
|
canCreatePages;
|
||||||
|
|
||||||
return (
|
const filteredSpreadsheets = spreadsheetOptions.filter(
|
||||||
<>
|
(option) => (option.label || "").toLowerCase()?.includes(searchString),
|
||||||
<SelectContainer>
|
|
||||||
{!!props.datasourceId ? (
|
|
||||||
<SelectListWrapper>
|
|
||||||
<Text>Spreadsheet</Text>
|
|
||||||
<SelectWrapper width={DROPDOWN_DIMENSION.WIDTH}>
|
|
||||||
<Select
|
|
||||||
data-testid="t--table-dropdown"
|
|
||||||
isLoading={isFetchingSpreadsheets}
|
|
||||||
onChange={(value: any) =>
|
|
||||||
onSelectSpreadsheet(
|
|
||||||
value,
|
|
||||||
datasourceTableOptions.find(
|
|
||||||
(table) => table.value === value,
|
|
||||||
) as DatasourceTableDropdownOption,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
value={selectedSpreadsheet}
|
|
||||||
>
|
|
||||||
{datasourceTableOptions.map((table) => {
|
|
||||||
return (
|
|
||||||
<Option key={table.value} value={table.value}>
|
|
||||||
{table.label}
|
|
||||||
</Option>
|
|
||||||
);
|
);
|
||||||
})}
|
|
||||||
</Select>
|
return (
|
||||||
</SelectWrapper>
|
<ViewModeSchemaContainer>
|
||||||
</SelectListWrapper>
|
<DataWrapperContainer>
|
||||||
) : null}
|
<StructureContainer>
|
||||||
{selectedSpreadsheet.value ? (
|
{datasource && (
|
||||||
<SelectListWrapper>
|
<DatasourceStructureHeader
|
||||||
<Text>Sheet</Text>
|
datasource={datasource}
|
||||||
<SelectWrapper width={DROPDOWN_DIMENSION.WIDTH}>
|
paddingBottom
|
||||||
<Select
|
refetchFn={refetchAllSpreadsheets}
|
||||||
data-testid="t--sheetName-dropdown"
|
/>
|
||||||
isLoading={isFetchingSheetsList}
|
)}
|
||||||
onChange={(value: any) =>
|
<DatasourceListContainer className="t--gsheet-structure">
|
||||||
onSelectSheetOption(
|
{!isFetchingSpreadsheets && (
|
||||||
value,
|
<DatasourceStructureSearchContainer className="t--gsheet-search-container">
|
||||||
sheetsList.find(
|
<SearchInput
|
||||||
(sheet: DropdownOption) => sheet.value === value,
|
className="datasourceStructure-search"
|
||||||
|
endIcon="close"
|
||||||
|
onChange={(value) => handleSearch(value)}
|
||||||
|
placeholder={createMessage(GSHEET_SEARCH_PLACEHOLDER)}
|
||||||
|
size={"sm"}
|
||||||
|
startIcon="search"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</DatasourceStructureSearchContainer>
|
||||||
|
)}
|
||||||
|
<div className="t--gsheet-structure-list">
|
||||||
|
{isFetchingSpreadsheets ? (
|
||||||
|
<ItemLoadingIndicator type="SPREADSHEET" />
|
||||||
|
) : (
|
||||||
|
filteredSpreadsheets.map((spreadsheet) => {
|
||||||
|
return (
|
||||||
|
<Entity
|
||||||
|
className="t--spreadsheet-structure"
|
||||||
|
customAddButton={refreshSpreadSheetButton(spreadsheet)}
|
||||||
|
entityId={`${datasource?.id}-${spreadsheet.value}`}
|
||||||
|
icon={null}
|
||||||
|
key={`${datasource?.id}-${spreadsheet.value}`}
|
||||||
|
name={spreadsheet.label as string}
|
||||||
|
onToggle={(isOpen) => {
|
||||||
|
isOpen &&
|
||||||
|
onSelectSpreadsheet(spreadsheet.value, spreadsheet);
|
||||||
|
}}
|
||||||
|
showAddButton={
|
||||||
|
spreadsheet.value === selectedSpreadsheet.value
|
||||||
|
}
|
||||||
|
step={0}
|
||||||
|
>
|
||||||
|
{isFetchingSheetsList ? (
|
||||||
|
<ItemLoadingIndicator type="SHEET" />
|
||||||
|
) : sheetOptions.length > 0 ? (
|
||||||
|
sheetOptions.map((sheet) => (
|
||||||
|
<Entity
|
||||||
|
className={`t--sheet-structure ${
|
||||||
|
sheet.value === selectedSheet.value
|
||||||
|
? "t--sheet-structure-active"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
entityId={`${datasource?.id}-${selectedSpreadsheet.value}-${sheet.value}`}
|
||||||
|
icon={null}
|
||||||
|
key={`${datasource?.id}-${selectedSpreadsheet.value}-${sheet.value}`}
|
||||||
|
name={sheet.label as string}
|
||||||
|
onToggle={(isOpen) => {
|
||||||
|
isOpen && onSelectSheetOption(sheet.value, sheet);
|
||||||
|
}}
|
||||||
|
step={1}
|
||||||
|
>
|
||||||
|
{selectedSheet.value === sheet.value ? (
|
||||||
|
isFetchingSheetData ? (
|
||||||
|
<ItemLoadingIndicator type="DATA" />
|
||||||
|
) : sheetData?.length > 0 ? (
|
||||||
|
<DatasourceAttributesWrapper>
|
||||||
|
{Object.keys(sheetData[0]).map(
|
||||||
|
(fieldValue, index) => (
|
||||||
|
<DatasourceField
|
||||||
|
field={{
|
||||||
|
name: fieldValue,
|
||||||
|
type: "string",
|
||||||
|
}}
|
||||||
|
key={`${fieldValue}${index}`}
|
||||||
|
step={2}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
)
|
)}
|
||||||
}
|
</DatasourceAttributesWrapper>
|
||||||
value={selectedSheet}
|
) : null
|
||||||
>
|
) : (
|
||||||
{sheetsList.map((sheet) => {
|
<ItemLoadingIndicator type="DATA" />
|
||||||
return (
|
)}
|
||||||
<Option key={sheet.label} value={sheet.label}>
|
</Entity>
|
||||||
{sheet?.label}
|
))
|
||||||
</Option>
|
) : (
|
||||||
|
<ItemLoadingIndicator type="SPREADSHEET" />
|
||||||
|
)}
|
||||||
|
</Entity>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
</Select>
|
)}
|
||||||
</SelectWrapper>
|
</div>
|
||||||
</SelectListWrapper>
|
</DatasourceListContainer>
|
||||||
) : null}
|
</StructureContainer>
|
||||||
|
<DatasourceDataContainer>
|
||||||
|
<TableWrapper>
|
||||||
|
{isLoading ? (
|
||||||
|
<RenderInterimDataState state="LOADING" />
|
||||||
|
) : isError ? (
|
||||||
|
<RenderInterimDataState state="FAILED" />
|
||||||
|
) : sheetData?.length > 0 ? (
|
||||||
|
<Table data={sheetData} shouldResize={false} />
|
||||||
|
) : (
|
||||||
|
<RenderInterimDataState state="NODATA" />
|
||||||
|
)}
|
||||||
|
</TableWrapper>
|
||||||
|
</DatasourceDataContainer>
|
||||||
|
</DataWrapperContainer>
|
||||||
{showGeneratePageBtn && (
|
{showGeneratePageBtn && (
|
||||||
|
<ButtonContainer>
|
||||||
<Button
|
<Button
|
||||||
className="t--datasource-generate-page"
|
className="t--datasource-generate-page"
|
||||||
isDisabled={!currentSheetData || currentSheetData?.length == 0}
|
|
||||||
key="datasource-generate-page"
|
key="datasource-generate-page"
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
onClick={onGsheetGeneratePage}
|
onClick={onGsheetGeneratePage}
|
||||||
|
|
@ -389,29 +488,9 @@ function GoogleSheetSchema(props: Props) {
|
||||||
>
|
>
|
||||||
{createMessage(DATASOURCE_GENERATE_PAGE_BUTTON)}
|
{createMessage(DATASOURCE_GENERATE_PAGE_BUTTON)}
|
||||||
</Button>
|
</Button>
|
||||||
|
</ButtonContainer>
|
||||||
)}
|
)}
|
||||||
</SelectContainer>
|
</ViewModeSchemaContainer>
|
||||||
<TableWrapper>
|
|
||||||
{isLoading ? (
|
|
||||||
<MessageWrapper>
|
|
||||||
<Spinner size="md" />
|
|
||||||
<Text style={{ marginLeft: "8px" }}>
|
|
||||||
{createMessage(FETCHING_DATASOURCE_PREVIEW_DATA)}
|
|
||||||
</Text>
|
|
||||||
</MessageWrapper>
|
|
||||||
) : isError ? (
|
|
||||||
<Text color="var(--ads-color-red-500)">
|
|
||||||
{createMessage(ERR_FETCHING_DATASOURCE_PREVIEW_DATA)}
|
|
||||||
</Text>
|
|
||||||
) : currentSheetData?.length > 0 ? (
|
|
||||||
<Table data={currentSheetData} />
|
|
||||||
) : (
|
|
||||||
<MessageWrapper>
|
|
||||||
<Text>{createMessage(SCHEMA_PREVIEW_NO_DATA)}</Text>
|
|
||||||
</MessageWrapper>
|
|
||||||
)}
|
|
||||||
</TableWrapper>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
createMessage,
|
||||||
|
GSHEET_DATA_LOADING,
|
||||||
|
GSHEET_SHEET_LOADING,
|
||||||
|
GSHEET_SPREADSHEET_LOADING,
|
||||||
|
LOADING_SCHEMA,
|
||||||
|
} from "@appsmith/constants/messages";
|
||||||
|
import { Spinner, Text } from "design-system";
|
||||||
|
import { MessageWrapper } from "./SchemaViewModeCSS";
|
||||||
|
|
||||||
|
type LoadingItemType = "SPREADSHEET" | "SHEET" | "DATA" | "SCHEMA";
|
||||||
|
|
||||||
|
const ItemLoadingIndicator = ({ type }: { type: LoadingItemType }) => {
|
||||||
|
return (
|
||||||
|
<MessageWrapper
|
||||||
|
className={`t--item-loading-indicator t--item-loading-indicator--${type.toLowerCase()}`}
|
||||||
|
>
|
||||||
|
<Spinner size="md" />
|
||||||
|
<Text style={{ marginLeft: "8px" }}>
|
||||||
|
{createMessage(
|
||||||
|
type === "SPREADSHEET"
|
||||||
|
? GSHEET_SPREADSHEET_LOADING
|
||||||
|
: type === "SHEET"
|
||||||
|
? GSHEET_SHEET_LOADING
|
||||||
|
: type === "SCHEMA"
|
||||||
|
? LOADING_SCHEMA
|
||||||
|
: GSHEET_DATA_LOADING,
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</MessageWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ItemLoadingIndicator;
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import React from "react";
|
||||||
|
import EmptyTableSVG from "assets/images/empty-table-in-display-preview.svg";
|
||||||
|
import { Spinner, Text } from "design-system";
|
||||||
|
import {
|
||||||
|
EMPTY_TABLE_TITLE_TEXT,
|
||||||
|
EMPTY_TABLE_MESSAGE_TEXT,
|
||||||
|
createMessage,
|
||||||
|
EMPTY_TABLE_SVG_ALT_TEXT,
|
||||||
|
LOADING_RECORDS_MESSAGE_TEXT,
|
||||||
|
LOADING_RECORDS_TITLE_TEXT,
|
||||||
|
ERR_FETCHING_DATASOURCE_PREVIEW_DATA,
|
||||||
|
} from "@appsmith/constants/messages";
|
||||||
|
import { MessageWrapper, SchemaStateMessageWrapper } from "./SchemaViewModeCSS";
|
||||||
|
|
||||||
|
type InterimState = "LOADING" | "NODATA" | "FAILED";
|
||||||
|
|
||||||
|
interface RenderInterimDataStateProps {
|
||||||
|
state: InterimState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RenderInterimDataState = ({ state }: RenderInterimDataStateProps) => {
|
||||||
|
return (
|
||||||
|
<MessageWrapper>
|
||||||
|
<SchemaStateMessageWrapper>
|
||||||
|
{state === "NODATA" ? (
|
||||||
|
<>
|
||||||
|
{/* Render empty table image */}
|
||||||
|
<img
|
||||||
|
alt={createMessage(EMPTY_TABLE_SVG_ALT_TEXT)}
|
||||||
|
src={EmptyTableSVG}
|
||||||
|
/>
|
||||||
|
{/* Show description below the image */}
|
||||||
|
{/* Show title */}
|
||||||
|
<Text style={{ fontWeight: "bold" }}>
|
||||||
|
{createMessage(EMPTY_TABLE_TITLE_TEXT)}
|
||||||
|
</Text>
|
||||||
|
{/* Show description */}
|
||||||
|
<Text>{createMessage(EMPTY_TABLE_MESSAGE_TEXT)}</Text>
|
||||||
|
</>
|
||||||
|
) : state === "FAILED" ? (
|
||||||
|
<Text color="var(--ads-color-red-500)">
|
||||||
|
{createMessage(ERR_FETCHING_DATASOURCE_PREVIEW_DATA)}
|
||||||
|
</Text>
|
||||||
|
) : state === "LOADING" ? (
|
||||||
|
<>
|
||||||
|
{/* Show spinner */}
|
||||||
|
<Spinner size="md" />
|
||||||
|
{/* Show title */}
|
||||||
|
<Text style={{ fontWeight: "bold" }}>
|
||||||
|
{createMessage(LOADING_RECORDS_TITLE_TEXT)}
|
||||||
|
</Text>
|
||||||
|
{/* Show description */}
|
||||||
|
<Text>{createMessage(LOADING_RECORDS_MESSAGE_TEXT)}</Text>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</SchemaStateMessageWrapper>
|
||||||
|
</MessageWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RenderInterimDataState;
|
||||||
212
app/client/src/pages/Editor/DatasourceInfo/SchemaViewModeCSS.tsx
Normal file
212
app/client/src/pages/Editor/DatasourceInfo/SchemaViewModeCSS.tsx
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
export const ViewModeSchemaContainer = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DataWrapperContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
.t--datasource-column:hover {
|
||||||
|
background: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StructureContainer = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
width: 25%;
|
||||||
|
padding: var(--ads-v2-spaces-4) 0 var(--ads-v2-spaces-4)
|
||||||
|
var(--ads-v2-spaces-5);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
border-right: 1px solid var(--ads-v2-color-gray-300);
|
||||||
|
flex-shrink: 0;
|
||||||
|
& > .datasourceStructure-header {
|
||||||
|
padding: 0 var(--ads-v2-spaces-5);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DatasourceDataContainer = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
width: 75%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DatasourceListContainer = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: var(--ads-v2-spaces-5);
|
||||||
|
.t--entity.datasourceStructure-datasource-view-mode {
|
||||||
|
padding-right: var(--ads-v2-spaces-5);
|
||||||
|
}
|
||||||
|
&.t--gsheet-structure {
|
||||||
|
padding-bottom: var(--ads-v2-spaces-8);
|
||||||
|
.t--gsheet-structure-list {
|
||||||
|
overflow-y: auto;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-grow: 0;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
|
.t--spreadsheet-structure > .t--entity-item {
|
||||||
|
font-weight: var(--ads-v2-font-weight-bold);
|
||||||
|
height: 36px;
|
||||||
|
padding-left: 0;
|
||||||
|
& .ads-v2-button__content:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.t--spreadsheet-structure {
|
||||||
|
padding-right: var(--ads-spaces-3);
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.t--sheet-structure:not(:last-of-type) {
|
||||||
|
padding-bottom: var(--ads-spaces-3);
|
||||||
|
}
|
||||||
|
.t--sheet-structure .t--datasource-column {
|
||||||
|
padding-top: var(--ads-spaces-1);
|
||||||
|
padding-bottom: var(--ads-spaces-1);
|
||||||
|
}
|
||||||
|
.t--sheet-structure > .t--entity-item {
|
||||||
|
color: var(--ads-v2-color-gray-600);
|
||||||
|
height: 36px;
|
||||||
|
padding-left: var(--ads-spaces-10);
|
||||||
|
}
|
||||||
|
.t--sheet-structure .t--datasource-column {
|
||||||
|
color: var(--ads-v2-color-gray-600);
|
||||||
|
height: 30px;
|
||||||
|
padding-left: var(--ads-spaces-10);
|
||||||
|
}
|
||||||
|
.t--sheet-structure.t--sheet-structure-active > .t--entity-item {
|
||||||
|
background: var(--ads-v2-color-gray-100);
|
||||||
|
}
|
||||||
|
.t--sheet-structure .t--entity-name {
|
||||||
|
padding: var(--ads-spaces-2) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.t--schema-virtuoso-container {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DatasourceAttributesWrapper = styled.div`
|
||||||
|
padding: var(--ads-spaces-1) 0 var(--ads-spaces-1) var(--ads-spaces-10);
|
||||||
|
.t--datasource-column > div > div:first-of-type {
|
||||||
|
padding-right: var(--ads-spaces-3);
|
||||||
|
}
|
||||||
|
.t--datasource-column > div > div:last-of-type {
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ButtonContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
border-top: 1px solid var(--ads-v2-color-gray-300);
|
||||||
|
padding: var(--ads-v2-spaces-4);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MessageWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
&.t--item-loading-indicator {
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: var(--ads-spaces-1) 0 var(--ads-spaces-1) var(--ads-spaces-11);
|
||||||
|
}
|
||||||
|
&.t--item-loading-indicator--spreadsheet,
|
||||||
|
&.t--item-loading-indicator--schema {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SchemaStateMessageWrapper = styled.div`
|
||||||
|
width: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
img {
|
||||||
|
padding-bottom: var(--ads-v2-spaces-7);
|
||||||
|
}
|
||||||
|
span:first-child {
|
||||||
|
padding-bottom: var(--ads-v2-spaces-2);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TableWrapper = styled.div`
|
||||||
|
overflow-x: auto;
|
||||||
|
height: 100%;
|
||||||
|
&& > div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&& > ${MessageWrapper} {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
&& .t--table-response {
|
||||||
|
border: none;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
&& .tableWrap {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
& .table {
|
||||||
|
background: none;
|
||||||
|
& > div:first-child {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
& .draggable-header {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .table div:first-of-type .tr {
|
||||||
|
background: var(--ads-v2-color-black-5);
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: 1px solid var(--ads-v2-color-black-75);
|
||||||
|
}
|
||||||
|
&& .table div.tbody .tr {
|
||||||
|
background: var(--ads-v2-color-white);
|
||||||
|
border-bottom: 1px solid var(--ads-v2-color-black-75);
|
||||||
|
}
|
||||||
|
&& .table .td,
|
||||||
|
&& .table .th {
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
&& .tableWrap {
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DatasourceStructureSearchContainer = styled.div`
|
||||||
|
margin: var(--ads-v2-spaces-3) 0 var(--ads-v2-spaces-4) 0;
|
||||||
|
background: white;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-right: var(--ads-v2-spaces-5);
|
||||||
|
&.t--gsheet-search-container {
|
||||||
|
margin-top: var(--ads-v2-spaces-4);
|
||||||
|
margin-bottom: var(--ads-v2-spaces-3);
|
||||||
|
}
|
||||||
|
&.t--search-container--query-editor {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
@ -272,7 +272,17 @@ export interface UseSheetDataReturn {
|
||||||
}: FetchSheetData) => void;
|
}: FetchSheetData) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSheetsList = (): UseSheetListReturn => {
|
export interface UseSheetListProps {
|
||||||
|
setSheetOptions?: (tableOptions: DropdownOptions) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseSheetDataProps {
|
||||||
|
setSheetData?: (tableOptions: DropdownOptions) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSheetsList = (
|
||||||
|
props: UseSheetListProps = {},
|
||||||
|
): UseSheetListReturn => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [sheetsList, setSheetsList] = useState<DropdownOption[]>([]);
|
const [sheetsList, setSheetsList] = useState<DropdownOption[]>([]);
|
||||||
|
|
@ -298,12 +308,13 @@ export const useSheetsList = (): UseSheetListReturn => {
|
||||||
const responseBody = payload.data.trigger;
|
const responseBody = payload.data.trigger;
|
||||||
if (Array.isArray(responseBody)) {
|
if (Array.isArray(responseBody)) {
|
||||||
setSheetsList(responseBody);
|
setSheetsList(responseBody);
|
||||||
|
props.setSheetOptions && props.setSheetOptions(responseBody);
|
||||||
} else {
|
} else {
|
||||||
// to handle error like "401 Unauthorized"
|
// to handle error like "401 Unauthorized"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setSheetsList, setIsFetchingSheetsList],
|
[setSheetsList, setIsFetchingSheetsList, props.setSheetOptions],
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchSheetsList = useCallback(
|
const fetchSheetsList = useCallback(
|
||||||
|
|
@ -314,6 +325,7 @@ export const useSheetsList = (): UseSheetListReturn => {
|
||||||
selectedSpreadsheetUrl,
|
selectedSpreadsheetUrl,
|
||||||
}: FetchSheetsList) => {
|
}: FetchSheetsList) => {
|
||||||
setSheetsList([]);
|
setSheetsList([]);
|
||||||
|
props.setSheetOptions && props.setSheetOptions([]);
|
||||||
setIsFetchingSheetsList(true);
|
setIsFetchingSheetsList(true);
|
||||||
setFailedFetchingSheetsList(false);
|
setFailedFetchingSheetsList(false);
|
||||||
const formattedRequestData = {
|
const formattedRequestData = {
|
||||||
|
|
@ -343,6 +355,7 @@ export const useSheetsList = (): UseSheetListReturn => {
|
||||||
onFetchAllSheetFailure,
|
onFetchAllSheetFailure,
|
||||||
setIsFetchingSheetsList,
|
setIsFetchingSheetsList,
|
||||||
setFailedFetchingSheetsList,
|
setFailedFetchingSheetsList,
|
||||||
|
props.setSheetOptions,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -354,7 +367,9 @@ export const useSheetsList = (): UseSheetListReturn => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSheetData = (): UseSheetDataReturn => {
|
export const useSheetData = (
|
||||||
|
props: UseSheetDataProps = {},
|
||||||
|
): UseSheetDataReturn => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [sheetData, setSheetData] = useState<any>([]);
|
const [sheetData, setSheetData] = useState<any>([]);
|
||||||
|
|
@ -380,12 +395,13 @@ export const useSheetData = (): UseSheetDataReturn => {
|
||||||
const responseBody = payload.data.trigger;
|
const responseBody = payload.data.trigger;
|
||||||
if (Array.isArray(responseBody)) {
|
if (Array.isArray(responseBody)) {
|
||||||
setSheetData(responseBody);
|
setSheetData(responseBody);
|
||||||
|
props.setSheetData && props.setSheetData(responseBody);
|
||||||
} else {
|
} else {
|
||||||
// to handle error like "401 Unauthorized"
|
// to handle error like "401 Unauthorized"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setSheetData, setIsFetchingSheetData],
|
[setSheetData, setIsFetchingSheetData, props.setSheetData],
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchSheetData = useCallback(
|
const fetchSheetData = useCallback(
|
||||||
|
|
@ -396,6 +412,7 @@ export const useSheetData = (): UseSheetDataReturn => {
|
||||||
selectedSpreadsheetUrl,
|
selectedSpreadsheetUrl,
|
||||||
}: FetchSheetData) => {
|
}: FetchSheetData) => {
|
||||||
setSheetData([]);
|
setSheetData([]);
|
||||||
|
props.setSheetData && props.setSheetData([]);
|
||||||
setIsFetchingSheetData(true);
|
setIsFetchingSheetData(true);
|
||||||
setFailedFetchingSheetData(false);
|
setFailedFetchingSheetData(false);
|
||||||
const formattedRequestData = {
|
const formattedRequestData = {
|
||||||
|
|
@ -428,6 +445,7 @@ export const useSheetData = (): UseSheetDataReturn => {
|
||||||
onFetchAllSheetFailure,
|
onFetchAllSheetFailure,
|
||||||
setIsFetchingSheetData,
|
setIsFetchingSheetData,
|
||||||
setFailedFetchingSheetData,
|
setFailedFetchingSheetData,
|
||||||
|
props.setSheetData,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import type { Theme } from "constants/DefaultTheme";
|
||||||
interface TableProps {
|
interface TableProps {
|
||||||
data: Record<string, any>[];
|
data: Record<string, any>[];
|
||||||
tableBodyHeight?: number;
|
tableBodyHeight?: number;
|
||||||
|
shouldResize?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TABLE_SIZES = {
|
const TABLE_SIZES = {
|
||||||
|
|
@ -208,6 +209,7 @@ export const getScrollBarWidth = (tableBodyEle: any, scrollBarW: number) => {
|
||||||
function Table(props: TableProps) {
|
function Table(props: TableProps) {
|
||||||
const theme = useTheme() as Theme;
|
const theme = useTheme() as Theme;
|
||||||
const tableBodyRef = React.useRef<HTMLElement>();
|
const tableBodyRef = React.useRef<HTMLElement>();
|
||||||
|
const { shouldResize = true } = props;
|
||||||
|
|
||||||
const data = React.useMemo(() => {
|
const data = React.useMemo(() => {
|
||||||
/* Check for length greater than 0 of rows returned from the query for mappings keys */
|
/* Check for length greater than 0 of rows returned from the query for mappings keys */
|
||||||
|
|
@ -346,12 +348,14 @@ function Table(props: TableProps) {
|
||||||
>
|
>
|
||||||
<AutoToolTipComponent title={column.render("Header")}>
|
<AutoToolTipComponent title={column.render("Header")}>
|
||||||
{column.render("Header")}
|
{column.render("Header")}
|
||||||
|
{shouldResize && (
|
||||||
<div
|
<div
|
||||||
{...column.getResizerProps()}
|
{...column.getResizerProps()}
|
||||||
className={`resizer ${
|
className={`resizer ${
|
||||||
column.isResizing ? "isResizing" : ""
|
column.isResizing ? "isResizing" : ""
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</AutoToolTipComponent>
|
</AutoToolTipComponent>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ import {
|
||||||
} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
|
||||||
import { selectFeatureFlagCheck } from "@appsmith/selectors/featureFlagsSelectors";
|
import { selectFeatureFlagCheck } from "@appsmith/selectors/featureFlagsSelectors";
|
||||||
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
||||||
import GoogleSheetSchema from "../DatasourceInfo/GoogleSheetSchema";
|
import DatasourceTabs from "../DatasourceInfo/DatasorceTabs";
|
||||||
|
|
||||||
const ViewModeContainer = styled.div`
|
const ViewModeContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -468,13 +468,77 @@ class DatasourceSaaSEditor extends JSONtoForm<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDatasourceInfo = () => {
|
renderDatasourceInfo = () => {
|
||||||
const { datasource, formConfig, viewMode } = this.props;
|
const {
|
||||||
|
datasource,
|
||||||
|
formConfig,
|
||||||
|
formData,
|
||||||
|
isPluginAuthFailed,
|
||||||
|
isPluginAuthorized,
|
||||||
|
pageId,
|
||||||
|
plugin,
|
||||||
|
pluginPackageName,
|
||||||
|
viewMode,
|
||||||
|
} = this.props;
|
||||||
|
const isGoogleSheetPlugin = isGoogleSheetPluginDS(pluginPackageName);
|
||||||
|
const authErrorMessage = getDatasourceErrorMessage(
|
||||||
|
formData,
|
||||||
|
plugin,
|
||||||
|
this.state.filterParams.id,
|
||||||
|
);
|
||||||
|
const hideDatasourceSection =
|
||||||
|
isGoogleSheetPlugin &&
|
||||||
|
!isPluginAuthorized &&
|
||||||
|
authErrorMessage == GSHEET_AUTHORIZATION_ERROR;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<ViewModeWrapper data-testid="t--ds-review-section">
|
||||||
|
{datasource &&
|
||||||
|
isGoogleSheetPlugin &&
|
||||||
|
isPluginAuthFailed &&
|
||||||
|
datasource.id !== TEMP_DATASOURCE_ID && (
|
||||||
|
<AuthMessage
|
||||||
|
actionType={ActionType.AUTHORIZE}
|
||||||
|
datasource={datasource}
|
||||||
|
description={authErrorMessage}
|
||||||
|
isInViewMode
|
||||||
|
pageId={pageId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!isNil(formConfig) && !isNil(datasource) && !hideDatasourceSection && (
|
||||||
<DatasourceInformation
|
<DatasourceInformation
|
||||||
config={formConfig[0]}
|
config={formConfig[0]}
|
||||||
datasource={datasource}
|
datasource={datasource}
|
||||||
viewMode={viewMode}
|
viewMode={viewMode}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</ViewModeWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
shouldShowTabs = () => {
|
||||||
|
const { datasource, isPluginAuthorized, pluginPackageName } = this.props;
|
||||||
|
|
||||||
|
const isGoogleSheetPlugin = isGoogleSheetPluginDS(pluginPackageName);
|
||||||
|
|
||||||
|
const isGoogleSheetSchemaAvailable =
|
||||||
|
isGoogleSheetPlugin && isPluginAuthorized;
|
||||||
|
|
||||||
|
return isGoogleSheetSchemaAvailable && datasource;
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTabsForViewMode = () => {
|
||||||
|
const { datasource } = this.props;
|
||||||
|
return (
|
||||||
|
<ViewModeContainer>
|
||||||
|
{this.shouldShowTabs() ? (
|
||||||
|
<DatasourceTabs
|
||||||
|
configChild={this.renderDatasourceInfo()}
|
||||||
|
datasource={datasource as Datasource}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
this.renderDatasourceInfo()
|
||||||
|
)}
|
||||||
|
</ViewModeContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -486,7 +550,6 @@ class DatasourceSaaSEditor extends JSONtoForm<Props, State> {
|
||||||
datasource,
|
datasource,
|
||||||
datasourceButtonConfiguration,
|
datasourceButtonConfiguration,
|
||||||
datasourceId,
|
datasourceId,
|
||||||
formConfig,
|
|
||||||
formData,
|
formData,
|
||||||
gsheetProjectID,
|
gsheetProjectID,
|
||||||
gsheetToken,
|
gsheetToken,
|
||||||
|
|
@ -526,13 +589,8 @@ class DatasourceSaaSEditor extends JSONtoForm<Props, State> {
|
||||||
GOOGLE_SHEETS_INFO_BANNER_MESSAGE,
|
GOOGLE_SHEETS_INFO_BANNER_MESSAGE,
|
||||||
);
|
);
|
||||||
|
|
||||||
const hideDatasourceSection =
|
const showingTabsOnViewMode =
|
||||||
isGoogleSheetPlugin &&
|
this.shouldShowTabs() && viewMode && !isInsideReconnectModal;
|
||||||
!isPluginAuthorized &&
|
|
||||||
authErrorMessage == GSHEET_AUTHORIZATION_ERROR;
|
|
||||||
|
|
||||||
const isGoogleSheetSchemaAvailable =
|
|
||||||
isGoogleSheetPlugin && isPluginAuthorized;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -546,6 +604,7 @@ class DatasourceSaaSEditor extends JSONtoForm<Props, State> {
|
||||||
isDeleting={isDeleting}
|
isDeleting={isDeleting}
|
||||||
isNewDatasource={createFlow}
|
isNewDatasource={createFlow}
|
||||||
isPluginAuthorized={isPluginAuthorized}
|
isPluginAuthorized={isPluginAuthorized}
|
||||||
|
noBottomBorder={showingTabsOnViewMode}
|
||||||
pluginImage={pluginImage}
|
pluginImage={pluginImage}
|
||||||
pluginName={plugin?.name || ""}
|
pluginName={plugin?.name || ""}
|
||||||
pluginType={plugin?.type || ""}
|
pluginType={plugin?.type || ""}
|
||||||
|
|
@ -554,7 +613,11 @@ class DatasourceSaaSEditor extends JSONtoForm<Props, State> {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ResizerMainContainer>
|
<ResizerMainContainer>
|
||||||
<ResizerContentContainer className="saas-form-resizer-content">
|
<ResizerContentContainer
|
||||||
|
className={`saas-form-resizer-content ${
|
||||||
|
showingTabsOnViewMode && "saas-form-resizer-content-show-tabs"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<DSEditorWrapper>
|
<DSEditorWrapper>
|
||||||
<DSDataFilter
|
<DSDataFilter
|
||||||
filterId={this.state.filterParams.id}
|
filterId={this.state.filterParams.id}
|
||||||
|
|
@ -601,35 +664,9 @@ class DatasourceSaaSEditor extends JSONtoForm<Props, State> {
|
||||||
{""}
|
{""}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{viewMode && !isInsideReconnectModal && (
|
{viewMode &&
|
||||||
<ViewModeContainer>
|
!isInsideReconnectModal &&
|
||||||
<ViewModeWrapper>
|
this.renderTabsForViewMode()}
|
||||||
{datasource &&
|
|
||||||
isGoogleSheetPlugin &&
|
|
||||||
isPluginAuthFailed ? (
|
|
||||||
<AuthMessage
|
|
||||||
actionType={ActionType.AUTHORIZE}
|
|
||||||
datasource={datasource}
|
|
||||||
description={authErrorMessage}
|
|
||||||
isInViewMode
|
|
||||||
pageId={pageId}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
{!isNil(formConfig) &&
|
|
||||||
!isNil(datasource) &&
|
|
||||||
!hideDatasourceSection
|
|
||||||
? this.renderDatasourceInfo()
|
|
||||||
: undefined}
|
|
||||||
</ViewModeWrapper>
|
|
||||||
{isGoogleSheetSchemaAvailable && datasource && (
|
|
||||||
<GoogleSheetSchema
|
|
||||||
datasourceId={datasourceId}
|
|
||||||
key={datasourceId}
|
|
||||||
pluginId={plugin?.id}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ViewModeContainer>
|
|
||||||
)}
|
|
||||||
</Form>
|
</Form>
|
||||||
{/* Render datasource form call-to-actions */}
|
{/* Render datasource form call-to-actions */}
|
||||||
{datasource && (
|
{datasource && (
|
||||||
|
|
|
||||||
|
|
@ -622,4 +622,5 @@ export const ColumnWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user