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

chore: Move smaller Entity Explorer components into ADS #38321

Merged
merged 8 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Canvas, Meta } from "@storybook/blocks";

import * as EmptyStateStories from "./EmptyState.stories";

<Meta of={EmptyStateStories} />

# Empty State

A placeholder for when there is no data to display. It can be used to guide users on what to do next.

## Anatomy

icon: The icon of the file type or the entity type that is being displayed.

description: The details of the empty state. It should be a short and clear message.

button: A button that can be used to trigger an action. This is optional.

### Default implementation

Below is the default implementation of the Empty State component. It does not have a button.

<Canvas of={EmptyStateStories.Basic} />

### With Button

Button kind can be supplied. If no kind is supplied, default is "secondary".

<Canvas of={EmptyStateStories.WithButton} />

### With Button but no onClick is supplied

onClick is optional. If not supplied, the button will not be shown.

<Canvas of={EmptyStateStories.WithButtonWithoutOnClick} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint-disable no-console */
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";

import { EmptyState, type EmptyStateProps } from ".";

const meta: Meta<typeof EmptyState> = {
title: "ADS/Templates/Entity Explorer/Empty State",
component: EmptyState,
};

export default meta;

const Template = (props: EmptyStateProps) => {
const { button, description, icon } = props;

return (
<EmptyState
{...{
description,
icon,
button,
}}
/>
);
};

export const Basic = Template.bind({}) as StoryObj;

Basic.args = {
description: "No data available",
icon: "folder-line",
};

export const WithButton = Template.bind({}) as StoryObj;

WithButton.args = {
description: "No data available",
icon: "file-line",
button: {
text: "Add new",
onClick: () => console.log("Add clicked"),
},
};

export const WithButtonWithoutOnClick = Template.bind({}) as StoryObj;

WithButtonWithoutOnClick.args = {
description: "No data available",
icon: "file-line",
button: {
text: "Add new",
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from "react";
import { Button, Flex, Icon, Text } from "../../..";
import type { EmptyStateProps } from "./EmptyState.types";

const EmptyState = ({ button, description, icon }: EmptyStateProps) => {
return (
<Flex
alignItems={"center"}
flexDirection="column"
gap="spaces-4"
justifyContent={"center"}
px="spaces-3"
py="spaces-7"
>
<Flex
alignItems="center"
backgroundColor="var(--ads-v2-color-bg-subtle)"
borderRadius="var(--ads-v2-border-radius)"
height="var(--ads-v2-spaces-11)"
justifyContent="center"
padding="spaces-3"
width="var(--ads-v2-spaces-11)"
>
<Icon name={icon} size="lg" />
</Flex>
<Text
className="text-center"
color="var(--ads-v2-color-fg)"
kind="heading-xs"
>
{description}
</Text>
{button && button.onClick ? (
<Button
className={button.className}
data-testid={button.testId}
kind={button.kind || "secondary"}
onClick={button.onClick}
size="sm"
>
{button.text}
</Button>
) : null}
</Flex>
);
};

export { EmptyState };
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { type IconNames, type ButtonKind } from "../../..";

export interface EmptyStateProps {
icon: IconNames;
description: string;
button?: {
text: string;
onClick?: () => void;
kind?: Extract<ButtonKind, "primary" | "secondary">;
className?: string;
testId?: string;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { EmptyState } from "./EmptyState";
export * from "./EmptyState.types";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const ExplorerContainerBorder = {
STANDARD: "1px solid var(--ads-v2-color-border)",
NONE: "",
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint-disable no-console */
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";

import { type ExplorerContainerProps, ExplorerContainer } from ".";

import { SearchAndAdd } from "..";
import { Flex } from "../../../Flex";

const meta: Meta<typeof ExplorerContainer> = {
title: "ADS/Templates/Entity Explorer/Container",
component: ExplorerContainer,
argTypes: {
borderRight: {
options: ["STANDARD", "NONE"],
control: { type: "select" },
},
},
};

export default meta;

const Template = (props: ExplorerContainerProps) => {
const { borderRight, children, className, height, width } = props;

return (
<ExplorerContainer
{...{
children,
width,
height,
className,
borderRight,
}}
/>
);
};

export const Basic = Template.bind({}) as StoryObj;

const Children = () => {
return (
<Flex flexDirection="column" p="spaces-2">
<SearchAndAdd showAddButton={false} />
</Flex>
);
};

Basic.args = {
children: <Children />,
borderRight: "STANDARD",
height: "300px",
width: "255px",
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import { ExplorerContainerBorder, Flex } from "../../..";
import type { ExplorerContainerProps } from "./ExplorerContainer.types";

export const ExplorerContainer = (props: ExplorerContainerProps) => {
return (
<Flex
borderRight={ExplorerContainerBorder[props.borderRight]}
className={`relative ${props.className}`}
flexDirection="column"
height={props.height}
overflow="hidden"
width={props.width}
>
{props.children}
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { type ReactNode } from "react";
import type { ExplorerContainerBorder } from "./ExplorerContainer.constants";

export interface ExplorerContainerProps {
children: ReactNode | ReactNode[];
borderRight: keyof typeof ExplorerContainerBorder;
className?: string;
width?: string | number;
height?: string | number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { ExplorerContainer } from "./ExplorerContainer";
export * from "./ExplorerContainer.types";
export { ExplorerContainerBorder } from "./ExplorerContainer.constants";
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Canvas, Meta } from "@storybook/blocks";

import * as NoSearchResultStories from "./NoSearchResults.stories";

<Meta of={NoSearchResultStories} />

# No Search Results

A placeholder for when there are no search results to display. It can be used to guide users on what to do next.
What you get is an ADS styled message from this component.

### Default implementation

Below is the default implementation

<Canvas of={NoSearchResultStories.Basic} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* eslint-disable no-console */
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";

import { NoSearchResults, type NoSearchResultsProps } from ".";

const meta: Meta<typeof NoSearchResults> = {
title: "ADS/Templates/Entity Explorer/No Search Results",
component: NoSearchResults,
};

export default meta;

const Template = (props: NoSearchResultsProps) => {
const { text } = props;

return <NoSearchResults text={text} />;
};

export const Basic = Template.bind({}) as StoryObj;

Basic.args = {
text: "No files found",
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import { Text } from "../../..";
import type { NoSearchResultsProps } from "./NoSearchResults.types";

const NoSearchResults = ({ text }: NoSearchResultsProps) => {
return (
<Text
className="font-normal text-center"
color="var(--ads-v2-color-fg-muted)"
kind="body-s"
>
{text}
</Text>
);
};

export { NoSearchResults };
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface NoSearchResultsProps {
text: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { NoSearchResults } from "./NoSearchResults";
export * from "./NoSearchResults.types";
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ export { ListItemContainer, ListHeaderContainer } from "./styles";
export { ListWithHeader } from "./ListWithHeader";
export { EditorSegments } from "./EditorSegments";
export * from "./SearchAndAdd";
export { EmptyState } from "./EmptyState";
export { NoSearchResults } from "./NoSearchResults";
export * from "./ExplorerContainer";
14 changes: 5 additions & 9 deletions app/client/src/pages/Editor/IDE/EditorPane/Explorer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { Flex } from "@appsmith/ads";
import { ExplorerContainer } from "@appsmith/ads";
import { Switch, useRouteMatch } from "react-router";
import { SentryRoute } from "ee/AppRouter";
import {
Expand All @@ -26,15 +26,11 @@ const EditorPaneExplorer = () => {
const ideViewMode = useSelector(getIDEViewMode);

return (
<Flex
<ExplorerContainer
borderRight={
ideViewMode === EditorViewMode.SplitScreen
? ""
: "1px solid var(--ads-v2-color-border)"
ideViewMode === EditorViewMode.SplitScreen ? "NONE" : "STANDARD"
ankitakinger marked this conversation as resolved.
Show resolved Hide resolved
}
className="relative ide-editor-left-pane__content"
flexDirection="column"
overflow="hidden"
className="ide-editor-left-pane__content"
width={
ideViewMode === EditorViewMode.FullScreen
? DEFAULT_EXPLORER_PANE_WIDTH
Expand All @@ -61,7 +57,7 @@ const EditorPaneExplorer = () => {
]}
/>
</Switch>
</Flex>
</ExplorerContainer>
);
};

Expand Down
10 changes: 6 additions & 4 deletions app/client/src/pages/Editor/IDE/EditorPane/JS/Add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useCallback, useState } from "react";
import SegmentAddHeader from "../components/SegmentAddHeader";
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
import type { ListItemProps } from "@appsmith/ads";
import { Flex, SearchInput } from "@appsmith/ads";
import { Flex, SearchInput, NoSearchResults } from "@appsmith/ads";
import { useDispatch, useSelector } from "react-redux";
import { getCurrentPageId } from "selectors/editorSelectors";
import GroupedList from "../components/GroupedList";
Expand All @@ -13,7 +13,6 @@ import {
import type { ActionOperation } from "components/editorComponents/GlobalSearch/utils";
import { createAddClassName } from "../utils";
import { FocusEntity } from "navigation/FocusEntity";
import { EmptySearchResult } from "../components/EmptySearchResult";
import { getIDEViewMode } from "selectors/ideSelectors";
import type { FlexProps } from "@appsmith/ads";
import { EditorViewMode } from "ee/entities/IDE/constants";
Expand Down Expand Up @@ -98,8 +97,11 @@ const AddJS = () => {
<GroupedList groups={filteredItemGroups} />
) : null}
{filteredItemGroups.length === 0 && searchTerm !== "" ? (
<EmptySearchResult
type={createMessage(EDITOR_PANE_TEXTS.search_objects.jsObject)}
<NoSearchResults
text={createMessage(
EDITOR_PANE_TEXTS.empty_search_result,
createMessage(EDITOR_PANE_TEXTS.search_objects.jsObject),
)}
/>
) : null}
</Flex>
Expand Down
Loading
Loading