Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Overflow tabs list view #34150

Merged
merged 21 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4f2ef49
feat: New ui for overflow tabs
albinAppsmith Jun 10, 2024
4eec56e
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 10, 2024
3031920
fix: new tab click fix
albinAppsmith Jun 10, 2024
914614d
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 10, 2024
1a499f3
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 17, 2024
f98571d
fix: optmised editortab component
albinAppsmith Jun 17, 2024
22b2dfb
chore: Optimisations
albinAppsmith Jun 19, 2024
000cde8
removed refs
albinAppsmith Jun 20, 2024
ad3f4e7
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 20, 2024
d31c64f
fix: seperated add button and tab
albinAppsmith Jun 20, 2024
8b98201
added border for sticky button
albinAppsmith Jun 21, 2024
e14a985
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 21, 2024
c1d0795
added missing dependency
albinAppsmith Jun 21, 2024
f89cecc
fix: removed scrollbar defer
albinAppsmith Jun 21, 2024
2703067
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 24, 2024
77611ad
fix: show list issues
albinAppsmith Jun 24, 2024
7d07044
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 24, 2024
43b8219
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 25, 2024
296c976
fix: cypress failures
albinAppsmith Jun 25, 2024
1c829af
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
albinAppsmith Jun 25, 2024
fb8addb
fix: jest test fix
albinAppsmith Jun 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions app/client/src/IDE/Components/FileTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from "react";
import styled from "styled-components";
import clsx from "classnames";

import { Flex, Icon } from "design-system";

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 (
<StyledTab
className={clsx("editor-tab", isActive && "active")}
data-testid={`t--ide-tab-${title}`}
onClick={onClick}
>
{icon ? <TabIconContainer>{icon}</TabIconContainer> : null}
<TabTextContainer>{title}</TabTextContainer>
{/* not using button component because of the size not matching design */}
<Icon
className="tab-close rounded-[4px] hover:bg-[var(--ads-v2-colors-action-tertiary-surface-hover-bg)] cursor-pointer p-[2px]"
data-testid="t--tab-close-btn"
name="close-line"
onClick={onClose}
/>
</StyledTab>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ 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();
Expand Down Expand Up @@ -161,7 +162,7 @@ export const useQuerySegmentRoutes = (path: string): UseRoutes => {
},
{
key: "QueryEmpty",
component: ListQuery,
component: QueriesBlankState,
albinAppsmith marked this conversation as resolved.
Show resolved Hide resolved
exact: true,
path: [path],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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/SplitScreenTabs";
import EditorTabs from "../EditorTabs";
import {
jsSegmentRoutes,
querySegmentRoutes,
Expand All @@ -17,19 +17,23 @@ 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 (
<Flex
className="relative"
flexDirection="column"
gap="spacing-2"
height="100%"
overflow="hidden"
>
<SegmentedHeader />
<EditorTabs />
{ideViewMode === EditorViewMode.SplitScreen ? <EditorTabs /> : null}
<Flex
className="ide-editor-left-pane__content"
flexDirection="column"
Expand Down
1 change: 1 addition & 0 deletions app/client/src/pages/Editor/IDE/EditorPane/JS/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const ListJSObjects = () => {
return (
<JSContainer
className="ide-editor-left-pane__content-js"
flex="1"
flexDirection="column"
gap="spaces-3"
overflow="hidden"
Expand Down
54 changes: 38 additions & 16 deletions app/client/src/pages/Editor/IDE/EditorTabs/AddButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,56 @@ import React from "react";
import { Flex, Spinner, Button } from "design-system";
import { useCurrentEditorState, useIDETabClickHandlers } from "../hooks";
import { useIsJSAddLoading } from "@appsmith/pages/Editor/IDE/EditorPane/JS/hooks";
import { EditorEntityTabState } from "@appsmith/entities/IDE/constants";
import {
EditorEntityTab,
EditorEntityTabState,
} from "@appsmith/entities/IDE/constants";
import { FileTab } from "IDE/Components/FileTab";

const AddButton = () => {
const AddButton = ({
newTabClickCallback,
onClose,
}: {
newTabClickCallback: () => void;
onClose: (actionId?: string) => void;
}) => {
const { addClickHandler } = useIDETabClickHandlers();
const isJSLoading = useIsJSAddLoading();
const { segmentMode } = useCurrentEditorState();
const { segment, segmentMode } = useCurrentEditorState();

if (segmentMode === EditorEntityTabState.Add) {
return null;
}
if (isJSLoading) {
return (
<Flex px="spaces-2">
<Spinner size="md" />
</Flex>
);
}
return (
<Button
className="!min-w-[24px]"
data-testid="t--ide-tabs-add-button"
id="tabs-add-toggle"
isIconButton
kind="tertiary"
onClick={addClickHandler}
size="sm"
startIcon="add-line"

const onCloseClick = (e: React.MouseEvent) => {
e.stopPropagation();
onClose();
};

return segmentMode === EditorEntityTabState.Add ? (
<FileTab
isActive={segmentMode === EditorEntityTabState.Add}
onClick={newTabClickCallback}
onClose={(e) => onCloseClick(e)}
title={`New ${segment === EditorEntityTab.JS ? "JS" : "Query"}`}
/>
) : (
<div className="bg-white sticky right-0 flex items-center h-[32px] border-b border-b-[var(--ads-v2-color-border-muted)] pl-[var(--ads-v2-spaces-2)]">
<Button
className="!min-w-[24px]"
data-testid="t--ide-tabs-add-button"
id="tabs-add-toggle"
isIconButton
kind="tertiary"
onClick={addClickHandler}
size="sm"
startIcon="add-line"
/>
</div>
);
};

Expand Down
1 change: 1 addition & 0 deletions app/client/src/pages/Editor/IDE/EditorTabs/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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"
Expand Down
3 changes: 3 additions & 0 deletions app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe("FileTabs", () => {
it("renders tabs correctly", () => {
const { getByTestId, getByText } = render(
<FileTabs
currentTab={mockTabs[0].key}
navigateToTab={mockNavigateToTab}
onClose={mockOnClose}
tabs={mockTabs}
Expand All @@ -40,6 +41,7 @@ describe("FileTabs", () => {
it("check tab click", () => {
const { getByTestId } = render(
<FileTabs
currentTab={mockTabs[0].key}
navigateToTab={mockNavigateToTab}
onClose={mockOnClose}
tabs={mockTabs}
Expand All @@ -54,6 +56,7 @@ describe("FileTabs", () => {
it("check for close click", () => {
const { getByTestId } = render(
<FileTabs
currentTab={mockTabs[1].key}
navigateToTab={mockNavigateToTab}
onClose={mockOnClose}
tabs={mockTabs}
Expand Down
101 changes: 17 additions & 84 deletions app/client/src/pages/Editor/IDE/EditorTabs/FileTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
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 type { EntityItem } from "@appsmith/entities/IDE/constants";
import { useCurrentEditorState } from "../hooks";
import { FileTab } from "IDE/Components/FileTab";

interface Props {
tabs: EntityItem[];
navigateToTab: (tab: EntityItem) => void;
onClose: (actionId?: string) => void;
currentTab: string;
}

const FILE_TABS_CONTAINER_ID = "file-tabs-container";

const FileTabs = (props: Props) => {
const { navigateToTab, onClose, tabs } = props;
const { segment, segmentMode } = useCurrentEditorState();

const location = useLocation();

const currentEntity = identifyEntityFromPath(location.pathname);
const { currentTab, navigateToTab, onClose, tabs } = props;
const { segmentMode } = useCurrentEditorState();

useEffect(() => {
const activetab = document.querySelector(".editor-tab.active");
Expand All @@ -41,74 +24,24 @@ const FileTabs = (props: Props) => {
}
}, [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();
onClose(id);
};

return (
<ScrollArea
className="h-[32px] top-[0.5px]"
data-testid="t--editor-tabs"
options={{
overflow: {
x: "scroll",
y: "hidden",
},
}}
size={"sm"}
>
<Flex gap="spaces-2" height="100%" id={FILE_TABS_CONTAINER_ID}>
{tabs.map((tab: EntityItem) => (
<StyledTab
className={clsx(
"editor-tab",
currentEntity.id === tab.key && "active",
)}
data-testid={`t--ide-tab-${tab.title}`}
key={tab.key}
onClick={() => navigateToTab(tab)}
>
<TabIconContainer>{tab.icon}</TabIconContainer>
<TabTextContainer>{tab.title}</TabTextContainer>
{/* not using button component because of the size not matching design */}
<Icon
className="tab-close rounded-[4px] hover:bg-[var(--ads-v2-colors-action-tertiary-surface-hover-bg)] cursor-pointer p-[2px]"
data-testid="t--tab-close-btn"
name="close-line"
onClick={(e) => onCloseClick(e, tab.key)}
/>
</StyledTab>
))}
{/* New Tab */}
{segmentMode === EditorEntityTabState.Add ? (
<StyledTab
className={clsx("editor-tab", "active")}
data-testid={`t--ide-tab-new`}
>
<TabTextContainer>
New {segment === EditorEntityTab.JS ? "JS" : "Query"}
</TabTextContainer>
{/* not using button component because of the size not matching design */}
<Icon
className="tab-close rounded-[4px] hover:bg-[var(--ads-v2-colors-action-tertiary-surface-hover-bg)] cursor-pointer p-[2px]"
data-testid="t--tab-close-btn"
name="close-line"
onClick={(e) => onCloseClick(e)}
/>
</StyledTab>
) : null}
</Flex>
</ScrollArea>
<>
{tabs.map((tab: EntityItem) => (
<FileTab
icon={tab.icon}
isActive={currentTab === tab.key}
key={tab.key}
onClick={() => navigateToTab(tab)}
onClose={(e) => onCloseClick(e, tab.key)}
title={tab.title}
/>
))}
</>
);
};

Expand Down
Loading
Loading