diff --git a/app/client/cypress/e2e/Regression/ClientSide/IDE/IDE_Add_Pane_Interactions_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/IDE/IDE_Add_Pane_Interactions_spec.ts
index e8bd59c4233b..0a1126ee2991 100644
--- a/app/client/cypress/e2e/Regression/ClientSide/IDE/IDE_Add_Pane_Interactions_spec.ts
+++ b/app/client/cypress/e2e/Regression/ClientSide/IDE/IDE_Add_Pane_Interactions_spec.ts
@@ -68,7 +68,7 @@ describe("IDE add pane interactions", { tags: ["@tag.IDE"] }, () => {
// check add pane
PageLeftPane.assertInAddView();
// close add tab
- FileTabs.closeTab("new_query");
+ FileTabs.closeTab("new");
// open add pane to add item
PageLeftPane.switchToAddNew();
// add item
diff --git a/app/client/cypress/support/Pages/IDE/FileTabs.ts b/app/client/cypress/support/Pages/IDE/FileTabs.ts
index 2557436a1b35..24bfa7bb53e1 100644
--- a/app/client/cypress/support/Pages/IDE/FileTabs.ts
+++ b/app/client/cypress/support/Pages/IDE/FileTabs.ts
@@ -1,10 +1,8 @@
import { ObjectsRegistry } from "../../Objects/Registry";
-import { sanitizeString } from "../../../../src/utils/URLUtils";
class FileTabs {
locators = {
container: "[data-testid='t--editor-tabs']",
- tabName: (name: string) =>
- `[data-testid='t--ide-tab-${sanitizeString(name)}']`,
+ tabName: (name: string) => `[data-testid='t--ide-tab-${name}']`,
tabs: ".editor-tab",
addItem: "[data-testid='t--ide-tabs-add-button']",
closeTab: "[data-testid='t--tab-close-btn']",
diff --git a/app/client/src/IDE/Components/FileTab.tsx b/app/client/src/IDE/Components/FileTab.tsx
deleted file mode 100644
index ec32b7739666..000000000000
--- a/app/client/src/IDE/Components/FileTab.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-import clsx from "classnames";
-
-import { Flex, Icon } from "design-system";
-import { sanitizeString } from "utils/URLUtils";
-
-interface FileTabProps {
- isActive: boolean;
- title: string;
- onClick: () => void;
- onClose: (e: React.MouseEvent) => void;
- icon?: React.ReactNode;
-}
-
-export const StyledTab = styled(Flex)`
- position: relative;
- height: 100%;
- font-size: 12px;
- color: var(--ads-v2-colors-text-default);
- cursor: pointer;
- gap: var(--ads-v2-spaces-2);
- border-top: 1px solid transparent;
- border-top-left-radius: var(--ads-v2-border-radius);
- border-top-right-radius: var(--ads-v2-border-radius);
- align-items: center;
- justify-content: center;
- padding: var(--ads-v2-spaces-3);
- border-left: 1px solid transparent;
- border-right: 1px solid transparent;
- border-top: 2px solid transparent;
-
- &.active {
- background: var(--ads-v2-colors-control-field-default-bg);
- border-top-color: var(--ads-v2-color-bg-brand);
- border-left-color: var(--ads-v2-color-border-muted);
- border-right-color: var(--ads-v2-color-border-muted);
- }
-
- & > .tab-close {
- position: relative;
- right: -2px;
- visibility: hidden;
- }
-
- &:hover > .tab-close {
- visibility: visible;
- }
-
- &.active > .tab-close {
- visibility: visible;
- }
-`;
-
-export const TabTextContainer = styled.span`
- width: 100%;
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
-`;
-
-export const TabIconContainer = styled.div`
- height: 12px;
- width: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- img {
- width: 12px;
- }
-`;
-
-export const FileTab = ({
- icon,
- isActive,
- onClick,
- onClose,
- title,
-}: FileTabProps) => {
- return (
-
- {icon ? {icon} : null}
- {title}
- {/* not using button component because of the size not matching design */}
-
-
- );
-};
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.ts
index 6d5a2c96abb3..71130f46e1cf 100644
--- a/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.ts
+++ b/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/hooks.ts
@@ -17,7 +17,6 @@ import history from "utils/history";
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
import { useModuleOptions } from "@appsmith/utils/moduleInstanceHelpers";
import { getJSUrl } from "@appsmith/pages/Editor/IDE/EditorPane/JS/utils";
-import { JSBlankState } from "pages/Editor/JSEditor/JSBlankState";
export const useJSAdd = () => {
const pageId = useSelector(getCurrentPageId);
@@ -96,7 +95,7 @@ export const useJSSegmentRoutes = (path: string): UseRoutes => {
},
{
key: "JSEmpty",
- component: JSBlankState,
+ component: ListJS,
exact: true,
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 3eedf95b8740..90b37aee232f 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
@@ -38,7 +38,6 @@ import { Tag, type ListItemProps } from "design-system";
import { useCurrentEditorState } from "pages/Editor/IDE/hooks";
import CurlImportEditor from "pages/Editor/APIEditor/CurlImportEditor";
import { createAddClassName } from "pages/Editor/IDE/EditorPane/utils";
-import { QueriesBlankState } from "pages/Editor/QueryEditor/QueriesBlankState";
export const useQueryAdd = () => {
const location = useLocation();
@@ -162,7 +161,7 @@ export const useQuerySegmentRoutes = (path: string): UseRoutes => {
},
{
key: "QueryEmpty",
- component: QueriesBlankState,
+ component: ListQuery,
exact: true,
path: [path],
},
diff --git a/app/client/src/ce/selectors/appIDESelectors.ts b/app/client/src/ce/selectors/appIDESelectors.ts
index af37fe267181..dfd9faa67873 100644
--- a/app/client/src/ce/selectors/appIDESelectors.ts
+++ b/app/client/src/ce/selectors/appIDESelectors.ts
@@ -6,7 +6,6 @@ import {
getQuerySegmentItems,
} from "@appsmith/selectors/entitiesSelector";
import { getJSTabs, getQueryTabs } from "selectors/ideSelectors";
-import type { AppState } from "@appsmith/reducers";
export type EditorSegmentList = Array<{
group: string | "NA";
@@ -46,22 +45,28 @@ export const selectJSSegmentEditorList = createSelector(
},
);
-export const selectJSSegmentEditorTabs = (state: AppState) => {
- const items = getJSSegmentItems(state);
- const tabs = getJSTabs(state);
-
- const keyedItems = keyBy(items, "key");
- return tabs
- .map((tab) => {
- return keyedItems[tab];
- })
- .filter(Boolean);
-};
-
-export const selectQuerySegmentEditorTabs = (state: AppState) => {
- const items = getQuerySegmentItems(state);
- const tabs = getQueryTabs(state);
+export const selectJSSegmentEditorTabs = createSelector(
+ getJSSegmentItems,
+ getJSTabs,
+ (items, tabs) => {
+ const keyedItems = keyBy(items, "key");
+ return tabs
+ .map((tab) => {
+ return keyedItems[tab];
+ })
+ .filter(Boolean);
+ },
+);
- const keyedItems = keyBy(items, "key");
- return tabs.map((tab) => keyedItems[tab]).filter(Boolean);
-};
+export const selectQuerySegmentEditorTabs = createSelector(
+ getQuerySegmentItems,
+ getQueryTabs,
+ (items, tabs) => {
+ const keyedItems = keyBy(items, "key");
+ return tabs
+ .map((tab) => {
+ return keyedItems[tab];
+ })
+ .filter(Boolean);
+ },
+);
diff --git a/app/client/src/pages/Editor/IDE/EditorPane/EditorPaneSegments.tsx b/app/client/src/pages/Editor/IDE/EditorPane/EditorPaneSegments.tsx
index 5d44ec5edf28..c2daef1f8322 100644
--- a/app/client/src/pages/Editor/IDE/EditorPane/EditorPaneSegments.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorPane/EditorPaneSegments.tsx
@@ -6,7 +6,7 @@ import QueriesSegment from "./Query";
import WidgetsSegment from "./UI";
import JSSegment from "./JS";
import SegmentedHeader from "./components/SegmentedHeader";
-import EditorTabs from "../EditorTabs";
+import EditorTabs from "../EditorTabs/SplitScreenTabs";
import {
jsSegmentRoutes,
querySegmentRoutes,
@@ -17,23 +17,19 @@ import {
BUILDER_PATH,
BUILDER_PATH_DEPRECATED,
} from "@appsmith/constants/routes/appRoutes";
-import { useSelector } from "react-redux";
-import { getIDEViewMode } from "selectors/ideSelectors";
-import { EditorViewMode } from "@appsmith/entities/IDE/constants";
const EditorPaneSegments = () => {
const { path } = useRouteMatch();
- const ideViewMode = useSelector(getIDEViewMode);
return (
- {ideViewMode === EditorViewMode.SplitScreen ? : null}
+
{
).toBe(true);
// Tabs active state
expect(
- getByTestId("t--ide-tab-jsobject1").classList.contains("active"),
+ getByTestId("t--ide-tab-JSObject1").classList.contains("active"),
).toBe(true);
// Check if the form is rendered
expect(container.querySelector(".js-editor-tab")).not.toBeNull();
@@ -201,7 +201,7 @@ describe("IDE Render: JS", () => {
expect(getAllByText("JSObject2").length).toBe(2);
// Tabs active state
expect(
- getByTestId("t--ide-tab-jsobject2").classList.contains("active"),
+ getByTestId("t--ide-tab-JSObject2").classList.contains("active"),
).toBe(true);
// Check if the form is rendered
@@ -245,7 +245,7 @@ describe("IDE Render: JS", () => {
expect(getAllByText("JSObject3").length).toEqual(2);
// Tabs active state
expect(
- getByTestId("t--ide-tab-jsobject3").classList.contains("active"),
+ getByTestId("t--ide-tab-JSObject3").classList.contains("active"),
).toBe(false);
// Check js object is not rendered. Instead new tab should render
expect(container.querySelector(".js-editor-tab")).toBeNull();
@@ -283,7 +283,7 @@ describe("IDE Render: JS", () => {
expect(getAllByText("JSObject4").length).toEqual(1);
// Tabs active state
expect(
- getByTestId("t--ide-tab-jsobject4").classList.contains("active"),
+ getByTestId("t--ide-tab-JSObject4").classList.contains("active"),
).toBe(false);
// Check if the form is not rendered
diff --git a/app/client/src/pages/Editor/IDE/EditorPane/JS/List.tsx b/app/client/src/pages/Editor/IDE/EditorPane/JS/List.tsx
index b3e21a8014eb..ccf56595ff1d 100644
--- a/app/client/src/pages/Editor/IDE/EditorPane/JS/List.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorPane/JS/List.tsx
@@ -51,7 +51,6 @@ const ListJSObjects = () => {
return (
{
>
{
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
@@ -121,7 +121,7 @@ describe("IDE URL rendering of Queries", () => {
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
@@ -161,7 +161,7 @@ describe("IDE URL rendering of Queries", () => {
getByTestId("t--entity-item-Api1").classList.contains("active"),
).toBe(true);
// Tabs active state
- expect(getByTestId("t--ide-tab-api1").classList.contains("active")).toBe(
+ expect(getByTestId("t--ide-tab-Api1").classList.contains("active")).toBe(
true,
);
// Check if the form is rendered
@@ -205,7 +205,7 @@ describe("IDE URL rendering of Queries", () => {
// Check if api is rendered in side by side
expect(getAllByText("Api2").length).toBe(2);
// Tabs active state
- expect(getByTestId("t--ide-tab-api2").classList.contains("active")).toBe(
+ expect(getByTestId("t--ide-tab-Api2").classList.contains("active")).toBe(
true,
);
// Check if the form is rendered
@@ -244,7 +244,7 @@ describe("IDE URL rendering of Queries", () => {
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
@@ -278,7 +278,7 @@ describe("IDE URL rendering of Queries", () => {
// There will be 1 Api4 text ( The tab )
expect(getAllByText("Api4").length).toEqual(1);
// Tabs active state
- expect(getByTestId("t--ide-tab-api4").classList.contains("active")).toBe(
+ expect(getByTestId("t--ide-tab-Api4").classList.contains("active")).toBe(
false,
);
// Add button should not present
@@ -291,7 +291,7 @@ describe("IDE URL rendering of Queries", () => {
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
@@ -336,7 +336,7 @@ describe("IDE URL rendering of Queries", () => {
).toBe(true);
// Tabs active state
expect(
- getByTestId("t--ide-tab-query1").classList.contains("active"),
+ getByTestId("t--ide-tab-Query1").classList.contains("active"),
).toBe(true);
await userEvent.click(getByRole("tab", { name: "Query" }));
@@ -384,7 +384,7 @@ describe("IDE URL rendering of Queries", () => {
expect(getAllByText("Query2").length).toBe(2);
// Tabs active state
expect(
- getByTestId("t--ide-tab-query2").classList.contains("active"),
+ getByTestId("t--ide-tab-Query2").classList.contains("active"),
).toBe(true);
await userEvent.click(getByRole("tab", { name: "Query" }));
@@ -430,7 +430,7 @@ describe("IDE URL rendering of Queries", () => {
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
@@ -469,7 +469,7 @@ describe("IDE URL rendering of Queries", () => {
expect(getAllByText("Query4").length).toEqual(1);
// Tabs active state
expect(
- getByTestId("t--ide-tab-query4").classList.contains("active"),
+ getByTestId("t--ide-tab-Query4").classList.contains("active"),
).toBe(false);
// Add button should not present
expect(queryByTestId("t--ide-tabs-add-button")).toBeNull();
@@ -481,7 +481,7 @@ describe("IDE URL rendering of Queries", () => {
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
@@ -527,7 +527,7 @@ describe("IDE URL rendering of Queries", () => {
).toBe(true);
// Tabs active state
expect(
- getByTestId("t--ide-tab-sheets1").classList.contains("active"),
+ getByTestId("t--ide-tab-Sheets1").classList.contains("active"),
).toBe(true);
await userEvent.click(getByRole("tab", { name: "Query" }));
@@ -576,7 +576,7 @@ describe("IDE URL rendering of Queries", () => {
expect(getAllByText("Sheets2").length).toBe(2);
// Tabs active state
expect(
- getByTestId("t--ide-tab-sheets2").classList.contains("active"),
+ getByTestId("t--ide-tab-Sheets2").classList.contains("active"),
).toBe(true);
await userEvent.click(getByRole("tab", { name: "Query" }));
@@ -625,7 +625,7 @@ describe("IDE URL rendering of Queries", () => {
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
@@ -665,7 +665,7 @@ describe("IDE URL rendering of Queries", () => {
expect(getAllByText("Sheets4").length).toEqual(1);
// Tabs active state
expect(
- getByTestId("t--ide-tab-sheets4").classList.contains("active"),
+ getByTestId("t--ide-tab-Sheets4").classList.contains("active"),
).toBe(false);
// Add button active state
expect(queryByTestId("t--ide-tabs-add-button")).toBeNull();
@@ -677,7 +677,7 @@ describe("IDE URL rendering of Queries", () => {
getByText("New datasource");
getByText("REST API");
// Check new tab presence
- const newTab = getByTestId("t--ide-tab-new_query");
+ const newTab = getByTestId("t--ide-tab-new");
expect(newTab).not.toBeNull();
// Close button is rendered
expect(
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/AddTab.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/AddTab.tsx
deleted file mode 100644
index f5d3564a88bb..000000000000
--- a/app/client/src/pages/Editor/IDE/EditorTabs/AddTab.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from "react";
-
-import { FileTab } from "IDE/Components/FileTab";
-import { useCurrentEditorState } from "../hooks";
-import {
- EditorEntityTab,
- EditorEntityTabState,
-} from "@appsmith/entities/IDE/constants";
-
-const AddTab = ({
- isListActive,
- newTabClickCallback,
- onClose,
-}: {
- newTabClickCallback: () => void;
- onClose: (actionId?: string) => void;
- isListActive: boolean;
-}) => {
- const { segment, segmentMode } = useCurrentEditorState();
-
- if (segmentMode !== EditorEntityTabState.Add) return null;
-
- const onCloseClick = (e: React.MouseEvent) => {
- e.stopPropagation();
- onClose();
- };
-
- return (
- onCloseClick(e)}
- title={`New ${segment === EditorEntityTab.JS ? "JS" : "Query"}`}
- />
- );
-};
-
-export { AddTab };
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/Container.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/Container.tsx
index dbc77dd103f6..b248f9e5f969 100644
--- a/app/client/src/pages/Editor/IDE/EditorTabs/Container.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/Container.tsx
@@ -9,7 +9,6 @@ const Container = (props: { children: ReactNode }) => {
backgroundColor="#FFFFFF"
borderBottom="1px solid var(--ads-v2-color-border-muted)"
gap="spaces-2"
- id="ide-tabs-container"
maxHeight="32px"
minHeight="32px"
px="spaces-2"
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.test.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.test.tsx
index be5f41c683ac..8b00ea582459 100644
--- a/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.test.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.test.tsx
@@ -1,10 +1,8 @@
import React from "react";
import { fireEvent, render } from "test/testUtils";
import FileTabs from "./FileTabs";
-import { EditorState, type EntityItem } from "@appsmith/entities/IDE/constants";
+import type { EntityItem } from "@appsmith/entities/IDE/constants";
import { PluginType } from "entities/Action";
-import { FocusEntity } from "navigation/FocusEntity";
-import { sanitizeString } from "utils/URLUtils";
describe("FileTabs", () => {
const mockTabs: EntityItem[] = [
@@ -16,26 +14,22 @@ describe("FileTabs", () => {
const mockNavigateToTab = jest.fn();
const mockOnClose = jest.fn();
- const activeEntity = {
- entity: FocusEntity.API,
- id: "File 1",
- appState: EditorState.EDITOR,
- params: {},
- };
it("renders tabs correctly", () => {
const { getByTestId, getByText } = render(
,
);
+ const editorTabsContainer = getByTestId("t--editor-tabs");
+ expect(editorTabsContainer).not.toBeNull();
+
// Check if each tab is rendered with correct content
mockTabs.forEach((tab) => {
- const tabElement = getByTestId(`t--ide-tab-${sanitizeString(tab.title)}`);
+ const tabElement = getByTestId(`t--ide-tab-${tab.title}`);
expect(tabElement).not.toBeNull();
const tabTitleElement = getByText(tab.title);
@@ -46,15 +40,12 @@ describe("FileTabs", () => {
it("check tab click", () => {
const { getByTestId } = render(
,
);
- const tabElement = getByTestId(
- `t--ide-tab-${sanitizeString(mockTabs[0].title)}`,
- );
+ const tabElement = getByTestId(`t--ide-tab-${mockTabs[0].title}`);
fireEvent.click(tabElement);
expect(mockNavigateToTab).toHaveBeenCalledWith(mockTabs[0]);
@@ -63,15 +54,12 @@ describe("FileTabs", () => {
it("check for close click", () => {
const { getByTestId } = render(
,
);
- const tabElement = getByTestId(
- `t--ide-tab-${sanitizeString(mockTabs[1].title)}`,
- );
+ const tabElement = getByTestId(`t--ide-tab-${mockTabs[1].title}`);
const closeElement = tabElement.querySelector(
"[data-testid='t--tab-close-btn']",
) as HTMLElement;
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.tsx
index 215ccca50c17..90499d2b984f 100644
--- a/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.tsx
@@ -1,24 +1,54 @@
-import React from "react";
+import React, { useEffect } from "react";
+import { useLocation } from "react-router";
+import clsx from "classnames";
+import { Flex, Icon, ScrollArea } from "design-system";
import {
+ EditorEntityTab,
EditorEntityTabState,
type EntityItem,
} from "@appsmith/entities/IDE/constants";
+import {
+ StyledTab,
+ TabIconContainer,
+ TabTextContainer,
+} from "./StyledComponents";
+import { identifyEntityFromPath } from "navigation/FocusEntity";
import { useCurrentEditorState } from "../hooks";
-import { FileTab } from "IDE/Components/FileTab";
-import type { FocusEntityInfo } from "navigation/FocusEntity";
interface Props {
tabs: EntityItem[];
navigateToTab: (tab: EntityItem) => void;
onClose: (actionId?: string) => void;
- currentEntity: FocusEntityInfo;
- isListActive?: boolean;
}
+const FILE_TABS_CONTAINER_ID = "file-tabs-container";
+
const FileTabs = (props: Props) => {
- const { currentEntity, isListActive, navigateToTab, onClose, tabs } = props;
- const { segmentMode } = useCurrentEditorState();
+ const { navigateToTab, onClose, tabs } = props;
+ const { segment, segmentMode } = useCurrentEditorState();
+
+ const location = useLocation();
+
+ const currentEntity = identifyEntityFromPath(location.pathname);
+
+ useEffect(() => {
+ const activetab = document.querySelector(".editor-tab.active");
+ if (activetab) {
+ activetab.scrollIntoView({
+ inline: "nearest",
+ });
+ }
+ }, [tabs, segmentMode]);
+
+ useEffect(() => {
+ const ele = document.getElementById(FILE_TABS_CONTAINER_ID)?.parentElement;
+ if (ele && ele.scrollWidth > ele.clientWidth) {
+ ele.style.borderRight = "1px solid var(--ads-v2-color-border)";
+ } else if (ele) {
+ ele.style.borderRight = "unset";
+ }
+ }, [tabs]);
const onCloseClick = (e: React.MouseEvent, id?: string) => {
e.stopPropagation();
@@ -26,22 +56,59 @@ const FileTabs = (props: Props) => {
};
return (
- <>
- {tabs.map((tab: EntityItem) => (
- navigateToTab(tab)}
- onClose={(e) => onCloseClick(e, tab.key)}
- title={tab.title}
- />
- ))}
- >
+
+
+ {tabs.map((tab: EntityItem) => (
+ navigateToTab(tab)}
+ >
+ {tab.icon}
+ {tab.title}
+ {/* not using button component because of the size not matching design */}
+ onCloseClick(e, tab.key)}
+ />
+
+ ))}
+ {/* New Tab */}
+ {segmentMode === EditorEntityTabState.Add ? (
+
+
+ New {segment === EditorEntityTab.JS ? "JS" : "Query"}
+
+ {/* not using button component because of the size not matching design */}
+ onCloseClick(e)}
+ />
+
+ ) : null}
+
+
);
};
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx
new file mode 100644
index 000000000000..f9a3f14c5f0f
--- /dev/null
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/FullScreenTabs.tsx
@@ -0,0 +1,67 @@
+import React, { useCallback } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { Button, Tooltip } from "design-system";
+import { getIDEViewMode, getIsSideBySideEnabled } from "selectors/ideSelectors";
+import {
+ EditorEntityTab,
+ EditorViewMode,
+} from "@appsmith/entities/IDE/constants";
+import { setIdeEditorViewMode } from "actions/ideActions";
+import FileTabs from "./FileTabs";
+import Container from "./Container";
+import { useCurrentEditorState, useIDETabClickHandlers } from "../hooks";
+import { TabSelectors } from "./constants";
+import {
+ MINIMIZE_BUTTON_TOOLTIP,
+ createMessage,
+} from "@appsmith/constants/messages";
+import AnalyticsUtil from "@appsmith/utils/AnalyticsUtil";
+import { AddButton } from "./AddButton";
+
+const FullScreenTabs = () => {
+ const dispatch = useDispatch();
+ const isSideBySideEnabled = useSelector(getIsSideBySideEnabled);
+ const ideViewMode = useSelector(getIDEViewMode);
+ const { segment } = useCurrentEditorState();
+ const { closeClickHandler, tabClickHandler } = useIDETabClickHandlers();
+
+ const setSplitScreenMode = useCallback(() => {
+ dispatch(setIdeEditorViewMode(EditorViewMode.SplitScreen));
+ AnalyticsUtil.logEvent("EDITOR_MODE_CHANGE", {
+ to: EditorViewMode.SplitScreen,
+ });
+ }, []);
+ const tabsConfig = TabSelectors[segment];
+
+ const files = useSelector(tabsConfig.tabsSelector);
+
+ if (!isSideBySideEnabled) return null;
+ if (ideViewMode === EditorViewMode.SplitScreen) return null;
+ if (segment === EditorEntityTab.UI) return null;
+ return (
+
+
+ {files.length > 0 ? : null}
+
+
+
+
+ );
+};
+
+export default FullScreenTabs;
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/List.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/List.tsx
deleted file mode 100644
index b053c6d9c1e3..000000000000
--- a/app/client/src/pages/Editor/IDE/EditorTabs/List.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-import { Flex } from "design-system";
-
-import { useCurrentEditorState } from "../hooks";
-import { EditorEntityTab } from "@appsmith/entities/IDE/constants";
-import ListQuery from "../EditorPane/Query/List";
-import ListJSObjects from "../EditorPane/JS/List";
-
-const ListContainer = styled(Flex)`
- & .t--entity-item {
- grid-template-columns: 0 auto 1fr auto auto auto auto auto;
- height: 32px;
-
- & .t--entity-name {
- padding-left: var(--ads-v2-spaces-3);
- }
- }
-`;
-
-export const List = () => {
- const { segment } = useCurrentEditorState();
-
- return (
-
- {segment === EditorEntityTab.QUERIES ? : }
-
- );
-};
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/ListButton.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/ListButton.tsx
index 1f6abf2f6a68..503f09088967 100644
--- a/app/client/src/pages/Editor/IDE/EditorTabs/ListButton.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/ListButton.tsx
@@ -9,7 +9,7 @@ import {
MenuTrigger,
Text,
} from "design-system";
-import { ListIconContainer, ListTitle } from "./StyledComponents";
+import { ListIconContainer, TabTextContainer } from "./StyledComponents";
interface Props {
items: EntityItem[];
@@ -50,7 +50,7 @@ const ListButton = (props: Props) => {
gap="spaces-2"
>
{item.icon}
- {item.title}
+ {item.title}
))}
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/ScreenModeToggle.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/ScreenModeToggle.tsx
deleted file mode 100644
index 13eb9dd1c770..000000000000
--- a/app/client/src/pages/Editor/IDE/EditorTabs/ScreenModeToggle.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import React, { useCallback } from "react";
-import { useDispatch, useSelector } from "react-redux";
-import { Button, Tooltip } from "design-system";
-
-import { getIDEViewMode } from "selectors/ideSelectors";
-import { EditorViewMode } from "@appsmith/entities/IDE/constants";
-import AnalyticsUtil from "@appsmith/utils/AnalyticsUtil";
-import {
- MAXIMIZE_BUTTON_TOOLTIP,
- MINIMIZE_BUTTON_TOOLTIP,
- createMessage,
-} from "@appsmith/constants/messages";
-import { setIdeEditorViewMode } from "actions/ideActions";
-
-export const ScreenModeToggle = () => {
- const dispatch = useDispatch();
- const ideViewMode = useSelector(getIDEViewMode);
-
- const toggleEditorMode = useCallback(() => {
- const newMode =
- ideViewMode === EditorViewMode.SplitScreen
- ? EditorViewMode.FullScreen
- : EditorViewMode.SplitScreen;
-
- AnalyticsUtil.logEvent("EDITOR_MODE_CHANGE", {
- to: newMode,
- });
- dispatch(setIdeEditorViewMode(newMode));
- }, [ideViewMode, dispatch]);
-
- return (
-
-
-
- );
-};
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/SearchableFilesList.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/SearchableFilesList.tsx
index 62358727c470..8b058b55ebdf 100644
--- a/app/client/src/pages/Editor/IDE/EditorTabs/SearchableFilesList.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/SearchableFilesList.tsx
@@ -13,7 +13,7 @@ import {
MenuTrigger,
SearchInput,
} from "design-system";
-import { ListIconContainer, ListTitle } from "./StyledComponents";
+import { ListIconContainer, TabTextContainer } from "./StyledComponents";
interface Props {
allItems: EntityItem[];
@@ -64,7 +64,7 @@ const SearchableFilesList = (props: Props) => {
gap="spaces-2"
>
{file.icon}
- {file.title}
+ {file.title}
));
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/SplitScreenTabs.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/SplitScreenTabs.tsx
new file mode 100644
index 000000000000..dd4f490b1bc4
--- /dev/null
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/SplitScreenTabs.tsx
@@ -0,0 +1,79 @@
+import React, { useCallback } from "react";
+
+import FileTabs from "./FileTabs";
+import { useDispatch, useSelector } from "react-redux";
+import { getIDEViewMode, getIsSideBySideEnabled } from "selectors/ideSelectors";
+import Container from "./Container";
+import { useCurrentEditorState, useIDETabClickHandlers } from "../hooks";
+import {
+ EditorEntityTab,
+ EditorViewMode,
+} from "@appsmith/entities/IDE/constants";
+import { TabSelectors } from "./constants";
+import { Announcement } from "../EditorPane/components/Announcement";
+import { SearchableFilesList } from "./SearchableFilesList";
+import { AddButton } from "./AddButton";
+import { Button, Tooltip } from "design-system";
+import {
+ MAXIMIZE_BUTTON_TOOLTIP,
+ createMessage,
+} from "@appsmith/constants/messages";
+import AnalyticsUtil from "@appsmith/utils/AnalyticsUtil";
+import { setIdeEditorViewMode } from "actions/ideActions";
+
+const SplitScreenTabs = () => {
+ const dispatch = useDispatch();
+ const isSideBySideEnabled = useSelector(getIsSideBySideEnabled);
+ const ideViewMode = useSelector(getIDEViewMode);
+ const { segment } = useCurrentEditorState();
+ const { closeClickHandler, tabClickHandler } = useIDETabClickHandlers();
+
+ const tabsConfig = TabSelectors[segment];
+
+ const files = useSelector(tabsConfig.tabsSelector);
+ const allFilesList = useSelector(tabsConfig.listSelector);
+
+ const handleMaximizeButtonClick = useCallback(() => {
+ AnalyticsUtil.logEvent("EDITOR_MODE_CHANGE", {
+ to: EditorViewMode.FullScreen,
+ });
+ dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen));
+ }, []);
+
+ if (!isSideBySideEnabled) return null;
+ if (ideViewMode === EditorViewMode.FullScreen) return null;
+ if (segment === EditorEntityTab.UI) return null;
+
+ return (
+ <>
+ {/* {files.length > 0 ? ( */}
+
+
+
+ {files.length > 0 ? : null}
+
+
+
+
+
+
+ >
+ );
+};
+
+export default SplitScreenTabs;
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/StyledComponents.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/StyledComponents.tsx
index d396860bfde6..66e40cd39356 100644
--- a/app/client/src/pages/Editor/IDE/EditorTabs/StyledComponents.tsx
+++ b/app/client/src/pages/Editor/IDE/EditorTabs/StyledComponents.tsx
@@ -1,4 +1,77 @@
import styled from "styled-components";
+import { Flex } from "design-system";
+
+/**
+ * Logic for 54px in max width
+ *
+ * 4px tabs + add icon container left padding
+ * 4px tabs + add icon container right padding
+ * 4px gap between tabs and add icon
+ * 16px 4px gap between every tabs * 4 (since max tab count is 5,
+ * there will be 5 gaps)
+ * 26px Add button width
+ * 62px show more list button(considering 3 digit width as max)
+ * ======================================
+ * 127px
+ *
+ */
+export const StyledTab = styled(Flex)`
+ position: relative;
+ top: 1px;
+ font-size: 12px;
+ color: var(--ads-v2-colors-text-default);
+ cursor: pointer;
+ gap: var(--ads-v2-spaces-2);
+ border-top: 1px solid transparent;
+ border-top-left-radius: var(--ads-v2-border-radius);
+ border-top-right-radius: var(--ads-v2-border-radius);
+ align-items: center;
+ justify-content: center;
+ padding: var(--ads-v2-spaces-3);
+ border-left: 1px solid transparent;
+ border-right: 1px solid transparent;
+ border-top: 2px solid transparent;
+
+ &.active {
+ background: var(--ads-v2-colors-control-field-default-bg);
+ border-top-color: var(--ads-v2-color-bg-brand);
+ border-left-color: var(--ads-v2-color-border-muted);
+ border-right-color: var(--ads-v2-color-border-muted);
+ }
+
+ & > .tab-close {
+ position: relative;
+ right: -2px;
+ visibility: hidden;
+ }
+
+ &:hover > .tab-close {
+ visibility: visible;
+ }
+
+ &.active > .tab-close {
+ visibility: visible;
+ }
+`;
+
+export const TabTextContainer = styled.span`
+ width: 100%;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+`;
+
+export const TabIconContainer = styled.div`
+ height: 12px;
+ width: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ img {
+ width: 12px;
+ }
+`;
export const ListIconContainer = styled.div`
height: 18px;
@@ -11,10 +84,3 @@ export const ListIconContainer = styled.div`
width: 18px;
}
`;
-
-export const ListTitle = styled.span`
- width: 100%;
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
-`;
diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/index.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/index.tsx
deleted file mode 100644
index b3e1bd10773d..000000000000
--- a/app/client/src/pages/Editor/IDE/EditorTabs/index.tsx
+++ /dev/null
@@ -1,138 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { shallowEqual, useSelector } from "react-redux";
-import { Flex, ScrollArea, ToggleButton } from "design-system";
-import { getIDEViewMode, getIsSideBySideEnabled } from "selectors/ideSelectors";
-import type { EntityItem } from "@appsmith/entities/IDE/constants";
-import {
- EditorEntityTab,
- EditorEntityTabState,
- EditorViewMode,
-} from "@appsmith/entities/IDE/constants";
-import FileTabs from "./FileTabs";
-import Container from "./Container";
-import { useCurrentEditorState, useIDETabClickHandlers } from "../hooks";
-import { TabSelectors } from "./constants";
-import { AddButton } from "./AddButton";
-import { Announcement } from "../EditorPane/components/Announcement";
-import { useLocation } from "react-router";
-import { identifyEntityFromPath } from "navigation/FocusEntity";
-import { List } from "./List";
-import { ScreenModeToggle } from "./ScreenModeToggle";
-import { AddTab } from "./AddTab";
-
-const EditorTabs = () => {
- const [showListView, setShowListView] = useState(false);
- const isSideBySideEnabled = useSelector(getIsSideBySideEnabled);
- const ideViewMode = useSelector(getIDEViewMode);
- const { segment, segmentMode } = useCurrentEditorState();
- const { closeClickHandler, tabClickHandler } = useIDETabClickHandlers();
- const tabsConfig = TabSelectors[segment];
- const files = useSelector(tabsConfig.tabsSelector, shallowEqual);
-
- const location = useLocation();
- const currentEntity = identifyEntityFromPath(location.pathname);
-
- // Turn off list view while changing segment, files
- useEffect(() => {
- setShowListView(false);
- }, [currentEntity.id, currentEntity.entity, files, segmentMode]);
-
- // Show list view if all tabs is closed
- useEffect(() => {
- if (files.length === 0 && segmentMode !== EditorEntityTabState.Add) {
- setShowListView(true);
- }
- }, [files, segmentMode, currentEntity.entity]);
-
- // scroll to the active tab
- useEffect(() => {
- const activetab = document.querySelector(".editor-tab.active");
- if (activetab) {
- activetab.scrollIntoView({
- inline: "nearest",
- });
- }
- }, [files, segmentMode]);
-
- // show border if add button is sticky
- useEffect(() => {
- const ele = document.querySelector(
- '[data-testid="t--editor-tabs"] > [data-overlayscrollbars-viewport]',
- );
- if (ele && ele.scrollWidth > ele.clientWidth) {
- ele.style.borderRight = "1px solid var(--ads-v2-color-border)";
- } else if (ele) {
- ele.style.borderRight = "unset";
- }
- }, [files]);
-
- if (!isSideBySideEnabled) return null;
- if (segment === EditorEntityTab.UI) return null;
-
- const handleHamburgerClick = () => {
- if (files.length === 0 && segmentMode !== EditorEntityTabState.Add) return;
- setShowListView(!showListView);
- };
-
- const onTabClick = (tab: EntityItem) => {
- setShowListView(false);
- tabClickHandler(tab);
- };
-
- const newTabClickHandler = () => {
- setShowListView(false);
- };
-
- return (
- <>
-
- {ideViewMode === EditorViewMode.SplitScreen && (
-
- )}
-
-
-
-
-
-
-
- {files.length > 0 ? : null}
- {/* Switch screen mode button */}
-
-
-
- {/* Overflow list */}
- {showListView && ideViewMode === EditorViewMode.SplitScreen &&
}
-
- {/* Announcement modal */}
- {ideViewMode === EditorViewMode.SplitScreen && }
- >
- );
-};
-
-export default EditorTabs;
diff --git a/app/client/src/pages/Editor/IDE/MainPane/index.tsx b/app/client/src/pages/Editor/IDE/MainPane/index.tsx
index edae34902ad8..23973c915b6e 100644
--- a/app/client/src/pages/Editor/IDE/MainPane/index.tsx
+++ b/app/client/src/pages/Editor/IDE/MainPane/index.tsx
@@ -3,16 +3,12 @@ import { BUILDER_PATH } from "constants/routes";
import { Route, Switch, useRouteMatch } from "react-router";
import * as Sentry from "@sentry/react";
import useRoutes from "@appsmith/pages/Editor/IDE/MainPane/useRoutes";
-import EditorTabs from "pages/Editor/IDE/EditorTabs";
+import EditorTabs from "pages/Editor/IDE/EditorTabs/FullScreenTabs";
import { useWidgetSelectionBlockListener } from "pages/Editor/IDE/hooks";
-import { useSelector } from "react-redux";
-import { getIDEViewMode } from "selectors/ideSelectors";
-import { EditorViewMode } from "@appsmith/entities/IDE/constants";
const SentryRoute = Sentry.withSentryRouting(Route);
export const MainPane = (props: { id: string }) => {
const { path } = useRouteMatch();
- const ideViewMode = useSelector(getIDEViewMode);
const routes = useRoutes(path);
useWidgetSelectionBlockListener();
@@ -22,7 +18,7 @@ export const MainPane = (props: { id: string }) => {
data-testid="t--ide-main-pane"
id={props.id}
>
- {ideViewMode === EditorViewMode.FullScreen ? : null}
+
{routes.map((route) => (
diff --git a/app/client/src/pages/Editor/IDE/hooks.ts b/app/client/src/pages/Editor/IDE/hooks.ts
index c7cbb2549e49..ef4639e90119 100644
--- a/app/client/src/pages/Editor/IDE/hooks.ts
+++ b/app/client/src/pages/Editor/IDE/hooks.ts
@@ -214,7 +214,7 @@ export const useIDETabClickHandlers = () => {
);
const closeClickHandler = useCallback(
- (actionId?: string) => {
+ (actionId: string | undefined) => {
if (!actionId) {
// handle JS
return segment === EditorEntityTab.JS ? closeAddJS() : closeAddQuery();
diff --git a/app/client/src/utils/URLUtils.ts b/app/client/src/utils/URLUtils.ts
index b986f8aeb377..55b6b1a2d3e2 100644
--- a/app/client/src/utils/URLUtils.ts
+++ b/app/client/src/utils/URLUtils.ts
@@ -39,7 +39,3 @@ export function matchesURLPattern(url: string) {
) !== null
);
}
-
-export const sanitizeString = (str: string): string => {
- return str.toLowerCase().replace(/[^a-z0-9]/g, "_");
-};