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:
parent
ad810c0811
commit
68264f1e2e
|
|
@ -86,7 +86,7 @@ export class CommonLocators {
|
||||||
_anvilDnDHighlight = "[data-type=anvil-dnd-highlight]";
|
_anvilDnDHighlight = "[data-type=anvil-dnd-highlight]";
|
||||||
_editPage = "[data-testid=onboarding-tasks-datasource-text], .t--drop-target";
|
_editPage = "[data-testid=onboarding-tasks-datasource-text], .t--drop-target";
|
||||||
_crossBtn = "span.cancel-icon";
|
_crossBtn = "span.cancel-icon";
|
||||||
_createNew = ".t--add-item";
|
_createNew = "[data-testid='t--add-item']";
|
||||||
_uploadFiles = "div.uppy-Dashboard-AddFiles input";
|
_uploadFiles = "div.uppy-Dashboard-AddFiles input";
|
||||||
_uploadBtn = "button.uppy-StatusBar-actionBtn--upload";
|
_uploadBtn = "button.uppy-StatusBar-actionBtn--upload";
|
||||||
_errorTab = "[data-testid=t--tab-ERROR_TAB]";
|
_errorTab = "[data-testid=t--tab-ERROR_TAB]";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ class ListView {
|
||||||
public locators = {
|
public locators = {
|
||||||
list: "[data-testid='t--ide-list']",
|
list: "[data-testid='t--ide-list']",
|
||||||
listItem: "[data-testid='t--ide-list-item']",
|
listItem: "[data-testid='t--ide-list-item']",
|
||||||
addItem: "button.t--add-item",
|
addItem: "[data-testid='t--add-item']",
|
||||||
};
|
};
|
||||||
|
|
||||||
public assertListVisibility() {
|
public assertListVisibility() {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
};
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
@ -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";
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { SearchAndAdd } from "./SearchAndAdd";
|
||||||
|
export * from "./SearchAndAdd.types";
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
export { ListItemContainer, ListHeaderContainer } from "./styles";
|
export { ListItemContainer, ListHeaderContainer } from "./styles";
|
||||||
export { ListWithHeader } from "./ListWithHeader";
|
export { ListWithHeader } from "./ListWithHeader";
|
||||||
export { EditorSegments } from "./EditorSegments";
|
export { EditorSegments } from "./EditorSegments";
|
||||||
|
export * from "./SearchAndAdd";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { Flex, Text } from "@appsmith/ads";
|
import { Flex, Text, SearchAndAdd } from "@appsmith/ads";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { selectJSSegmentEditorList } from "ee/selectors/appIDESelectors";
|
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 { useJSAdd } from "ee/pages/Editor/IDE/EditorPane/JS/hooks";
|
||||||
import { JSListItem } from "ee/pages/Editor/IDE/EditorPane/JS/ListItem";
|
import { JSListItem } from "ee/pages/Editor/IDE/EditorPane/JS/ListItem";
|
||||||
import { BlankState } from "./BlankState";
|
import { BlankState } from "./BlankState";
|
||||||
import { AddAndSearchbar } from "../components/AddAndSearchbar";
|
|
||||||
import { EmptySearchResult } from "../components/EmptySearchResult";
|
import { EmptySearchResult } from "../components/EmptySearchResult";
|
||||||
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
|
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
|
||||||
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
|
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
|
||||||
|
|
@ -64,10 +63,10 @@ const ListJSObjects = () => {
|
||||||
py="spaces-3"
|
py="spaces-3"
|
||||||
>
|
>
|
||||||
{itemGroups && itemGroups.length > 0 ? (
|
{itemGroups && itemGroups.length > 0 ? (
|
||||||
<AddAndSearchbar
|
<SearchAndAdd
|
||||||
hasAddPermission={canCreateActions}
|
onAdd={openAddJS}
|
||||||
onAddClick={openAddJS}
|
|
||||||
onSearch={setSearchTerm}
|
onSearch={setSearchTerm}
|
||||||
|
showAddButton={canCreateActions}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<FilesContextProvider
|
<FilesContextProvider
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Flex, Text } from "@appsmith/ads";
|
import { Flex, Text, SearchAndAdd } from "@appsmith/ads";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
import { getHasCreateActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
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 { QueryListItem } from "ee/pages/Editor/IDE/EditorPane/Query/ListItem";
|
||||||
import { getShowWorkflowFeature } from "ee/selectors/workflowSelectors";
|
import { getShowWorkflowFeature } from "ee/selectors/workflowSelectors";
|
||||||
import { BlankState } from "./BlankState";
|
import { BlankState } from "./BlankState";
|
||||||
import { AddAndSearchbar } from "../components/AddAndSearchbar";
|
|
||||||
import { EmptySearchResult } from "../components/EmptySearchResult";
|
import { EmptySearchResult } from "../components/EmptySearchResult";
|
||||||
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
|
import { EDITOR_PANE_TEXTS, createMessage } from "ee/constants/messages";
|
||||||
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
|
import { filterEntityGroupsBySearchTerm } from "IDE/utils";
|
||||||
|
|
@ -55,10 +54,10 @@ const ListQuery = () => {
|
||||||
py="spaces-3"
|
py="spaces-3"
|
||||||
>
|
>
|
||||||
{itemGroups.length > 0 ? (
|
{itemGroups.length > 0 ? (
|
||||||
<AddAndSearchbar
|
<SearchAndAdd
|
||||||
hasAddPermission={canCreateActions}
|
onAdd={openAddQuery}
|
||||||
onAddClick={openAddQuery}
|
|
||||||
onSearch={setSearchTerm}
|
onSearch={setSearchTerm}
|
||||||
|
showAddButton={canCreateActions}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<Flex flexDirection={"column"} gap="spaces-4" overflowY="auto">
|
<Flex flexDirection={"column"} gap="spaces-4" overflowY="auto">
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ const ListWidgets = (props: {
|
||||||
/* If no widgets exist, show the blank state */
|
/* If no widgets exist, show the blank state */
|
||||||
<EmptyState
|
<EmptyState
|
||||||
buttonClassName="t--add-item"
|
buttonClassName="t--add-item"
|
||||||
|
buttonTestId="t--add-item"
|
||||||
buttonText={createMessage(EDITOR_PANE_TEXTS.widget_add_button)}
|
buttonText={createMessage(EDITOR_PANE_TEXTS.widget_add_button)}
|
||||||
description={createMessage(
|
description={createMessage(
|
||||||
EDITOR_PANE_TEXTS.widget_blank_state_description,
|
EDITOR_PANE_TEXTS.widget_blank_state_description,
|
||||||
|
|
@ -75,6 +76,7 @@ const ListWidgets = (props: {
|
||||||
<Flex flexDirection="column" px="spaces-3">
|
<Flex flexDirection="column" px="spaces-3">
|
||||||
<Button
|
<Button
|
||||||
className="t--add-item"
|
className="t--add-item"
|
||||||
|
data-testid="t--add-item"
|
||||||
kind={"secondary"}
|
kind={"secondary"}
|
||||||
onClick={addButtonClickHandler}
|
onClick={addButtonClickHandler}
|
||||||
size={"sm"}
|
size={"sm"}
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
|
||||||
Loading…
Reference in New Issue
Block a user