diff --git a/app/client/cypress/support/Pages/JSEditor.ts b/app/client/cypress/support/Pages/JSEditor.ts
index a8ed3d4fbac3..832c83048d97 100644
--- a/app/client/cypress/support/Pages/JSEditor.ts
+++ b/app/client/cypress/support/Pages/JSEditor.ts
@@ -113,6 +113,7 @@ export class JSEditor {
);
//Checking JS object was created successfully
this.assertHelper.AssertNetworkStatus("@createNewJSCollection", 201);
+ cy.get(this._jsObjName).click({ force: true });
this.agHelper.AssertElementVisibility(this._jsObjTxt);
// Assert that the name of the JS Object is focused when newly created
this.agHelper.PressEnter();
diff --git a/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.ts b/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.tsx
similarity index 67%
rename from app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.ts
rename to app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.tsx
index 58614a67abe9..34ce88dd556a 100644
--- a/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.ts
+++ b/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.tsx
@@ -1,4 +1,5 @@
-import { useCallback } from "react";
+import { lazy, Suspense, useCallback, useMemo } from "react";
+import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { createNewJSCollection } from "actions/jsPaneActions";
import { getCurrentPageId } from "selectors/editorSelectors";
@@ -7,17 +8,16 @@ import { createMessage, EDITOR_PANE_TEXTS } from "ee/constants/messages";
import { JsFileIconV2 } from "pages/Editor/Explorer/ExplorerIcons";
import { SEARCH_ITEM_TYPES } from "components/editorComponents/GlobalSearch/utils";
import type { UseRoutes } from "ee/entities/IDE/constants";
-import JSEditor from "pages/Editor/JSEditor";
-import AddJS from "pages/Editor/IDE/EditorPane/JS/Add";
import { ADD_PATH } from "ee/constants/routes/appRoutes";
import history from "utils/history";
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
import { useModuleOptions } from "ee/utils/moduleInstanceHelpers";
import { getJSUrl } from "ee/pages/Editor/IDE/EditorPane/JS/utils";
-import { JSBlankState } from "pages/Editor/JSEditor/JSBlankState";
import { getIDEViewMode } from "selectors/ideSelectors";
import { EditorViewMode } from "ee/entities/IDE/constants";
import { setListViewActiveState } from "actions/ideActions";
+import { retryPromise } from "utils/AppsmithUtils";
+import Skeleton from "widgets/Skeleton";
export const useJSAdd = () => {
const pageId = useSelector(getCurrentPageId);
@@ -93,25 +93,64 @@ export const useGroupedAddJsOperations = (): GroupedAddOperations => {
];
};
+const AddJS = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(
+ /* webpackChunkName: "AddJS" */ "pages/Editor/IDE/EditorPane/JS/Add"
+ ),
+ ),
+);
+const JSEditor = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(/* webpackChunkName: "JSEditor" */ "pages/Editor/JSEditor"),
+ ),
+);
+
+const JSEmpty = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(
+ /* webpackChunkName: "JSEmpty" */ "pages/Editor/JSEditor/JSBlankState"
+ ),
+ ),
+);
+
export const useJSEditorRoutes = (path: string): UseRoutes => {
- return [
- {
- exact: true,
- key: "AddJS",
- component: AddJS,
- path: [`${path}${ADD_PATH}`, `${path}/:baseCollectionId${ADD_PATH}`],
- },
- {
- exact: true,
- key: "JSEditor",
- component: JSEditor,
- path: [path + "/:baseCollectionId"],
- },
- {
- key: "JSEmpty",
- component: JSBlankState,
- exact: true,
- path: [path],
- },
- ];
+ return useMemo(
+ () => [
+ {
+ exact: true,
+ key: "AddJS",
+ component: (args) => (
+ }>
+
+
+ ),
+ path: [`${path}${ADD_PATH}`, `${path}/:baseCollectionId${ADD_PATH}`],
+ },
+ {
+ exact: true,
+ key: "JSEditor",
+ component: (args) => (
+ }>
+
+
+ ),
+ path: [path + "/:baseCollectionId"],
+ },
+ {
+ key: "JSEmpty",
+ component: (args) => (
+ }>
+
+
+ ),
+ exact: true,
+ path: [path],
+ },
+ ],
+ [path],
+ );
};
diff --git a/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.tsx b/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.tsx
index 73ffb6ab8a74..7eeba362e2e1 100644
--- a/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.tsx
+++ b/app/client/src/ce/pages/Editor/IDE/EditorPane/Query/hooks.tsx
@@ -1,4 +1,5 @@
-import { useCallback, useMemo } from "react";
+import { lazy, Suspense, useCallback, useMemo } from "react";
+import React from "react";
import history from "utils/history";
import { useLocation } from "react-router";
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
@@ -23,19 +24,17 @@ import {
BUILDER_PATH_DEPRECATED,
} from "ee/constants/routes/appRoutes";
import { SAAS_EDITOR_API_ID_PATH } from "pages/Editor/SaaSEditor/constants";
-import ApiEditor from "pages/Editor/APIEditor";
import type { UseRoutes } from "ee/entities/IDE/constants";
-import QueryEditor from "pages/Editor/QueryEditor";
-import AddQuery from "pages/Editor/IDE/EditorPane/Query/Add";
import type { AppState } from "ee/reducers";
import keyBy from "lodash/keyBy";
import { getPluginEntityIcon } from "pages/Editor/Explorer/ExplorerIcons";
import type { ListItemProps } from "@appsmith/ads";
import { createAddClassName } from "pages/Editor/IDE/EditorPane/utils";
-import { QueriesBlankState } from "pages/Editor/QueryEditor/QueriesBlankState";
import { getIDEViewMode } from "selectors/ideSelectors";
import { EditorViewMode } from "ee/entities/IDE/constants";
import { setListViewActiveState } from "actions/ideActions";
+import { retryPromise } from "utils/AppsmithUtils";
+import Skeleton from "widgets/Skeleton";
export const useQueryAdd = () => {
const location = useLocation();
@@ -114,47 +113,107 @@ export const useGroupedAddQueryOperations = (): GroupedAddOperations => {
return groups;
};
+const ApiEditor = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(/* webpackChunkName: "APIEditor" */ "pages/Editor/APIEditor"),
+ ),
+);
+
+const AddQuery = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(
+ /* webpackChunkName: "AddQuery" */ "pages/Editor/IDE/EditorPane/Query/Add"
+ ),
+ ),
+);
+const QueryEditor = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(/* webpackChunkName: "QueryEditor" */ "pages/Editor/QueryEditor"),
+ ),
+);
+
+const QueryEmpty = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(
+ /* webpackChunkName: "QueryEmpty" */ "pages/Editor/QueryEditor/QueriesBlankState"
+ ),
+ ),
+);
+
export const useQueryEditorRoutes = (path: string): UseRoutes => {
- return [
- {
- key: "ApiEditor",
- component: ApiEditor,
- exact: true,
- path: [
- BUILDER_PATH + API_EDITOR_ID_PATH,
- BUILDER_CUSTOM_PATH + API_EDITOR_ID_PATH,
- BUILDER_PATH_DEPRECATED + API_EDITOR_ID_PATH,
- ],
- },
- {
- key: "AddQuery",
- exact: true,
- component: AddQuery,
- path: [`${path}${ADD_PATH}`, `${path}/:baseQueryId${ADD_PATH}`],
- },
- {
- key: "SAASEditor",
- component: QueryEditor,
- exact: true,
- path: [
- BUILDER_PATH + SAAS_EDITOR_API_ID_PATH,
- BUILDER_CUSTOM_PATH + SAAS_EDITOR_API_ID_PATH,
- BUILDER_PATH_DEPRECATED + SAAS_EDITOR_API_ID_PATH,
- ],
- },
- {
- key: "QueryEditor",
- component: QueryEditor,
- exact: true,
- path: [path + "/:baseQueryId"],
- },
- {
- key: "QueryEmpty",
- component: QueriesBlankState,
- exact: true,
- path: [path],
- },
- ];
+ return useMemo(
+ () => [
+ {
+ key: "ApiEditor",
+ component: (args) => {
+ return (
+ }>
+
+
+ );
+ },
+ exact: true,
+ path: [
+ BUILDER_PATH + API_EDITOR_ID_PATH,
+ BUILDER_CUSTOM_PATH + API_EDITOR_ID_PATH,
+ BUILDER_PATH_DEPRECATED + API_EDITOR_ID_PATH,
+ ],
+ },
+ {
+ key: "AddQuery",
+ exact: true,
+ component: (args) => (
+ }>
+
+
+ ),
+ path: [`${path}${ADD_PATH}`, `${path}/:baseQueryId${ADD_PATH}`],
+ },
+ {
+ key: "SAASEditor",
+ component: (args) => {
+ return (
+ }>
+
+
+ );
+ },
+ exact: true,
+ path: [
+ BUILDER_PATH + SAAS_EDITOR_API_ID_PATH,
+ BUILDER_CUSTOM_PATH + SAAS_EDITOR_API_ID_PATH,
+ BUILDER_PATH_DEPRECATED + SAAS_EDITOR_API_ID_PATH,
+ ],
+ },
+ {
+ key: "QueryEditor",
+ component: (args) => {
+ return (
+ }>
+
+
+ );
+ },
+ exact: true,
+ path: [path + "/:baseQueryId"],
+ },
+ {
+ key: "QueryEmpty",
+ component: (args) => (
+ }>
+
+
+ ),
+ exact: true,
+ path: [path],
+ },
+ ],
+ [path],
+ );
};
export const useAddQueryListItems = () => {
diff --git a/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.ts b/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.tsx
similarity index 85%
rename from app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.ts
rename to app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.tsx
index c49f522c1c33..d0fdc4ecda05 100644
--- a/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.ts
+++ b/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.tsx
@@ -24,7 +24,6 @@ import {
WIDGETS_EDITOR_ID_PATH,
} from "constants/routes";
import CreateNewDatasourceTab from "pages/Editor/IntegrationEditor/CreateNewDatasourceTab";
-import OnboardingChecklist from "pages/Editor/FirstTimeUserOnboarding/Checklist";
import {
SAAS_EDITOR_API_ID_ADD_PATH,
SAAS_EDITOR_API_ID_PATH,
@@ -38,7 +37,28 @@ import GeneratePage from "pages/Editor/GeneratePage";
import type { RouteProps } from "react-router";
import { useSelector } from "react-redux";
import { combinedPreviewModeSelector } from "selectors/editorSelectors";
+import { lazy, Suspense } from "react";
+import React from "react";
+import { retryPromise } from "utils/AppsmithUtils";
+import Skeleton from "widgets/Skeleton";
+
+const FirstTimeUserOnboardingChecklist = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(
+ /* webpackChunkName: "FirstTimeUserOnboardingChecklist" */ "pages/Editor/FirstTimeUserOnboarding/Checklist"
+ ),
+ ),
+);
+
+export const LazilyLoadedFirstTimeUserOnboardingChecklist = () => {
+ return (
+ }>
+
+
+ );
+};
export interface RouteReturnType extends RouteProps {
key: string;
}
@@ -95,7 +115,9 @@ function useRoutes(path: string): RouteReturnType[] {
},
{
key: "OnboardingChecklist",
- component: isPreviewMode ? WidgetsEditor : OnboardingChecklist,
+ component: isPreviewMode
+ ? WidgetsEditor
+ : FirstTimeUserOnboardingChecklist,
exact: true,
path: `${path}${BUILDER_CHECKLIST_PATH}`,
},
diff --git a/app/client/src/pages/Editor/FirstTimeUserOnboarding/Modal.tsx b/app/client/src/pages/Editor/FirstTimeUserOnboarding/Modal.tsx
index a0a70f11d605..6cd288820d19 100644
--- a/app/client/src/pages/Editor/FirstTimeUserOnboarding/Modal.tsx
+++ b/app/client/src/pages/Editor/FirstTimeUserOnboarding/Modal.tsx
@@ -1,11 +1,29 @@
-import React from "react";
+import React, { lazy, Suspense } from "react";
import { MenuContent } from "@appsmith/ads";
import styled from "styled-components";
-import Checklist from "./Checklist";
import HelpMenu from "./HelpMenu";
import { useDispatch } from "react-redux";
import { showSignpostingModal } from "actions/onboardingActions";
+import { retryPromise } from "utils/AppsmithUtils";
+import Skeleton from "widgets/Skeleton";
+
+const Checklist = lazy(async () =>
+ retryPromise(
+ async () =>
+ import(
+ /* webpackChunkName: "FirstTimeUserOnboardingChecklist" */ "./Checklist"
+ ),
+ ),
+);
+
+export const LazilyLoadedChecklist = () => {
+ return (
+ }>
+
+
+ );
+};
const SIGNPOSTING_POPUP_WIDTH = "360px";
const StyledMenuContent = styled(MenuContent)<{ animate: boolean }>`
@@ -48,7 +66,7 @@ function OnboardingModal(props: {
width={SIGNPOSTING_POPUP_WIDTH}
>
- {!props.showIntercomConsent && }
+ {!props.showIntercomConsent && }
{
localStorage.setItem("SPLITPANE_ANNOUNCEMENT", "false");
describe("JS Blank State", () => {
- it("Renders Fullscreen Blank State", () => {
- const { getByRole, getByText } = render(
+ it("Renders Fullscreen Blank State", async () => {
+ const { findByText, getByRole, getByText } = render(
,
@@ -31,7 +31,7 @@ describe("IDE Render: JS", () => {
);
// Main pane text
- getByText(createMessage(EDITOR_PANE_TEXTS.js_blank_state));
+ await findByText(createMessage(EDITOR_PANE_TEXTS.js_blank_state));
// Left pane text
getByText(createMessage(EDITOR_PANE_TEXTS.js_blank_state_description));
@@ -68,8 +68,8 @@ describe("IDE Render: JS", () => {
});
});
- it("Renders Fullscreen Add in Blank State", () => {
- const { getByTestId, getByText } = render(
+ it("Renders Fullscreen Add in Blank State", async () => {
+ const { findByText, getByTestId, getByText } = render(
,
@@ -80,7 +80,7 @@ describe("IDE Render: JS", () => {
);
// Main pane text
- getByText(createMessage(EDITOR_PANE_TEXTS.js_create_tab_title));
+ await findByText(createMessage(EDITOR_PANE_TEXTS.js_create_tab_title));
// Left pane description
getByText(createMessage(EDITOR_PANE_TEXTS.js_blank_state_description));
@@ -117,7 +117,7 @@ describe("IDE Render: JS", () => {
});
describe("JS Edit Render", () => {
- it("Renders JS routes in Full screen", () => {
+ it("Renders JS routes in Full screen", async () => {
const page = PageFactory.build();
const js1 = JSObjectFactory.build({
pageId: page.pageId,
@@ -143,6 +143,15 @@ describe("IDE Render: JS", () => {
},
);
+ await waitFor(
+ async () => {
+ const elements = getAllByText("JSObject1"); // Use the common test ID or selector
+
+ expect(elements).toHaveLength(3); // Wait until there are exactly 3 elements
+ },
+ { timeout: 3000, interval: 500 },
+ );
+
// There will be 3 JSObject1 text (Left pane list, editor tab and Editor form)
expect(getAllByText("JSObject1").length).toEqual(3);
// Left pane active state
diff --git a/app/client/src/pages/Editor/IDE/EditorPane/Query/QueryRender.test.tsx b/app/client/src/pages/Editor/IDE/EditorPane/Query/QueryRender.test.tsx
index 3bc3dca089ba..65314ae7a727 100644
--- a/app/client/src/pages/Editor/IDE/EditorPane/Query/QueryRender.test.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorPane/Query/QueryRender.test.tsx
@@ -12,7 +12,7 @@ import { sagasToRunForTests } from "test/sagas";
import userEvent from "@testing-library/user-event";
import { getIDETestState } from "test/factories/AppIDEFactoryUtils";
import { PageFactory } from "test/factories/PageFactory";
-import { screen } from "@testing-library/react";
+import { screen, waitFor } from "@testing-library/react";
import { GoogleSheetFactory } from "test/factories/Actions/GoogleSheetFactory";
const FeatureFlags = {
@@ -24,8 +24,8 @@ const basePageId = "0123456789abcdef00000000";
describe("IDE URL rendering of Queries", () => {
localStorage.setItem("SPLITPANE_ANNOUNCEMENT", "false");
describe("Query Blank State", () => {
- it("Renders Fullscreen Blank State", () => {
- const { getByRole, getByText } = render(
+ it("Renders Fullscreen Blank State", async () => {
+ const { findByText, getByRole, getByText } = render(
,
@@ -36,7 +36,7 @@ describe("IDE URL rendering of Queries", () => {
);
// Main pane text
- getByText(createMessage(EDITOR_PANE_TEXTS.query_blank_state));
+ await findByText(createMessage(EDITOR_PANE_TEXTS.query_blank_state));
// Left pane text
getByText(createMessage(EDITOR_PANE_TEXTS.query_blank_state_description));
@@ -69,8 +69,8 @@ describe("IDE URL rendering of Queries", () => {
getByText(/new query \/ api/i);
});
- it("Renders Fullscreen Add in Blank State", () => {
- const { getByTestId, getByText } = render(
+ it("Renders Fullscreen Add in Blank State", async () => {
+ const { findByText, getByTestId, getByText } = render(
,
@@ -81,7 +81,9 @@ describe("IDE URL rendering of Queries", () => {
);
// Create options are rendered
- getByText(createMessage(EDITOR_PANE_TEXTS.queries_create_from_existing));
+ await findByText(
+ createMessage(EDITOR_PANE_TEXTS.queries_create_from_existing),
+ );
getByText("New datasource");
getByText("REST API");
// Check new tab presence
@@ -130,7 +132,7 @@ describe("IDE URL rendering of Queries", () => {
});
describe("API Routes", () => {
- it("Renders Api routes in Full screen", () => {
+ it("Renders Api routes in Full screen", async () => {
const page = PageFactory.build();
const anApi = APIFactory.build({ pageId: page.pageId });
const state = getIDETestState({
@@ -153,6 +155,15 @@ describe("IDE URL rendering of Queries", () => {
},
);
+ await waitFor(
+ async () => {
+ const elements = getAllByText("Api1"); // Use the common test ID or selector
+
+ expect(elements).toHaveLength(3); // Wait until there are exactly 3 elements
+ },
+ { timeout: 3000, interval: 500 },
+ );
+
// There will be 3 Api1 text (Left pane list, editor tab and Editor form)
expect(getAllByText("Api1").length).toEqual(3);
// Left pane active state
@@ -343,6 +354,14 @@ describe("IDE URL rendering of Queries", () => {
},
);
+ await waitFor(
+ async () => {
+ const elements = getAllByText("Query1"); // Use the common test ID or selector
+
+ expect(elements).toHaveLength(3); // Wait until there are exactly 3 elements
+ },
+ { timeout: 3000, interval: 500 },
+ );
// There will be 3 Query1 text (Left pane list, editor tab and Editor form)
expect(getAllByText("Query1").length).toBe(3);
// Left pane active state
diff --git a/app/client/src/pages/Editor/JSEditor/JSBlankState.tsx b/app/client/src/pages/Editor/JSEditor/JSBlankState.tsx
index acf141ca0bec..303f41b1893b 100644
--- a/app/client/src/pages/Editor/JSEditor/JSBlankState.tsx
+++ b/app/client/src/pages/Editor/JSEditor/JSBlankState.tsx
@@ -26,4 +26,4 @@ const JSBlankState = () => {
);
};
-export { JSBlankState };
+export default JSBlankState;
diff --git a/app/client/src/pages/Editor/JSEditor/index.tsx b/app/client/src/pages/Editor/JSEditor/index.tsx
index e625d5057013..6fcd8956119b 100644
--- a/app/client/src/pages/Editor/JSEditor/index.tsx
+++ b/app/client/src/pages/Editor/JSEditor/index.tsx
@@ -15,7 +15,6 @@ import AppJSEditorContextMenu from "./AppJSEditorContextMenu";
import { updateFunctionProperty } from "actions/jsPaneActions";
import type { OnUpdateSettingsProps } from "./JSEditorToolbar";
import { saveJSObjectName } from "actions/jsActionActions";
-
const LoadingContainer = styled(CenteredWrapper)`
height: 50%;
`;
diff --git a/app/client/src/pages/Editor/QueryEditor/QueriesBlankState.tsx b/app/client/src/pages/Editor/QueryEditor/QueriesBlankState.tsx
index 2b6aae11ce00..0f23cd2c0751 100644
--- a/app/client/src/pages/Editor/QueryEditor/QueriesBlankState.tsx
+++ b/app/client/src/pages/Editor/QueryEditor/QueriesBlankState.tsx
@@ -26,4 +26,4 @@ const QueriesBlankState = () => {
);
};
-export { QueriesBlankState };
+export default QueriesBlankState;