chore: extract search and add to ads (#38192)

## Description
Extract search and add to ADS.


Fixes [#37888](https://github.com/appsmithorg/appsmith/issues/37888)

## Automation

/ok-to-test tags="@tag.IDE, @tag.Sanity"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/12407865393>
> Commit: dce12fbeebae3ef23d9bd251a8096b09306a06d5
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12407865393&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.IDE, @tag.Sanity`
> Spec:
> <hr>Thu, 19 Dec 2024 07:44:13 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

## Release Notes

- **New Features**
- Introduced the `SearchAndAdd` component for enhanced search and add
functionality.
- Added a new Storybook story for the `SearchAndAdd` component,
providing visual documentation and interaction examples.

- **Bug Fixes**
- Replaced the deprecated `AddAndSearchbar` component with
`SearchAndAdd` in relevant areas of the application.

- **Documentation**
- Enhanced documentation for the `SearchAndAdd` component through
Storybook.

- **Chores**
- Updated import statements to reflect the new component structure and
removed obsolete components.
- Modified locators to use data attributes for improved element
identification in tests.
- Added specific identifiers for testing frameworks to enhance
testability of components.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Alex 2024-12-19 11:13:13 +03:00 committed by GitHub
parent ad810c0811
commit 68264f1e2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 124 additions and 41 deletions

View File

@ -86,7 +86,7 @@ export class CommonLocators {
_anvilDnDHighlight = "[data-type=anvil-dnd-highlight]";
_editPage = "[data-testid=onboarding-tasks-datasource-text], .t--drop-target";
_crossBtn = "span.cancel-icon";
_createNew = ".t--add-item";
_createNew = "[data-testid='t--add-item']";
_uploadFiles = "div.uppy-Dashboard-AddFiles input";
_uploadBtn = "button.uppy-StatusBar-actionBtn--upload";
_errorTab = "[data-testid=t--tab-ERROR_TAB]";

View File

@ -4,7 +4,7 @@ class ListView {
public locators = {
list: "[data-testid='t--ide-list']",
listItem: "[data-testid='t--ide-list-item']",
addItem: "button.t--add-item",
addItem: "[data-testid='t--add-item']",
};
public assertListVisibility() {

View File

@ -0,0 +1,38 @@
/* eslint-disable no-console */
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { SearchAndAdd, type SearchAndAddProps } from ".";
const meta: Meta<typeof SearchAndAdd> = {
title: "ADS/Templates/Entity Explorer/Search And Add",
component: SearchAndAdd,
};
export default meta;
const Template = (props: SearchAndAddProps) => {
const { onAdd, onSearch, placeholder, showAddButton = true } = props;
return (
<div style={{ width: 250 }}>
<SearchAndAdd
{...{
onAdd,
onSearch,
showAddButton,
placeholder,
}}
/>
</div>
);
};
export const Basic = Template.bind({}) as StoryObj;
Basic.args = {
onAdd: () => console.log("Add clicked"),
onSearch: (searchTerm: string) => console.log(searchTerm),
placeholder: "Search",
showAddButton: true,
};

View File

@ -0,0 +1,16 @@
import styled from "styled-components";
import { Button } from "@appsmith/ads";
export const Root = styled.div`
display: flex;
gap: var(--ads-v2-spaces-3);
width: 100%;
`;
export const SquareButton = styled(Button)`
&& {
max-width: 24px;
min-width: 24px;
}
`;

View File

@ -0,0 +1,43 @@
import React, { forwardRef } from "react";
import { SearchInput } from "@appsmith/ads";
import * as Styles from "./SearchAndAdd.styles";
import type { SearchAndAddProps } from "./SearchAndAdd.types";
export const SearchAndAdd = forwardRef<HTMLInputElement, SearchAndAddProps>(
(props, ref) => {
const {
onAdd,
onSearch,
placeholder,
searchTerm = "",
showAddButton,
} = props;
return (
<Styles.Root>
<SearchInput
data-testid="t--search-input"
onChange={onSearch}
placeholder={placeholder}
ref={ref}
size="sm"
value={searchTerm}
/>
{showAddButton && (
<Styles.SquareButton
aria-label="Add"
data-testid="t--add-item"
isIconButton
kind="secondary"
onClick={onAdd}
size="sm"
startIcon="add-line"
/>
)}
</Styles.Root>
);
},
);
SearchAndAdd.displayName = "SearchAndAdd";

View File

@ -0,0 +1,12 @@
export interface SearchAndAddProps {
/** Placeholder text for search input. */
placeholder?: string;
/** Value for search input in controlled mode. */
searchTerm?: string;
/** Callback to be called when add button is clicked. */
onAdd?: () => void;
/** Callback to be called when search input value changes. */
onSearch?: (searchTerm: string) => void;
/** Whether to show the add button. Allows to hide the button for users with insufficient access privileges. */
showAddButton: boolean;
}

View File

@ -0,0 +1,2 @@
export { SearchAndAdd } from "./SearchAndAdd";
export * from "./SearchAndAdd.types";

View File

@ -1,3 +1,4 @@
export { ListItemContainer, ListHeaderContainer } from "./styles";
export { ListWithHeader } from "./ListWithHeader";
export { EditorSegments } from "./EditorSegments";
export * from "./SearchAndAdd";

View File

@ -1,6 +1,6 @@
import React, { useState } from "react";
import { useSelector } from "react-redux";
import { Flex, Text } from "@appsmith/ads";
import { Flex, Text, SearchAndAdd } from "@appsmith/ads";
import styled from "styled-components";
import { selectJSSegmentEditorList } from "ee/selectors/appIDESelectors";
@ -18,7 +18,6 @@ import { FilesContextProvider } from "pages/Editor/Explorer/Files/FilesContextPr
import { useJSAdd } from "ee/pages/Editor/IDE/EditorPane/JS/hooks";
import { JSListItem } from "ee/pages/Editor/IDE/EditorPane/JS/ListItem";
import { BlankState } from "./BlankState";
import { AddAndSearchbar } from "../components/AddAndSearchbar";
import { EmptySearchResult } from "../components/EmptySearchResult";
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
@ -64,10 +63,10 @@ const ListJSObjects = () => {
py="spaces-3"
>
{itemGroups && itemGroups.length > 0 ? (
<AddAndSearchbar
hasAddPermission={canCreateActions}
onAddClick={openAddJS}
<SearchAndAdd
onAdd={openAddJS}
onSearch={setSearchTerm}
showAddButton={canCreateActions}
/>
) : null}
<FilesContextProvider

View File

@ -1,5 +1,5 @@
import React, { useState } from "react";
import { Flex, Text } from "@appsmith/ads";
import { Flex, Text, SearchAndAdd } from "@appsmith/ads";
import { useSelector } from "react-redux";
import { getHasCreateActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
@ -18,7 +18,6 @@ import { useQueryAdd } from "ee/pages/Editor/IDE/EditorPane/Query/hooks";
import { QueryListItem } from "ee/pages/Editor/IDE/EditorPane/Query/ListItem";
import { getShowWorkflowFeature } from "ee/selectors/workflowSelectors";
import { BlankState } from "./BlankState";
import { AddAndSearchbar } from "../components/AddAndSearchbar";
import { EmptySearchResult } from "../components/EmptySearchResult";
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
@ -55,10 +54,10 @@ const ListQuery = () => {
py="spaces-3"
>
{itemGroups.length > 0 ? (
<AddAndSearchbar
hasAddPermission={canCreateActions}
onAddClick={openAddQuery}
<SearchAndAdd
onAdd={openAddQuery}
onSearch={setSearchTerm}
showAddButton={canCreateActions}
/>
) : null}
<Flex flexDirection={"column"} gap="spaces-4" overflowY="auto">

View File

@ -63,6 +63,7 @@ const ListWidgets = (props: {
/* If no widgets exist, show the blank state */
<EmptyState
buttonClassName="t--add-item"
buttonTestId="t--add-item"
buttonText={createMessage(EDITOR_PANE_TEXTS.widget_add_button)}
description={createMessage(
EDITOR_PANE_TEXTS.widget_blank_state_description,
@ -75,6 +76,7 @@ const ListWidgets = (props: {
<Flex flexDirection="column" px="spaces-3">
<Button
className="t--add-item"
data-testid="t--add-item"
kind={"secondary"}
onClick={addButtonClickHandler}
size={"sm"}

View File

@ -1,29 +0,0 @@
import React from "react";
import { Flex, Button, SearchInput } from "@appsmith/ads";
interface Props {
onAddClick: () => void;
hasAddPermission: boolean;
onSearch: (value: string) => void;
}
const AddAndSearchbar = ({ hasAddPermission, onAddClick, onSearch }: Props) => {
return (
<Flex alignItems="center" flexDirection="row" gap="spaces-3">
<SearchInput onChange={onSearch} size="sm" />
{hasAddPermission ? (
<Button
className="t--add-item !min-w-[24px]"
data-testid="t--add-item"
isIconButton
kind={"secondary"}
onClick={onAddClick}
size={"sm"}
startIcon={"add-line"}
/>
) : null}
</Flex>
);
};
export { AddAndSearchbar };