(null);
-
- useEffect(() => {
- if (active && newDatasourceRef.current) {
- scrollIntoView(newDatasourceRef.current, {
- behavior: "smooth",
- scrollMode: "always",
- block: "start",
- boundary: document.getElementById("new-integrations-wrapper"),
- });
- }
- }, [active]);
-
- const isAirgappedInstance = isAirgapped();
-
- return (
-
-
- {showMostPopularPlugins
- ? createMessage(CREATE_NEW_DATASOURCE_MOST_POPULAR_HEADER)
- : createMessage(CREATE_NEW_DATASOURCE_DATABASE_HEADER)}
-
-
-
- );
-}
-
-function CreateNewSaasIntegration({
- active,
- isCreating,
- isPremiumDatasourcesViewEnabled,
- pageId,
- showUnsupportedPluginDialog, // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
-}: any) {
- const newSaasAPIRef = useRef(null);
- const isMounted = useRef(false);
- const isAirgappedInstance = isAirgapped();
-
- useEffect(() => {
- if (active && newSaasAPIRef.current) {
- isMounted.current &&
- scrollIntoView(newSaasAPIRef.current, {
- behavior: "smooth",
- scrollMode: "always",
- block: "start",
- boundary: document.getElementById("new-integrations-wrapper"),
- });
- } else {
- isMounted.current = true;
- }
- }, [active]);
-
- return !isAirgappedInstance ? (
- <>
-
-
-
SaaS integrations
-
- {isPremiumDatasourcesViewEnabled && }
-
-
- >
- ) : null;
-}
-
-function CreateNewAIIntegration({
- isCreating,
- pageId,
- showUnsupportedPluginDialog, // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
-}: any) {
- const isAirgappedInstance = isAirgapped();
-
- return !isAirgappedInstance ? (
- <>
-
-
- >
- ) : null;
-}
-
interface CreateNewDatasourceScreenProps {
isCreating: boolean;
dataSources: Datasource[];
@@ -296,26 +100,24 @@ class CreateNewDatasourceTab extends React.Component<
if (!canCreateDatasource) return null;
- const mockDataSection =
- this.props.mockDatasources.length > 0 ? (
-
- ) : null;
+ const mockDataSectionVisible = this.props.mockDatasources.length > 0;
return (
<>
-
+
+
+
{dataSources.length === 0 && }
- {dataSources.length === 0 &&
- this.props.mockDatasources.length > 0 && (
- <>
- {mockDataSection}
-
- >
- )}
-
+ )}
+
-
-
-
-
-
-
+
+
- {dataSources.length > 0 && this.props.mockDatasources.length > 0 && (
- <>
-
- {mockDataSection}
- >
+ {dataSources.length > 0 && mockDataSectionVisible && (
+
)}
+
{isRequestNewIntegrationEnabled && }
{showDebugger && }
@@ -390,11 +198,15 @@ const mapStateToProps = (state: AppState) => {
userWorkspacePermissions,
);
- const isRequestNewIntegrationEnabled =
- !!featureFlags?.ab_request_new_integration_enabled;
+ const isRequestNewIntegrationEnabled = selectFeatureFlagCheck(
+ state,
+ FEATURE_FLAG.ab_request_new_integration_enabled,
+ );
- const isPremiumDatasourcesViewEnabled =
- !!featureFlags?.ab_premium_datasources_view_enabled;
+ const isPremiumDatasourcesViewEnabled = selectFeatureFlagCheck(
+ state,
+ FEATURE_FLAG.ab_premium_datasources_view_enabled,
+ );
return {
dataSources: getDatasources(state),
diff --git a/app/client/src/pages/Editor/IntegrationEditor/DatasourceHome.tsx b/app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx
similarity index 50%
rename from app/client/src/pages/Editor/IntegrationEditor/DatasourceHome.tsx
rename to app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx
index 047450a270..52584763d2 100644
--- a/app/client/src/pages/Editor/IntegrationEditor/DatasourceHome.tsx
+++ b/app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx
@@ -1,5 +1,4 @@
-import React, { type ReactNode } from "react";
-import styled from "styled-components";
+import React, { useEffect, useRef, type ReactNode } from "react";
import { connect } from "react-redux";
import { initialize } from "redux-form";
import {
@@ -21,18 +20,34 @@ import { getQueryParams } from "utils/URLUtils";
import { getGenerateCRUDEnabledPluginMap } from "ee/selectors/entitiesSelector";
import type { GenerateCRUDEnabledPluginMap } from "api/PluginApi";
import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil";
-import { getAssetUrl } from "ee/utils/airgapHelpers";
-import { ApiCard, API_ACTION, CardContentWrapper } from "./NewApi";
+import { getAssetUrl, isAirgapped } from "ee/utils/airgapHelpers";
+import { API_ACTION } from "./APIOrSaasPlugins";
import { PluginPackageName, PluginType } from "entities/Action";
import { Spinner } from "@appsmith/ads";
-import PlusLogo from "assets/images/Plus-logo.svg";
import {
createMessage,
CREATE_NEW_DATASOURCE_REST_API,
+ CREATE_NEW_DATASOURCE_MOST_POPULAR_HEADER,
+ CREATE_NEW_DATASOURCE_DATABASE_HEADER,
} from "ee/constants/messages";
import { createNewApiActionBasedOnEditorType } from "ee/actions/helpers";
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
import history from "utils/history";
+import {
+ DatasourceContainer,
+ DatasourceSection,
+ DatasourceSectionHeading,
+ StyledDivider,
+} from "./IntegrationStyledComponents";
+import DatasourceItem from "./DatasourceItem";
+import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants";
+import { useEditorType } from "ee/hooks";
+import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks";
+import scrollIntoView from "scroll-into-view-if-needed";
+import { pluginSearchSelector } from "./CreateNewDatasourceHeader";
+import type { CreateDatasourceConfig } from "api/DatasourcesApi";
+import type { Datasource } from "entities/Datasource";
+import type { AnyAction, Dispatch } from "redux";
// This function remove the given key from queryParams and return string
const removeQueryParams = (paramKeysToRemove: Array) => {
@@ -54,71 +69,7 @@ const removeQueryParams = (paramKeysToRemove: Array) => {
return "";
};
-const DatasourceHomePage = styled.div`
- .textBtn {
- justify-content: center;
- text-align: center;
- color: var(--ads-v2-color-fg);
- font-weight: 400;
- text-decoration: none !important;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- font-size: 16px;
- line-height: 24px;
- letter-spacing: -0.24px;
- margin: 0;
- }
-`;
-
-const DatasourceCardsContainer = styled.div`
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- gap: 16px;
- text-align: center;
- min-width: 150px;
- border-radius: 4px;
- align-items: center;
-`;
-
-const DatasourceCard = styled.div`
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 64px;
- border-radius: var(--ads-v2-border-radius);
- &:hover {
- background: var(--ads-v2-color-bg-subtle);
- cursor: pointer;
- }
-
- .dataSourceImage {
- height: 34px;
- width: auto;
- margin: 0 auto;
- max-width: 100%;
- }
-
- .cta {
- display: none;
- margin-right: 32px;
- }
-
- &:hover {
- .cta {
- display: flex;
- }
- }
-`;
-
-const DatasourceContentWrapper = styled.div`
- display: flex;
- align-items: center;
- gap: 13px;
- padding-left: 13.5px;
-`;
-
-interface DatasourceHomeScreenProps {
+interface DBOrMostPopularPluginsProps {
editorType: string;
editorId: string;
parentEntityId: string;
@@ -128,23 +79,14 @@ interface DatasourceHomeScreenProps {
};
showMostPopularPlugins?: boolean;
isCreating?: boolean;
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- showUnsupportedPluginDialog: (callback: any) => void;
- isAirgappedInstance?: boolean;
+ showUnsupportedPluginDialog: (callback: () => void) => void;
children?: ReactNode;
}
interface ReduxDispatchProps {
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- initializeForm: (data: Record) => void;
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- createDatasource: (data: any) => void;
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- createTempDatasource: (data: any) => void;
+ initializeForm: (data: Record) => void;
+ createDatasource: (data: CreateDatasourceConfig & Datasource) => void;
+ createTempDatasource: typeof createTempDatasourceFromForm;
createNewApiActionBasedOnEditorType: (
editorType: string,
editorId: string,
@@ -162,15 +104,35 @@ interface ReduxStateProps {
generateCRUDSupportedPlugin: GenerateCRUDEnabledPluginMap;
}
-type Props = ReduxStateProps & DatasourceHomeScreenProps & ReduxDispatchProps;
+interface CreateDBOrMostPopularPluginsProps {
+ location: {
+ search: string;
+ };
+ showMostPopularPlugins?: boolean;
+ isCreating?: boolean;
+ showUnsupportedPluginDialog: (callback: () => void) => void;
+ children?: ReactNode;
+ isOnboardingScreen?: boolean;
+ active?: boolean;
+ pageId: string;
+ addDivider?: boolean;
+}
-class DatasourceHomeScreen extends React.Component {
+type CreateDBOrMostPopularPluginsType = ReduxStateProps &
+ CreateDBOrMostPopularPluginsProps &
+ ReduxDispatchProps;
+
+type Props = DBOrMostPopularPluginsProps & CreateDBOrMostPopularPluginsType;
+
+class DBOrMostPopularPlugins extends React.Component {
goToCreateDatasource = (
pluginId: string,
pluginName: string,
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- params?: any,
+ params?: {
+ skipValidPluginCheck?: boolean;
+ packageName?: string;
+ type?: PluginType;
+ },
) => {
const {
currentApplication,
@@ -215,6 +177,7 @@ class DatasourceHomeScreen extends React.Component {
this.props.createTempDatasource({
pluginId,
+ type: params!.type!,
});
};
@@ -244,101 +207,140 @@ class DatasourceHomeScreen extends React.Component {
} = this.props;
return (
-
-
- {plugins.map((plugin, idx) => {
- return plugin.type === PluginType.API ? (
- !!showMostPopularPlugins ? (
- this.handleOnClick()}
- >
-
-
-
- {createMessage(CREATE_NEW_DATASOURCE_REST_API)}
-
-
- {/*@ts-expect-error Fix this the next time the file is edited*/}
- {isCreating && }
-
- ) : null
- ) : (
-
+ {plugins.map((plugin, idx) => {
+ return plugin.type === PluginType.API ? (
+ !!showMostPopularPlugins ? (
+ {
- AnalyticsUtil.logEvent("CREATE_DATA_SOURCE_CLICK", {
- appName: currentApplication?.name,
- pluginName: plugin.name,
- pluginPackageName: plugin.packageName,
- });
- this.goToCreateDatasource(plugin.id, plugin.name, {
- packageName: plugin.packageName,
- });
- }}
- >
-
-
- {plugin.name}
-
-
- );
- })}
-
-
+ name={createMessage(CREATE_NEW_DATASOURCE_REST_API)}
+ />
+ ) : null
+ ) : (
+ {
+ AnalyticsUtil.logEvent("CREATE_DATA_SOURCE_CLICK", {
+ appName: currentApplication?.name,
+ pluginName: plugin.name,
+ pluginPackageName: plugin.packageName,
+ });
+ this.goToCreateDatasource(plugin.id, plugin.name, {
+ packageName: plugin.packageName,
+ type: plugin.type,
+ });
+ }}
+ icon={getAssetUrl(pluginImages[plugin.id])}
+ key={`${plugin.id}_${idx}`}
+ name={plugin.name}
+ rightSibling={
+ isCreating &&
+ }
+ />
+ );
+ })}
+
);
}
}
+function CreateDBOrMostPopularPlugins(props: CreateDBOrMostPopularPluginsType) {
+ const editorType = useEditorType(location.pathname);
+ const { editorId, parentEntityId, parentEntityType } =
+ useParentEntityInfo(editorType);
+ const newDatasourceRef = useRef(null);
+
+ useEffect(() => {
+ if (props.active && newDatasourceRef.current) {
+ scrollIntoView(newDatasourceRef.current, {
+ behavior: "smooth",
+ scrollMode: "always",
+ block: "start",
+ boundary: document.getElementById("new-integrations-wrapper"),
+ });
+ }
+ }, [props.active]);
+
+ if (props.plugins.length === 0) return null;
+
+ return (
+ <>
+ {props.addDivider && }
+
+
+ {props.showMostPopularPlugins
+ ? createMessage(CREATE_NEW_DATASOURCE_MOST_POPULAR_HEADER)
+ : createMessage(CREATE_NEW_DATASOURCE_DATABASE_HEADER)}
+
+
+
+ >
+ );
+}
+
const mapStateToProps = (
state: AppState,
- props: { showMostPopularPlugins?: boolean; isAirgappedInstance?: boolean },
+ props: {
+ active?: boolean;
+ pageId: string;
+ showMostPopularPlugins?: boolean;
+ isOnboardingScreen?: boolean;
+ isCreating?: boolean;
+ },
) => {
const { datasources } = state.entities;
const mostPopularPlugins = getMostPopularPlugins(state);
- const filteredMostPopularPlugins: Plugin[] = !!props?.isAirgappedInstance
+ const isAirgappedInstance = isAirgapped();
+ const searchedPlugin = (
+ pluginSearchSelector(state, "search") || ""
+ ).toLocaleLowerCase();
+ const filteredMostPopularPlugins: Plugin[] = !!isAirgappedInstance
? mostPopularPlugins.filter(
(plugin: Plugin) =>
plugin?.packageName !== PluginPackageName.GOOGLE_SHEETS,
)
: mostPopularPlugins;
+ let plugins = !!props?.showMostPopularPlugins
+ ? filteredMostPopularPlugins
+ : getDBPlugins(state);
+
+ plugins = plugins.filter((plugin) =>
+ plugin.name.toLocaleLowerCase().includes(searchedPlugin),
+ );
+
return {
pluginImages: getPluginImages(state),
- plugins: !!props?.showMostPopularPlugins
- ? filteredMostPopularPlugins
- : getDBPlugins(state),
+ plugins,
currentApplication: getCurrentApplication(state),
isSaving: datasources.loading,
generateCRUDSupportedPlugin: getGenerateCRUDEnabledPluginMap(state),
};
};
-// TODO: Fix this the next time the file is edited
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-const mapDispatchToProps = (dispatch: any) => {
+const mapDispatchToProps = (dispatch: Dispatch) => {
return {
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- initializeForm: (data: Record) =>
+ initializeForm: (data: Record) =>
dispatch(initialize(DATASOURCE_DB_FORM, data)),
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- createDatasource: (data: any) => dispatch(createDatasourceFromForm(data)),
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- createTempDatasource: (data: any) =>
+ createDatasource: (data: CreateDatasourceConfig & Datasource) =>
+ dispatch(createDatasourceFromForm(data)),
+ createTempDatasource: (data: { pluginId: string; type: PluginType }) =>
dispatch(createTempDatasourceFromForm(data)),
createNewApiActionBasedOnEditorType: (
editorType: string,
@@ -362,4 +364,4 @@ const mapDispatchToProps = (dispatch: any) => {
export default connect(
mapStateToProps,
mapDispatchToProps,
-)(DatasourceHomeScreen);
+)(CreateDBOrMostPopularPlugins);
diff --git a/app/client/src/pages/Editor/IntegrationEditor/DatasourceItem.tsx b/app/client/src/pages/Editor/IntegrationEditor/DatasourceItem.tsx
new file mode 100644
index 0000000000..698d6c7ce9
--- /dev/null
+++ b/app/client/src/pages/Editor/IntegrationEditor/DatasourceItem.tsx
@@ -0,0 +1,64 @@
+import React, { type ReactNode } from "react";
+import {
+ DatasourceCard,
+ DatasourceDescription,
+ DatasourceImage,
+ DatasourceName,
+ DatasourceNameWrapper,
+} from "./IntegrationStyledComponents";
+
+interface DatasourceItem {
+ className?: string;
+ name: string;
+ icon: string;
+ description?: string;
+ handleOnClick: () => unknown;
+ rightSibling?: ReactNode;
+ dataNameTestId?: string;
+ dataCardTestId?: string;
+ dataCardWrapperTestId?: string;
+ dataCardDescriptionTestId?: string;
+ dataCardImageTestId?: string;
+}
+
+export default function DatasourceItem({
+ className = "",
+ dataCardDescriptionTestId = "datasource-description",
+ dataCardImageTestId = "datasource-image",
+ dataCardTestId = "datasource-card",
+ dataCardWrapperTestId = "datasource-content-wrapper",
+ dataNameTestId = "datasource-name",
+ description,
+ handleOnClick,
+ icon,
+ name,
+ rightSibling,
+}: DatasourceItem) {
+ return (
+
+
+
+
+ {name}
+
+
+ {description}
+
+
+ {rightSibling}
+
+ );
+}
diff --git a/app/client/src/pages/Editor/IntegrationEditor/EmptySearchedPlugins.tsx b/app/client/src/pages/Editor/IntegrationEditor/EmptySearchedPlugins.tsx
new file mode 100644
index 0000000000..e035d2bd7f
--- /dev/null
+++ b/app/client/src/pages/Editor/IntegrationEditor/EmptySearchedPlugins.tsx
@@ -0,0 +1,61 @@
+import React from "react";
+import { Flex, Text } from "@appsmith/ads";
+import { getAssetUrl } from "ee/utils/airgapHelpers";
+import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants";
+import {
+ CREATE_NEW_DATASOURCE_AUTHENTICATED_REST_API,
+ createMessage,
+ EMPTY_SEARCH_DATASOURCES_DESCRIPTION,
+ EMPTY_SEARCH_DATASOURCES_TITLE,
+} from "ee/constants/messages";
+import { useSelector } from "react-redux";
+import { pluginSearchSelector } from "./CreateNewDatasourceHeader";
+import { getPlugins } from "ee/selectors/entitiesSelector";
+import { PREMIUM_INTEGRATIONS } from "./PremiumDatasources/Constants";
+import styled from "styled-components";
+
+const EmptyImage = styled.img`
+ margin-bottom: var(--ads-v2-spaces-6);
+ width: 96px;
+`;
+
+export default function EmptySearchedPlugins({
+ isPremiumDatasourcesViewEnabled,
+}: {
+ isPremiumDatasourcesViewEnabled: boolean;
+}) {
+ let searchedPlugin = useSelector((state) =>
+ pluginSearchSelector(state, "search"),
+ );
+
+ searchedPlugin = (searchedPlugin || "").toLocaleLowerCase();
+ const plugins = useSelector(getPlugins);
+ let searchedItems = plugins.some((p) =>
+ p.name.toLocaleLowerCase().includes(searchedPlugin),
+ );
+
+ searchedItems =
+ searchedItems ||
+ createMessage(CREATE_NEW_DATASOURCE_AUTHENTICATED_REST_API)
+ .toLocaleLowerCase()
+ .includes(searchedPlugin) ||
+ (isPremiumDatasourcesViewEnabled &&
+ PREMIUM_INTEGRATIONS.some((p) =>
+ p.name.toLocaleLowerCase().includes(searchedPlugin),
+ ));
+
+ if (searchedItems) return null;
+
+ return (
+
+
+
+ {createMessage(EMPTY_SEARCH_DATASOURCES_TITLE)}
+
+ {createMessage(EMPTY_SEARCH_DATASOURCES_DESCRIPTION)}
+
+ );
+}
diff --git a/app/client/src/pages/Editor/IntegrationEditor/IntegrationStyledComponents.tsx b/app/client/src/pages/Editor/IntegrationEditor/IntegrationStyledComponents.tsx
new file mode 100644
index 0000000000..1c23de9d1d
--- /dev/null
+++ b/app/client/src/pages/Editor/IntegrationEditor/IntegrationStyledComponents.tsx
@@ -0,0 +1,73 @@
+import { Divider, Text } from "@appsmith/ads";
+import styled from "styled-components";
+
+export const StyledDivider = styled(Divider)`
+ margin-bottom: var(--ads-spaces-7);
+ border-color: var(--ads-v2-color-bg-muted);
+`;
+
+export const DatasourceSection = styled.div`
+ gap: var(--ads-v2-spaces-5);
+ display: flex;
+ flex-direction: column;
+`;
+
+export const DatasourceSectionHeading = styled(Text)`
+ font-size: var(--ads-v2-font-size-10);
+`;
+
+export const DatasourceContainer = styled.div`
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(218.25px, 1fr));
+ gap: var(--ads-v2-spaces-5);
+ min-width: 150px;
+ border-radius: 4px;
+ align-items: center;
+`;
+
+export const DatasourceCard = styled.div`
+ display: flex;
+ align-items: center;
+ gap: var(--ads-v2-spaces-4);
+ padding: var(--ads-v2-spaces-4);
+ cursor: pointer;
+ border-radius: var(--ads-v2-border-radius);
+ .cta {
+ display: none;
+ margin-right: var(--ads-v2-spaces-9);
+ }
+
+ &:hover {
+ background-color: var(--ads-v2-color-bg-subtle);
+ .cta {
+ display: flex;
+ }
+ }
+`;
+
+export const DatasourceImage = styled.img`
+ height: 34px;
+ width: auto;
+ max-width: 100%;
+ flex-shrink: 0;
+`;
+
+export const DatasourceNameWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+`;
+
+export const DatasourceName = styled(Text)`
+ font-size: var(--ads-v2-font-size-6);
+ font-weight: var(--ads-v2-font-weight-normal);
+ line-height: var(--ads-v2-line-height-4);
+ color: var(--ads-v2-color-fg);
+`;
+
+export const DatasourceDescription = styled.div`
+ color: var(--ads-v2-color-fg-muted);
+ font-size: var(--ads-v2-font-size-3);
+ font-weight: var(--ads-v2-font-weight-normal);
+ line-height: var(--ads-v2-line-height-2);
+`;
diff --git a/app/client/src/pages/Editor/IntegrationEditor/MockDataSources.tsx b/app/client/src/pages/Editor/IntegrationEditor/MockDataSources.tsx
index a9eee513e6..4acceb548c 100644
--- a/app/client/src/pages/Editor/IntegrationEditor/MockDataSources.tsx
+++ b/app/client/src/pages/Editor/IntegrationEditor/MockDataSources.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import styled from "styled-components";
import { useDispatch, useSelector } from "react-redux";
import type { MockDatasource } from "entities/Datasource";
import { getPluginImages } from "ee/selectors/entitiesSelector";
@@ -10,90 +9,27 @@ import type { AppState } from "ee/reducers";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { getAssetUrl } from "ee/utils/airgapHelpers";
import { DatasourceCreateEntryPoints } from "constants/Datasource";
-
-const MockDataSourceWrapper = styled.div`
- overflow: auto;
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- gap: 16px;
- min-width: 150px;
- align-items: center;
- margin-top: 8px;
-`;
-
-const Description = styled.div`
- color: var(--ads-v2-color-fg-muted);
- font-size: 13px;
- font-weight: 400;
- line-height: 17px;
- letter-spacing: -0.24px;
-`;
-
-function MockDataSources(props: { mockDatasources: MockDatasource[] }) {
- const workspaceId = useSelector(getCurrentWorkspaceId);
-
- return (
-
- {props.mockDatasources.map((datasource: MockDatasource, idx) => {
- return (
-
- );
- })}
-
- );
-}
-
-export default MockDataSources;
-
-const CardWrapper = styled.div`
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 64px;
- border-radius: var(--ads-v2-border-radius);
- &:hover {
- background-color: var(--ads-v2-color-bg-subtle);
- cursor: pointer;
- }
-`;
-
-const DatasourceImage = styled.img`
- height: 34px;
- width: auto;
- margin: 0 auto;
- max-width: 100%;
-`;
-
-const DatasourceName = styled.span`
- font-size: 16px;
- font-weight: 400;
- line-height: 24px;
- letter-spacing: -0.24px;
- color: var(--ads-v2-color-fg);
-`;
-
-const DatasourceCardHeader = styled.div`
- display: flex;
- align-items: center;
- gap: 13px;
- padding-left: 13.5px;
-`;
-
-const DatasourceNameWrapper = styled.div`
- display: flex;
- flex-direction: column;
-`;
+import {
+ DatasourceContainer,
+ DatasourceSection,
+ DatasourceSectionHeading,
+ StyledDivider,
+} from "./IntegrationStyledComponents";
+import DatasourceItem from "./DatasourceItem";
+import {
+ createMessage,
+ SAMPLE_DATASOURCE_SUBHEADING,
+ SAMPLE_DATASOURCES,
+} from "ee/constants/messages";
+import { pluginSearchSelector } from "./CreateNewDatasourceHeader";
+import { Flex, Text } from "@appsmith/ads";
interface MockDatasourceCardProps {
datasource: MockDatasource;
workspaceId: string;
}
-export function MockDatasourceCard(props: MockDatasourceCardProps) {
+function MockDatasourceCard(props: MockDatasourceCardProps) {
const { datasource, workspaceId } = props;
const dispatch = useDispatch();
const pluginImages = useSelector(getPluginImages);
@@ -137,22 +73,67 @@ export function MockDatasourceCard(props: MockDatasourceCardProps) {
};
return (
-
-
-
-
-
- {datasource.name}
-
-
- {datasource.description}
-
-
-
-
+
+ );
+}
+
+interface MockDataSourcesProps {
+ mockDatasources: MockDatasource[];
+ preDivider?: boolean;
+ postDivider?: boolean;
+}
+
+export default function MockDataSources({
+ mockDatasources,
+ postDivider,
+ preDivider,
+}: MockDataSourcesProps) {
+ const workspaceId = useSelector(getCurrentWorkspaceId);
+ let searchedPlugin = useSelector((state) =>
+ pluginSearchSelector(state, "search"),
+ );
+
+ searchedPlugin = (searchedPlugin || "").toLocaleLowerCase();
+
+ const filteredDatasources = mockDatasources.filter((m) =>
+ m.name.toLocaleLowerCase().includes(searchedPlugin),
+ );
+
+ if (filteredDatasources.length === 0) return null;
+
+ return (
+ <>
+ {preDivider && }
+
+
+
+ {createMessage(SAMPLE_DATASOURCES)}
+
+ {createMessage(SAMPLE_DATASOURCE_SUBHEADING)}
+
+
+ {filteredDatasources.map((datasource: MockDatasource, idx) => {
+ return (
+
+ );
+ })}
+
+
+ {postDivider && }
+ >
);
}
diff --git a/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx b/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx
deleted file mode 100644
index 3326d90761..0000000000
--- a/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx
+++ /dev/null
@@ -1,350 +0,0 @@
-import React, { useCallback, useEffect, useState, type ReactNode } from "react";
-import { connect, useSelector } from "react-redux";
-import styled from "styled-components";
-import {
- createDatasourceFromForm,
- createTempDatasourceFromForm,
-} from "actions/datasourceActions";
-import type { AppState } from "ee/reducers";
-import PlusLogo from "assets/images/Plus-logo.svg";
-import GraphQLLogo from "assets/images/Graphql-logo.svg";
-import type { GenerateCRUDEnabledPluginMap, Plugin } from "api/PluginApi";
-import AnalyticsUtil from "ee/utils/AnalyticsUtil";
-import { PluginPackageName, PluginType } from "entities/Action";
-import { getQueryParams } from "utils/URLUtils";
-import { getGenerateCRUDEnabledPluginMap } from "ee/selectors/entitiesSelector";
-import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil";
-import { getAssetUrl } from "ee/utils/airgapHelpers";
-import { Spinner } from "@appsmith/ads";
-import { useEditorType } from "ee/hooks";
-import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks";
-import { createNewApiActionBasedOnEditorType } from "ee/actions/helpers";
-import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
-
-export const StyledContainer = styled.div`
- flex: 1;
- margin-top: 8px;
- .textBtn {
- font-size: 16px;
- line-height: 24px;
- margin: 0;
- justify-content: center;
- text-align: center;
- letter-spacing: -0.24px;
- color: var(--ads-v2-color-fg);
- font-weight: 400;
- text-decoration: none !important;
- flex-wrap: wrap;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- @media (min-width: 2500px) {
- .textBtn {
- font-size: 18px;
- }
- }
- @media (min-width: 2500px) {
- .eachCard {
- width: 240px;
- height: 200px;
- }
- .apiImage {
- margin-top: 25px;
- margin-bottom: 20px;
- height: 80px;
- }
- .curlImage {
- width: 100px;
- }
- .createIcon {
- height: 70px;
- }
- }
-`;
-
-export const ApiCardsContainer = styled.div`
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- gap: 16px;
- text-align: center;
- min-width: 150px;
- border-radius: 4px;
- align-items: center;
-
- .create-new-api {
- &:hover {
- cursor: pointer;
- }
- }
-`;
-
-export const ApiCard = styled.div`
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 64px;
- border-radius: var(--ads-v2-border-radius);
-
- &:hover {
- background-color: var(--ads-v2-color-bg-subtle);
- cursor: pointer;
- }
-
- .content-icon {
- height: 34px;
- width: auto;
- margin: 0 auto;
- max-width: 100%;
- }
-
- .cta {
- display: none;
- margin-right: 32px;
- }
-
- &:hover {
- .cta {
- display: flex;
- }
- }
-`;
-
-export const CardContentWrapper = styled.div`
- display: flex;
- align-items: center;
- gap: 13px;
- padding-left: 13.5px;
-`;
-
-interface ApiHomeScreenProps {
- location: {
- search: string;
- };
- pageId: string;
- plugins: Plugin[];
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- createDatasourceFromForm: (data: any) => void;
- isCreating: boolean;
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- showUnsupportedPluginDialog: (callback: any) => void;
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- createTempDatasourceFromForm: (data: any) => void;
- showSaasAPIs: boolean; // If this is true, only SaaS APIs will be shown
- createNewApiActionBasedOnEditorType: (
- editorType: string,
- editorId: string,
- parentEntityId: string,
- parentEntityType: ActionParentEntityTypeInterface,
- apiType: string,
- ) => void;
- isOnboardingScreen?: boolean;
- children?: ReactNode;
-}
-
-type Props = ApiHomeScreenProps;
-
-export const API_ACTION = {
- IMPORT_CURL: "IMPORT_CURL",
- CREATE_NEW_API: "CREATE_NEW_API",
- CREATE_NEW_GRAPHQL_API: "CREATE_NEW_GRAPHQL_API",
- CREATE_DATASOURCE_FORM: "CREATE_DATASOURCE_FORM",
- AUTH_API: "AUTH_API",
-};
-
-function NewApiScreen(props: Props) {
- const { isCreating, isOnboardingScreen, pageId, plugins, showSaasAPIs } =
- props;
- const editorType = useEditorType(location.pathname);
- const { editorId, parentEntityId, parentEntityType } =
- useParentEntityInfo(editorType);
- const generateCRUDSupportedPlugin: GenerateCRUDEnabledPluginMap = useSelector(
- getGenerateCRUDEnabledPluginMap,
- );
- const [authApiPlugin, setAuthAPiPlugin] = useState();
-
- useEffect(() => {
- const plugin = plugins.find((p) => p.name === "REST API");
-
- setAuthAPiPlugin(plugin);
- }, [plugins]);
-
- const handleCreateAuthApiDatasource = useCallback(() => {
- if (authApiPlugin) {
- AnalyticsUtil.logEvent("CREATE_DATA_SOURCE_AUTH_API_CLICK", {
- pluginId: authApiPlugin.id,
- });
- AnalyticsUtil.logEvent("CREATE_DATA_SOURCE_CLICK", {
- pluginName: authApiPlugin.name,
- pluginPackageName: authApiPlugin.packageName,
- });
- props.createTempDatasourceFromForm({
- pluginId: authApiPlugin.id,
- });
- }
- }, [authApiPlugin, props.createTempDatasourceFromForm]);
-
- const handleCreateNew = (source: string) => {
- AnalyticsUtil.logEvent("CREATE_DATA_SOURCE_CLICK", {
- source,
- });
- props.createNewApiActionBasedOnEditorType(
- editorType,
- editorId,
- // Set parentEntityId as (parentEntityId or if it is onboarding screen then set it as pageId) else empty string
- parentEntityId || (isOnboardingScreen && pageId) || "",
- parentEntityType,
- source === API_ACTION.CREATE_NEW_GRAPHQL_API
- ? PluginPackageName.GRAPHQL
- : PluginPackageName.REST_API,
- );
- };
-
- // On click of any API card, handleOnClick action should be called to check if user came from generate-page flow.
- // if yes then show UnsupportedDialog for the API which are not supported to generate CRUD page.
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const handleOnClick = (actionType: string, params?: any) => {
- const queryParams = getQueryParams();
- const isGeneratePageInitiator = getIsGeneratePageInitiator(
- queryParams.isGeneratePageMode,
- );
-
- if (
- isGeneratePageInitiator &&
- !params?.skipValidPluginCheck &&
- !generateCRUDSupportedPlugin[params?.pluginId]
- ) {
- // show modal informing user that this will break the generate flow.
- props?.showUnsupportedPluginDialog(() =>
- handleOnClick(actionType, { skipValidPluginCheck: true, ...params }),
- );
-
- return;
- }
-
- switch (actionType) {
- case API_ACTION.CREATE_NEW_API:
- case API_ACTION.CREATE_NEW_GRAPHQL_API:
- handleCreateNew(actionType);
- break;
- case API_ACTION.CREATE_DATASOURCE_FORM: {
- props.createTempDatasourceFromForm({
- pluginId: params.pluginId,
- type: params.type,
- });
- break;
- }
- case API_ACTION.AUTH_API: {
- handleCreateAuthApiDatasource();
- break;
- }
- default:
- }
- };
-
- // Api plugins with Graphql
- const API_PLUGINS = plugins.filter((p) =>
- !showSaasAPIs
- ? p.packageName === PluginPackageName.GRAPHQL
- : p.type === PluginType.SAAS ||
- p.type === PluginType.REMOTE ||
- p.type === PluginType.EXTERNAL_SAAS,
- );
-
- return (
-
-
- {!showSaasAPIs && (
- <>
- handleOnClick(API_ACTION.CREATE_NEW_API)}
- >
-
-
- REST API
-
- {/*@ts-expect-error Fix this the next time the file is edited*/}
- {isCreating && }
-
- handleOnClick(API_ACTION.CREATE_NEW_GRAPHQL_API)}
- >
-
-
- GraphQL API
-
-
- {authApiPlugin && (
- handleOnClick(API_ACTION.AUTH_API)}
- >
-
-
- Authenticated API
-
-
- )}
- >
- )}
- {API_PLUGINS.map((p) => (
- {
- AnalyticsUtil.logEvent("CREATE_DATA_SOURCE_CLICK", {
- pluginName: p.name,
- pluginPackageName: p.packageName,
- });
- handleOnClick(API_ACTION.CREATE_DATASOURCE_FORM, {
- pluginId: p.id,
- });
- }}
- >
-
-
- {p.name}
-
-
- ))}
- {props.children}
-
-
- );
-}
-
-const mapStateToProps = (state: AppState) => ({
- plugins: state.entities.plugins.list,
-});
-
-const mapDispatchToProps = {
- createDatasourceFromForm,
- createTempDatasourceFromForm,
- createNewApiActionBasedOnEditorType,
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(NewApiScreen);
diff --git a/app/client/src/pages/Editor/IntegrationEditor/NewQuery.tsx b/app/client/src/pages/Editor/IntegrationEditor/NewQuery.tsx
deleted file mode 100644
index 15ea740854..0000000000
--- a/app/client/src/pages/Editor/IntegrationEditor/NewQuery.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-import DataSourceHome from "./DatasourceHome";
-import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
-
-const QueryHomePage = styled.div`
- display: flex;
- flex-direction: column;
- margin-top: 8px;
- .sectionHeader {
- font-weight: ${(props) => props.theme.fontWeights[2]};
- font-size: ${(props) => props.theme.fontSizes[4]}px;
- margin-top: 10px;
- }
-`;
-
-interface QueryHomeScreenProps {
- editorId: string;
- editorType: string;
- parentEntityId: string;
- parentEntityType: ActionParentEntityTypeInterface;
- isCreating: boolean;
- location: {
- search: string;
- };
- showMostPopularPlugins?: boolean;
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- showUnsupportedPluginDialog: (callback: any) => void;
- isAirgappedInstance?: boolean;
-}
-
-class QueryHomeScreen extends React.Component {
- render() {
- const {
- editorId,
- editorType,
- isAirgappedInstance,
- isCreating,
- location,
- parentEntityId,
- parentEntityType,
- showMostPopularPlugins,
- showUnsupportedPluginDialog,
- } = this.props;
-
- return (
-
-
-
- );
- }
-}
-
-export default QueryHomeScreen;
diff --git a/app/client/src/constants/PremiumDatasourcesConstants.ts b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/Constants.ts
similarity index 77%
rename from app/client/src/constants/PremiumDatasourcesConstants.ts
rename to app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/Constants.ts
index dba0034d1a..ab1a78b51b 100644
--- a/app/client/src/constants/PremiumDatasourcesConstants.ts
+++ b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/Constants.ts
@@ -1,7 +1,7 @@
import { getAssetUrl } from "ee/utils/airgapHelpers";
-import { ASSETS_CDN_URL } from "./ThirdPartyConstants";
+import { ASSETS_CDN_URL } from "../../../../constants/ThirdPartyConstants";
-interface PremiumIntegration {
+export interface PremiumIntegration {
name: string;
icon: string;
}
@@ -13,7 +13,7 @@ export const PREMIUM_INTEGRATIONS: PremiumIntegration[] = [
},
{
name: "Salesforce",
- icon: getAssetUrl(`${ASSETS_CDN_URL}/salesforce-icon.png`),
+ icon: getAssetUrl(`${ASSETS_CDN_URL}/salesforce-image.png`),
},
{
name: "Slack",
diff --git a/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/ContactForm.tsx b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/ContactForm.tsx
index 63f265df3f..4989bb1541 100644
--- a/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/ContactForm.tsx
+++ b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/ContactForm.tsx
@@ -27,8 +27,8 @@ import {
handleLearnMoreClick,
handleSubmitEvent,
shouldLearnMoreButtonBeVisible,
-} from "utils/PremiumDatasourcesHelpers";
-import { PREMIUM_INTEGRATION_CONTACT_FORM } from "constants/PremiumDatasourcesConstants";
+} from "./Helpers";
+import { PREMIUM_INTEGRATION_CONTACT_FORM } from "./Constants";
const FormWrapper = styled.form`
display: flex;
diff --git a/app/client/src/utils/PremiumDatasourcesHelpers.ts b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/Helpers.ts
similarity index 97%
rename from app/client/src/utils/PremiumDatasourcesHelpers.ts
rename to app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/Helpers.ts
index ef33d6db3e..d4938be71b 100644
--- a/app/client/src/utils/PremiumDatasourcesHelpers.ts
+++ b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/Helpers.ts
@@ -1,4 +1,4 @@
-import { SCHEDULE_CALL_URL } from "constants/PremiumDatasourcesConstants";
+import { SCHEDULE_CALL_URL } from "./Constants";
import { createMessage, PREMIUM_DATASOURCES } from "ee/constants/messages";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { isRelevantEmail } from "utils/formhelpers";
diff --git a/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/index.tsx b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/index.tsx
index e3b52ff4e6..d585771198 100644
--- a/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/index.tsx
+++ b/app/client/src/pages/Editor/IntegrationEditor/PremiumDatasources/index.tsx
@@ -1,16 +1,13 @@
import React, { useState } from "react";
-import { ApiCard, CardContentWrapper } from "../NewApi";
import { getAssetUrl } from "ee/utils/airgapHelpers";
-import { Modal, ModalContent, Tag, Text } from "@appsmith/ads";
+import { Modal, ModalContent, Tag } from "@appsmith/ads";
import styled from "styled-components";
import ContactForm from "./ContactForm";
-import { PREMIUM_INTEGRATIONS } from "constants/PremiumDatasourcesConstants";
-import {
- getTagText,
- handlePremiumDatasourceClick,
-} from "utils/PremiumDatasourcesHelpers";
+import { getTagText, handlePremiumDatasourceClick } from "./Helpers";
import { isFreePlan } from "ee/selectors/tenantSelectors";
import { useSelector } from "react-redux";
+import DatasourceItem from "../DatasourceItem";
+import type { PremiumIntegration } from "./Constants";
const ModalContentWrapper = styled(ModalContent)`
max-width: 518px;
@@ -35,7 +32,9 @@ const PremiumTag = styled(Tag)<{ isBusinessOrEnterprise: boolean }>`
}
`;
-export default function PremiumDatasources() {
+export default function PremiumDatasources(props: {
+ plugins: PremiumIntegration[];
+}) {
const [selectedIntegration, setSelectedIntegration] = useState("");
const isFreePlanInstance = useSelector(isFreePlan);
const handleOnClick = (name: string) => {
@@ -51,23 +50,16 @@ export default function PremiumDatasources() {
return (
<>
- {PREMIUM_INTEGRATIONS.map((integration) => (
- (
+ {
+ handleOnClick={() => {
handleOnClick(integration.name);
}}
- >
-
-
-
- {integration.name}
-
+ icon={getAssetUrl(integration.icon)}
+ key={integration.name}
+ name={integration.name}
+ rightSibling={
{getTagText(!isFreePlanInstance)}
-
-
+ }
+ />
))}