diff --git a/app/client/src/ce/hooks/datasourceEditorHooks.tsx b/app/client/src/ce/hooks/datasourceEditorHooks.tsx
index b2795eb61493..385a328f0c24 100644
--- a/app/client/src/ce/hooks/datasourceEditorHooks.tsx
+++ b/app/client/src/ce/hooks/datasourceEditorHooks.tsx
@@ -1,34 +1,34 @@
-import React from "react";
-import { useSelector } from "react-redux";
-import NewActionButton from "pages/Editor/DataSourceEditor/NewActionButton";
-import { EditorNames } from "./";
-import type { Datasource } from "entities/Datasource";
-import type { ApiDatasourceForm } from "entities/Datasource/RestAPIForm";
-import { Button } from "design-system";
+import { generateTemplateFormURL } from "@appsmith/RouteBuilder";
import {
GENERATE_NEW_PAGE_BUTTON_TEXT,
createMessage,
} from "@appsmith/constants/messages";
+import { ActionParentEntityType } from "@appsmith/entities/Engine/actionHelpers";
+import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
+import type { AppState } from "@appsmith/reducers";
+import { getPlugin } from "@appsmith/selectors/entitiesSelector";
import AnalyticsUtil from "@appsmith/utils/AnalyticsUtil";
-import history from "utils/history";
-import { generateTemplateFormURL } from "@appsmith/RouteBuilder";
+import {
+ getHasCreatePagePermission,
+ hasCreateDSActionPermissionInApp,
+} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
+import { Button } from "design-system";
+import type { Datasource } from "entities/Datasource";
+import type { ApiDatasourceForm } from "entities/Datasource/RestAPIForm";
+import NewActionButton from "pages/Editor/DataSourceEditor/NewActionButton";
+import { useShowPageGenerationOnHeader } from "pages/Editor/DataSourceEditor/hooks";
+import React from "react";
+import { useSelector } from "react-redux";
import {
getCurrentApplication,
getCurrentApplicationId,
getCurrentPageId,
getPagePermissions,
} from "selectors/editorSelectors";
-import { useShowPageGenerationOnHeader } from "pages/Editor/DataSourceEditor/hooks";
-import type { AppState } from "@appsmith/reducers";
-import {
- getHasCreatePagePermission,
- hasCreateDSActionPermissionInApp,
-} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers";
-import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
-import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
-import { ActionParentEntityType } from "@appsmith/entities/Engine/actionHelpers";
import { isEnabledForPreviewData } from "utils/editorContextUtils";
-import { getPlugin } from "@appsmith/selectors/entitiesSelector";
+import history from "utils/history";
+import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
+import { EditorNames } from "./";
export interface HeaderActionProps {
datasource: Datasource | ApiDatasourceForm | undefined;
@@ -48,6 +48,9 @@ export const useHeaderActions = (
) => {
const pageId = useSelector(getCurrentPageId);
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
+ const releaseDragDropBuildingBlocks = useFeatureFlag(
+ FEATURE_FLAG.release_drag_drop_building_blocks_enabled,
+ );
const userAppPermissions = useSelector(
(state: AppState) => getCurrentApplication(state)?.userPermissions ?? [],
);
@@ -65,6 +68,10 @@ export const useHeaderActions = (
const isPluginAllowedToPreviewData =
!!plugin && isEnabledForPreviewData(datasource as Datasource, plugin);
+ const shouldShowSecondaryGenerateButton = releaseDragDropBuildingBlocks
+ ? false
+ : !!isPluginAllowedToPreviewData;
+
if (editorType === EditorNames.APPLICATION) {
const canCreateDatasourceActions = hasCreateDSActionPermissionInApp({
isEnabled: isFeatureEnabled,
@@ -99,7 +106,7 @@ export const useHeaderActions = (
datasource={datasource as Datasource}
disabled={!canCreateDatasourceActions || !isPluginAuthorized}
eventFrom="datasource-pane"
- isNewQuerySecondaryButton={!!isPluginAllowedToPreviewData}
+ isNewQuerySecondaryButton={shouldShowSecondaryGenerateButton}
pluginType={pluginType}
/>
);
diff --git a/app/client/src/pages/Editor/DatasourceInfo/DatasourceViewModeSchema.tsx b/app/client/src/pages/Editor/DatasourceInfo/DatasourceViewModeSchema.tsx
index 3f2e78e3a189..b0d668b26e0a 100644
--- a/app/client/src/pages/Editor/DatasourceInfo/DatasourceViewModeSchema.tsx
+++ b/app/client/src/pages/Editor/DatasourceInfo/DatasourceViewModeSchema.tsx
@@ -77,6 +77,9 @@ const DatasourceViewModeSchema = (props: Props) => {
);
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
+ const releaseDragDropBuildingBlocks = useFeatureFlag(
+ FEATURE_FLAG.release_drag_drop_building_blocks_enabled,
+ );
const editorType = useEditorType(history.location.pathname);
@@ -230,7 +233,9 @@ const DatasourceViewModeSchema = (props: Props) => {
// if there was a failure in the fetching of the data
// if tableName from schema is availble
// if the user has permissions
+ // if drag and drop building blocks are not enabled
const showGeneratePageBtn =
+ !releaseDragDropBuildingBlocks &&
!isDatasourceStructureLoading &&
!isLoading &&
!failedFetchingPreviewData &&
diff --git a/app/client/src/pages/Editor/DatasourceInfo/GoogleSheetSchema.tsx b/app/client/src/pages/Editor/DatasourceInfo/GoogleSheetSchema.tsx
index 4d126e81505f..5d8f8fc8d83c 100644
--- a/app/client/src/pages/Editor/DatasourceInfo/GoogleSheetSchema.tsx
+++ b/app/client/src/pages/Editor/DatasourceInfo/GoogleSheetSchema.tsx
@@ -347,6 +347,9 @@ function GoogleSheetSchema(props: Props) {
);
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
+ const releaseDragDropBuildingBlocks = useFeatureFlag(
+ FEATURE_FLAG.release_drag_drop_building_blocks_enabled,
+ );
const editorType = useEditorType(history.location.pathname);
@@ -372,6 +375,7 @@ function GoogleSheetSchema(props: Props) {
);
const showGeneratePageBtn =
+ !releaseDragDropBuildingBlocks &&
!isLoading &&
!isError &&
sheetData?.length &&
diff --git a/app/client/src/pages/Editor/DatasourceInfo/HideGeneratePageButton.test.tsx b/app/client/src/pages/Editor/DatasourceInfo/HideGeneratePageButton.test.tsx
new file mode 100644
index 000000000000..001589da2361
--- /dev/null
+++ b/app/client/src/pages/Editor/DatasourceInfo/HideGeneratePageButton.test.tsx
@@ -0,0 +1,556 @@
+import {
+ DATASOURCE_GENERATE_PAGE_BUTTON,
+ NEW_AI_BUTTON_TEXT,
+ NEW_API_BUTTON_TEXT,
+ NEW_QUERY_BUTTON_TEXT,
+ createMessage,
+} from "@appsmith/constants/messages";
+import { getNumberOfEntitiesInCurrentPage } from "@appsmith/selectors/entitiesSelector";
+import "@testing-library/jest-dom";
+import { render, screen } from "@testing-library/react";
+import { PluginType } from "entities/Action";
+import { DatasourceConnectionMode, type Datasource } from "entities/Datasource";
+import { SSLType } from "entities/Datasource/RestAPIForm";
+import { unitTestBaseMockStore } from "layoutSystems/common/dropTarget/unitTestUtils";
+import React from "react";
+import { Provider, useSelector } from "react-redux";
+import { useParams } from "react-router";
+import configureStore from "redux-mock-store";
+import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
+import { DSFormHeader } from "../DataSourceEditor/DSFormHeader";
+import DatasourceViewModeSchema from "./DatasourceViewModeSchema";
+import GoogleSheetSchema from "./GoogleSheetSchema";
+/* eslint-disable @typescript-eslint/no-var-requires */
+const reactRouter = require("react-router");
+
+jest.mock("utils/hooks/useFeatureFlag");
+jest.mock("react-router", () => ({
+ ...jest.requireActual("react-router"),
+ useParams: jest.fn(),
+}));
+jest.mock("react-redux", () => ({
+ ...jest.requireActual("react-redux"),
+ useSelector: jest.fn(),
+}));
+
+const mockStore = configureStore([]);
+
+const mockSetDatasourceViewModeFlag = jest.fn();
+
+const renderBaseDatasourceComponent = () => {
+ render(
+
+
+ ,
+ );
+};
+
+const renderGoogleSheetDSComponent = () => {
+ render(
+
+
+ ,
+ );
+};
+
+const renderDSFormHeader = () => {
+ render(
+
+ true}
+ viewMode
+ />
+ ,
+ );
+};
+
+const getCreateButtonText = (pluginType: PluginType) => {
+ switch (pluginType) {
+ case PluginType.DB:
+ case PluginType.SAAS:
+ return createMessage(NEW_QUERY_BUTTON_TEXT);
+ case PluginType.AI:
+ return createMessage(NEW_AI_BUTTON_TEXT);
+ default:
+ return createMessage(NEW_API_BUTTON_TEXT);
+ }
+};
+
+describe("DatasourceViewModeSchema Component", () => {
+ it("1. should not render the 'generate page' button when release_drag_drop_building_blocks_enabled is enabled", () => {
+ (useFeatureFlag as jest.Mock).mockReturnValue(true);
+ (useParams as jest.Mock).mockReturnValue({
+ pageId: unitTestBaseMockStore.entities.pageList.currentPageId,
+ });
+ (useSelector as jest.Mock).mockImplementation((selector) => {
+ if (selector === getNumberOfEntitiesInCurrentPage) {
+ return 0;
+ }
+ return selector(baseStoreForSpec); // Default case for other selectors
+ });
+ renderBaseDatasourceComponent();
+
+ // Check that the "generate page" button is not rendered
+ const generatePageButton = screen.queryByText(
+ createMessage(DATASOURCE_GENERATE_PAGE_BUTTON),
+ );
+ expect(generatePageButton).not.toBeInTheDocument();
+ });
+
+ it("2. should render new query button as primary when release_drag_drop_building_blocks_enabled is enabled", () => {
+ (useFeatureFlag as jest.Mock).mockReturnValue(true);
+ const mockHistoryPush = jest.fn();
+ const mockHistoryReplace = jest.fn();
+ const mockHistoryLocation = {
+ pathname: "/",
+ search: "",
+ hash: "",
+ state: {},
+ };
+
+ jest.spyOn(reactRouter, "useHistory").mockReturnValue({
+ push: mockHistoryPush,
+ replace: mockHistoryReplace,
+ location: mockHistoryLocation,
+ });
+
+ jest.spyOn(reactRouter, "useLocation").mockReturnValue(mockHistoryLocation);
+
+ renderDSFormHeader();
+
+ // Check that the "New Query" button is rendered as primary
+ const newQuerySpan = screen.getByText(getCreateButtonText(PluginType.DB));
+ const newQueryButton = newQuerySpan.closest("button");
+ expect(newQueryButton).toHaveAttribute("kind", "primary");
+ });
+});
+
+describe("GoogleSheetSchema Component", () => {
+ it("should not render the 'generate page' button when release_drag_drop_building_blocks_enabled is enabled", () => {
+ (useFeatureFlag as jest.Mock).mockReturnValue(true);
+ (useParams as jest.Mock).mockReturnValue({
+ pageId: unitTestBaseMockStore.entities.pageList.currentPageId,
+ });
+ (useSelector as jest.Mock).mockImplementation((selector) => {
+ if (selector === getNumberOfEntitiesInCurrentPage) {
+ return 0;
+ }
+ return selector(baseStoreForSpec); // Default case for other selectors
+ });
+ renderGoogleSheetDSComponent();
+
+ // Check that the "generate page" button is not rendered
+ const generatePageButton = screen.queryByText(
+ createMessage(DATASOURCE_GENERATE_PAGE_BUTTON),
+ );
+ expect(generatePageButton).not.toBeInTheDocument();
+ });
+});
+
+const mockDatasource: Datasource = {
+ id: "667941878b418b52eb273895",
+ userPermissions: [
+ "execute:datasources",
+ "delete:datasources",
+ "manage:datasources",
+ "read:datasources",
+ ],
+ name: "Users",
+ pluginId: "656eeb1024ec7f5154c9ba00",
+ workspaceId: "6679402f8b418b52eb27388d",
+ datasourceStorages: {
+ unused_env: {
+ datasourceId: "667941878b418b52eb273895",
+ environmentId: "unused_env",
+ datasourceConfiguration: {
+ url: "",
+ connection: {
+ mode: DatasourceConnectionMode.READ_WRITE,
+ ssl: {
+ authType: SSLType.DEFAULT,
+ authTypeControl: false,
+ certificateFile: {} as any,
+ },
+ },
+ authentication: {
+ authenticationType: "dbAuth",
+ username: "users",
+ },
+ },
+ isConfigured: true,
+ isValid: true,
+ },
+ },
+ invalids: [],
+ messages: [],
+ isMock: true,
+};
+
+const baseStoreForSpec = {
+ entities: {
+ ...unitTestBaseMockStore.entities,
+ plugins: {
+ list: [
+ {
+ id: "656eeb1024ec7f5154c9ba00",
+ userPermissions: [],
+ name: "PostgreSQL",
+ type: "DB",
+ packageName: "postgres-plugin",
+ iconLocation: "https://assets.appsmith.com/logo/postgresql.svg",
+ documentationLink:
+ "https://docs.appsmith.com/reference/datasources/querying-postgres#create-crud-queries",
+ responseType: "TABLE",
+ uiComponent: "DbEditorForm",
+ datasourceComponent: "AutoForm",
+ generateCRUDPageComponent: "PostgreSQL",
+ allowUserDatasources: true,
+ isRemotePlugin: false,
+ templates: {
+ CREATE:
+ "INSERT INTO users\n (name, gender, email)\nVALUES\n (\n {{ nameInput.text }},\n {{ genderDropdown.selectedOptionValue }},\n {{ emailInput.text }}\n );",
+ SELECT:
+ "SELECT * FROM <> LIMIT 10;\n\n-- Please enter a valid table name and hit RUN",
+ UPDATE:
+ "UPDATE users\n SET status = 'APPROVED'\n WHERE id = {{ usersTable.selectedRow.id }};\n",
+ DELETE: "DELETE FROM users WHERE id = -1;",
+ },
+ remotePlugin: false,
+ new: false,
+ },
+ {
+ id: "656eeb1024ec7f5154c9ba01",
+ userPermissions: [],
+ name: "REST API",
+ type: "API",
+ packageName: "restapi-plugin",
+ iconLocation: "https://assets.appsmith.com/RestAPI.png",
+ uiComponent: "ApiEditorForm",
+ datasourceComponent: "RestAPIDatasourceForm",
+ allowUserDatasources: true,
+ isRemotePlugin: false,
+ templates: {},
+ remotePlugin: false,
+ new: false,
+ },
+ ],
+ },
+ datasources: {
+ list: [
+ {
+ id: "667941878b418b52eb273895",
+ userPermissions: [
+ "execute:datasources",
+ "delete:datasources",
+ "manage:datasources",
+ "read:datasources",
+ ],
+ name: "Users",
+ pluginId: "656eeb1024ec7f5154c9ba00",
+ workspaceId: "6679402f8b418b52eb27388d",
+ datasourceStorages: {
+ unused_env: {
+ id: "667941878b418b52eb273896",
+ datasourceId: "667941878b418b52eb273895",
+ environmentId: "unused_env",
+ datasourceConfiguration: {
+ connection: {
+ mode: "READ_WRITE",
+ ssl: {
+ authType: "DEFAULT",
+ },
+ },
+ endpoints: [
+ {
+ host: "mockdb.internal.appsmith.com",
+ },
+ ],
+ authentication: {
+ authenticationType: "dbAuth",
+ username: "users",
+ databaseName: "users",
+ },
+ },
+ isConfigured: true,
+ invalids: [],
+ messages: [],
+ isValid: true,
+ },
+ },
+ invalids: [],
+ messages: [],
+ isRecentlyCreated: true,
+ isMock: true,
+ isValid: true,
+ new: false,
+ },
+ ],
+ loading: false,
+ isTesting: false,
+ isListing: false,
+ fetchingDatasourceStructure: {
+ "66793e2a8b418b52eb27388a": false,
+ "667941878b418b52eb273895": false,
+ },
+ structure: {
+ "66793e2a8b418b52eb27388a": {
+ tables: [
+ {
+ type: "TABLE",
+ schema: "public",
+ name: "public.users",
+ columns: [
+ {
+ name: "id",
+ type: "int4",
+ defaultValue: "nextval('users_id_seq'::regclass)",
+ isAutogenerated: true,
+ },
+ {
+ name: "gender",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "latitude",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "longitude",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "dob",
+ type: "timestamptz",
+ isAutogenerated: false,
+ },
+ {
+ name: "phone",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "email",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "image",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "country",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "name",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "created_at",
+ type: "timestamp",
+ isAutogenerated: false,
+ },
+ {
+ name: "updated_at",
+ type: "timestamp",
+ isAutogenerated: false,
+ },
+ ],
+ keys: [
+ {
+ name: "users_pkey",
+ columnNames: ["id"],
+ type: "primary key",
+ },
+ ],
+ templates: [
+ {
+ title: "SELECT",
+ body: 'SELECT * FROM public."users" LIMIT 10;',
+ suggested: true,
+ },
+ {
+ title: "INSERT",
+ body: 'INSERT INTO public."users" ("gender", "latitude", "longitude", "dob", "phone", "email", "image", "country", "name", "created_at", "updated_at")\n VALUES (\'\', \'\', \'\', TIMESTAMP WITH TIME ZONE \'2019-07-01 06:30:00 CET\', \'\', \'\', \'\', \'\', \'\', TIMESTAMP \'2019-07-01 10:00:00\', TIMESTAMP \'2019-07-01 10:00:00\');',
+ suggested: false,
+ },
+ {
+ title: "UPDATE",
+ body: 'UPDATE public."users" SET\n "gender" = \'\',\n "latitude" = \'\',\n "longitude" = \'\',\n "dob" = TIMESTAMP WITH TIME ZONE \'2019-07-01 06:30:00 CET\',\n "phone" = \'\',\n "email" = \'\',\n "image" = \'\',\n "country" = \'\',\n "name" = \'\',\n "created_at" = TIMESTAMP \'2019-07-01 10:00:00\',\n "updated_at" = TIMESTAMP \'2019-07-01 10:00:00\'\n WHERE 1 = 0; -- Specify a valid condition here. Removing the condition may update every row in the table!',
+ suggested: false,
+ },
+ {
+ title: "DELETE",
+ body: 'DELETE FROM public."users"\n WHERE 1 = 0; -- Specify a valid condition here. Removing the condition may delete everything in the table!',
+ suggested: false,
+ },
+ ],
+ },
+ ],
+ },
+ "667941878b418b52eb273895": {
+ tables: [
+ {
+ type: "TABLE",
+ schema: "public",
+ name: "public.users",
+ columns: [
+ {
+ name: "id",
+ type: "int4",
+ defaultValue: "nextval('users_id_seq'::regclass)",
+ isAutogenerated: true,
+ },
+ {
+ name: "gender",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "latitude",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "longitude",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "dob",
+ type: "timestamptz",
+ isAutogenerated: false,
+ },
+ {
+ name: "phone",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "email",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "image",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "country",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "name",
+ type: "text",
+ isAutogenerated: false,
+ },
+ {
+ name: "created_at",
+ type: "timestamp",
+ isAutogenerated: false,
+ },
+ {
+ name: "updated_at",
+ type: "timestamp",
+ isAutogenerated: false,
+ },
+ ],
+ keys: [
+ {
+ name: "users_pkey",
+ columnNames: ["id"],
+ type: "primary key",
+ },
+ ],
+ templates: [
+ {
+ title: "SELECT",
+ body: 'SELECT * FROM public."users" LIMIT 10;',
+ suggested: true,
+ },
+ {
+ title: "INSERT",
+ body: 'INSERT INTO public."users" ("gender", "latitude", "longitude", "dob", "phone", "email", "image", "country", "name", "created_at", "updated_at")\n VALUES (\'\', \'\', \'\', TIMESTAMP WITH TIME ZONE \'2019-07-01 06:30:00 CET\', \'\', \'\', \'\', \'\', \'\', TIMESTAMP \'2019-07-01 10:00:00\', TIMESTAMP \'2019-07-01 10:00:00\');',
+ suggested: false,
+ },
+ {
+ title: "UPDATE",
+ body: 'UPDATE public."users" SET\n "gender" = \'\',\n "latitude" = \'\',\n "longitude" = \'\',\n "dob" = TIMESTAMP WITH TIME ZONE \'2019-07-01 06:30:00 CET\',\n "phone" = \'\',\n "email" = \'\',\n "image" = \'\',\n "country" = \'\',\n "name" = \'\',\n "created_at" = TIMESTAMP \'2019-07-01 10:00:00\',\n "updated_at" = TIMESTAMP \'2019-07-01 10:00:00\'\n WHERE 1 = 0; -- Specify a valid condition here. Removing the condition may update every row in the table!',
+ suggested: false,
+ },
+ {
+ title: "DELETE",
+ body: 'DELETE FROM public."users"\n WHERE 1 = 0; -- Specify a valid condition here. Removing the condition may delete everything in the table!',
+ suggested: false,
+ },
+ ],
+ },
+ ],
+ },
+ },
+ isFetchingMockDataSource: false,
+ mockDatasourceList: [
+ {
+ pluginType: "db",
+ packageName: "mongo-plugin",
+ description: "This contains a standard movies collection",
+ name: "Movies",
+ },
+ {
+ pluginType: "db",
+ packageName: "postgres-plugin",
+ description: "This contains a standard users information",
+ name: "Users",
+ },
+ ],
+ executingDatasourceQuery: false,
+ isReconnectingModalOpen: false,
+ unconfiguredList: [],
+ isDatasourceBeingSaved: false,
+ isDatasourceBeingSavedFromPopup: false,
+ gsheetToken: "",
+ gsheetProjectID: "",
+ gsheetStructure: {
+ spreadsheets: {},
+ sheets: {},
+ columns: {},
+ isFetchingSpreadsheets: false,
+ isFetchingSheets: false,
+ isFetchingColumns: false,
+ },
+ recentDatasources: [],
+ isDeleting: false,
+ },
+ },
+ ui: {
+ ...unitTestBaseMockStore.ui,
+ datasourcePane: {
+ selectedTableName: "users",
+ },
+ datasourceName: {
+ isSaving: [mockDatasource.id],
+ errors: [mockDatasource.id],
+ },
+ },
+};