diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js b/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js
index 091e0bef94ff..1140a8591fcf 100644
--- a/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js
+++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js
@@ -32,10 +32,12 @@ describe(
});
it("1.Bug #17002 Forking a template into an existing app which is connected to git makes the application go into a bad state ", function () {
- PageList.AddNewPage("Add page from template");
- _.agHelper.AssertElementExist(template.templateDialogBox);
- _.agHelper.GetNClick(template.templateCard);
- _.agHelper.GetNClick(template.templateViewForkButton);
+ cy.get(template.startFromTemplateCard).click();
+ _.assertHelper.AssertNetworkStatus("fetchTemplate");
+
+ cy.get(template.templateDialogBox).should("be.visible");
+ cy.get(template.templateCard).first().click();
+ cy.get(template.templateViewForkButton).first().click();
cy.waitUntil(() => cy.xpath("//span[text()='Setting up the template']"), {
errorMsg: "Setting Templates did not finish even after 75 seconds",
timeout: 75000,
diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.ts
index 2838e49a8674..e39a130e675c 100644
--- a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.ts
+++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.ts
@@ -33,7 +33,7 @@ describe(
it("2. Add selected pages from template to an app", () => {
homePage.CreateNewApplication();
- PageList.AddNewPage("Add page from template");
+ agHelper.GetNClick(template.startFromTemplateCard);
agHelper.AssertElementVisibility(template.templateDialogBox);
agHelper.GetNClick("//h1[text()='Applicant Tracker-test']");
agHelper.FailIfErrorToast(
diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts
index fe5bb57ef570..233a78e4b7ff 100644
--- a/app/client/src/ce/constants/messages.ts
+++ b/app/client/src/ce/constants/messages.ts
@@ -1771,6 +1771,9 @@ export const WIDGET_USED = () => "Widgets";
export const SIMILAR_TEMPLATES = () => "Similar templates";
export const VIEW_ALL_TEMPLATES = () => "View all templates";
export const FILTERS = () => "Filters";
+export const TEMPLATE_CARD_TITLE = () => "Start from a template";
+export const TEMPLATE_CARD_DESCRIPTION = () =>
+ "Create app from template by selecting pages";
export const FILTER_SELECTALL = () => "Select all";
export const FILTER_SELECT_PAGE = () => "Add selected page";
export const FILTER_SELECT_PAGES = () => "Add selected pages";
@@ -1823,6 +1826,9 @@ export const SEARCH_USERS = (
export const CREATE_PAGE = () => "New blank page";
export const CANVAS_NEW_PAGE_CARD = () => "Create new page";
+export const GENERATE_PAGE = () => "Generate page from data table";
+export const GENERATE_PAGE_DESCRIPTION = () =>
+ "Start app with a simple CRUD UI and customize it";
export const ADD_PAGE_FROM_TEMPLATE = () => "Add page from template";
export const INVALID_URL = () =>
"Please enter a valid URL, for example, https://example.com";
diff --git a/app/client/src/pages/Editor/WidgetsEditor/WidgetEditorHeader.tsx b/app/client/src/pages/Editor/WidgetsEditor/WidgetEditorHeader.tsx
index 122f29fa4f8a..6e579064db62 100644
--- a/app/client/src/pages/Editor/WidgetsEditor/WidgetEditorHeader.tsx
+++ b/app/client/src/pages/Editor/WidgetsEditor/WidgetEditorHeader.tsx
@@ -1,6 +1,12 @@
-import useMissingModuleNotification from "@appsmith/pages/Editor/IDE/MainPane/useMissingModuleNotification";
-import AnonymousDataPopup from "pages/Editor/FirstTimeUserOnboarding/AnonymousDataPopup";
import React from "react";
+import AnonymousDataPopup from "pages/Editor/FirstTimeUserOnboarding/AnonymousDataPopup";
+import EmptyCanvasPrompts from "./components/EmptyCanvasPrompts";
+import { useSelector } from "react-redux";
+import { combinedPreviewModeSelector } from "selectors/editorSelectors";
+import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors";
+import { useCurrentAppState } from "pages/Editor/IDE/hooks";
+import { EditorState } from "@appsmith/entities/IDE/constants";
+import useMissingModuleNotification from "@appsmith/pages/Editor/IDE/MainPane/useMissingModuleNotification";
/**
* WidgetEditorHeader
@@ -11,9 +17,19 @@ import React from "react";
* - missing module notification
*/
export const WidgetEditorHeader = () => {
+ const isNavigationSelectedInSettings = useSelector(
+ getIsAppSettingsPaneWithNavigationTabOpen,
+ );
+ const appState = useCurrentAppState();
+ const isAppSettingsPaneWithNavigationTabOpen =
+ appState === EditorState.SETTINGS && isNavigationSelectedInSettings;
+ const isPreviewMode = useSelector(combinedPreviewModeSelector);
const missingModuleNotification = useMissingModuleNotification();
return (
<>
+ {!isAppSettingsPaneWithNavigationTabOpen && (
+
+ )}
{missingModuleNotification}
>
diff --git a/app/client/src/pages/Editor/WidgetsEditor/components/EmptyCanvasPrompts.tsx b/app/client/src/pages/Editor/WidgetsEditor/components/EmptyCanvasPrompts.tsx
new file mode 100644
index 000000000000..71dfa584bafa
--- /dev/null
+++ b/app/client/src/pages/Editor/WidgetsEditor/components/EmptyCanvasPrompts.tsx
@@ -0,0 +1,170 @@
+import React, { useEffect } from "react";
+import styled from "styled-components";
+import { Text, TextType } from "design-system-old";
+import { useDispatch, useSelector } from "react-redux";
+import {
+ selectURLSlugs,
+ showCanvasTopSectionSelector,
+} from "selectors/editorSelectors";
+import AnalyticsUtil from "@appsmith/utils/AnalyticsUtil";
+import history from "utils/history";
+import { generateTemplateFormURL } from "@appsmith/RouteBuilder";
+import { useParams } from "react-router";
+import type { ExplorerURLParams } from "@appsmith/pages/Editor/Explorer/helpers";
+import { showTemplatesModal as showTemplatesModalAction } from "actions/templateActions";
+import {
+ createMessage,
+ GENERATE_PAGE,
+ GENERATE_PAGE_DESCRIPTION,
+ TEMPLATE_CARD_DESCRIPTION,
+ TEMPLATE_CARD_TITLE,
+} from "@appsmith/constants/messages";
+import { deleteCanvasCardsState } from "actions/editorActions";
+import { isAirgapped } from "@appsmith/utils/airgapHelpers";
+import { Icon } from "design-system";
+import {
+ LayoutSystemFeatures,
+ useLayoutSystemFeatures,
+} from "layoutSystems/common/useLayoutSystemFeatures";
+
+const Wrapper = styled.div`
+ margin: ${(props) =>
+ `${props.theme.spaces[7]}px ${props.theme.spaces[16]}px 0px ${props.theme.spaces[13]}px`};
+ display: flex;
+ flex-direction: row;
+ gap: ${(props) => props.theme.spaces[7]}px;
+`;
+
+const Card = styled.div<{ centerAlign?: boolean }>`
+ padding: ${(props) =>
+ `${props.theme.spaces[5]}px ${props.theme.spaces[9]}px`};
+ border: solid 1px var(--ads-v2-color-border);
+ background: var(--ads-v2-color-bg);
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ border-radius: var(--ads-v2-border-radius);
+ ${(props) =>
+ props.centerAlign &&
+ `
+ justify-content: center;
+ `}
+ cursor: pointer;
+
+ svg {
+ height: 24px;
+ width: 24px;
+ }
+ &:hover {
+ background-color: var(--ads-v2-color-bg-subtle);
+ }
+`;
+
+const Content = styled.div`
+ display: flex;
+ flex-direction: column;
+ padding-left: ${(props) => props.theme.spaces[7]}px;
+`;
+
+interface routeId {
+ applicationSlug: string;
+ pageId: string;
+ pageSlug: string;
+}
+
+const goToGenPageForm = ({ pageId }: routeId): void => {
+ AnalyticsUtil.logEvent("GEN_CRUD_PAGE_ACTION_CARD_CLICK");
+ history.push(generateTemplateFormURL({ pageId }));
+};
+
+interface EmptyCanvasPromptsProps {
+ isPreview: boolean;
+}
+
+/**
+ * OldName: CanvasTopSection
+ */
+/**
+ * This Component encompasses the prompts for empty canvas
+ * prompts like generate crud app or import from template
+ * @param props Object that contains
+ * @prop isPreview, boolean to indicate preview mode
+ * @returns
+ */
+function EmptyCanvasPrompts(props: EmptyCanvasPromptsProps) {
+ const dispatch = useDispatch();
+ const showCanvasTopSection = useSelector(showCanvasTopSectionSelector);
+ const { isPreview } = props;
+ const { pageId } = useParams();
+ const { applicationSlug, pageSlug } = useSelector(selectURLSlugs);
+
+ const checkLayoutSystemFeatures = useLayoutSystemFeatures();
+ const [enableForkingFromTemplates, enableGenerateCrud] =
+ checkLayoutSystemFeatures([
+ LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES,
+ LayoutSystemFeatures.ENABLE_GENERATE_CRUD_APP,
+ ]);
+
+ useEffect(() => {
+ if (!showCanvasTopSection && !isPreview) {
+ dispatch(deleteCanvasCardsState());
+ }
+ }, [showCanvasTopSection, isPreview]);
+
+ if (!showCanvasTopSection || isPreview) return null;
+
+ const showTemplatesModal = () => {
+ dispatch(showTemplatesModalAction({ isOpenFromCanvas: false }));
+ AnalyticsUtil.logEvent("CANVAS_BLANK_PAGE_CTA_CLICK", {
+ item: "ADD_PAGE_FROM_TEMPLATE",
+ });
+ };
+
+ const onGeneratePageClick = () => {
+ goToGenPageForm({ applicationSlug, pageSlug, pageId });
+ AnalyticsUtil.logEvent("CANVAS_BLANK_PAGE_CTA_CLICK", {
+ item: "GENERATE_PAGE",
+ });
+ };
+
+ const isAirgappedInstance = isAirgapped();
+ const showCanvasPrompts =
+ (enableForkingFromTemplates && !isAirgappedInstance) || enableGenerateCrud;
+ return showCanvasPrompts ? (
+
+ {enableForkingFromTemplates && !isAirgappedInstance && (
+
+
+
+
+ {createMessage(TEMPLATE_CARD_TITLE)}
+
+
+ {createMessage(TEMPLATE_CARD_DESCRIPTION)}
+
+
+
+ )}
+ {enableGenerateCrud && (
+
+
+
+
+ {createMessage(GENERATE_PAGE)}
+
+
+ {createMessage(GENERATE_PAGE_DESCRIPTION)}
+
+
+
+ )}
+
+ ) : null;
+}
+
+export default EmptyCanvasPrompts;