Skip to content

Commit

Permalink
chore: Move smaller Entity Explorer components into ADS (appsmithorg#…
Browse files Browse the repository at this point in the history
  • Loading branch information
hetunandu authored Dec 24, 2024
1 parent 55502c8 commit 8a5c2a5
Show file tree
Hide file tree
Showing 28 changed files with 406 additions and 138 deletions.
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 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"
}
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 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

0 comments on commit 8a5c2a5

Please sign in to comment.