diff --git a/app/client/packages/design-system/widgets-old/src/SearchComponent/index.test.tsx b/app/client/packages/design-system/widgets-old/src/SearchComponent/index.test.tsx
new file mode 100644
index 000000000000..0e4ae3525993
--- /dev/null
+++ b/app/client/packages/design-system/widgets-old/src/SearchComponent/index.test.tsx
@@ -0,0 +1,96 @@
+import React from "react";
+import { render, fireEvent, act } from "@testing-library/react";
+import SearchComponent from "../SearchComponent";
+import "@testing-library/jest-dom";
+
+// Mocking the debounce function to call the function immediately
+jest.mock("lodash", () => ({
+ debounce: (fn: any) => fn,
+}));
+
+// Mocking the SVG import to avoid issues with lazy loading in the test environment
+jest.mock("../utils/icon-loadables", () => ({
+ importSvg: jest.fn().mockReturnValue(() => ),
+}));
+
+describe("SearchComponent", () => {
+ const onSearchMock = jest.fn();
+
+ const renderComponent = (props = {}) => {
+ return render(
+ ,
+ );
+ };
+
+ it("should allow the user to type in the search box and see results immediately when client-side search is enabled", () => {
+ const { getByPlaceholderText } = renderComponent({
+ enableClientSideSearch: true,
+ });
+ const inputElement = getByPlaceholderText("Search...") as HTMLInputElement;
+
+ fireEvent.change(inputElement, { target: { value: "test" } });
+
+ expect(inputElement.value).toBe("test");
+ expect(onSearchMock).toHaveBeenCalledWith("test");
+ });
+
+ it("should allow the user to clear the search input by clicking the clear button and see updated search results", () => {
+ const { getByPlaceholderText, getByTestId } = renderComponent({
+ enableClientSideSearch: true,
+ value: "test",
+ });
+ const inputElement = getByPlaceholderText("Search...") as HTMLInputElement;
+ const clearButton = getByTestId("cross-icon");
+
+ fireEvent.click(clearButton);
+
+ expect(inputElement.value).toBe("");
+ expect(onSearchMock).toHaveBeenCalledWith("");
+ });
+
+ it("should update the search input when the user receives new search criteria from outside the component", () => {
+ const { getByPlaceholderText, rerender } = renderComponent({
+ value: "initial",
+ });
+
+ const inputElement = getByPlaceholderText("Search...") as HTMLInputElement;
+ expect(inputElement.value).toBe("initial");
+
+ rerender(
+ ,
+ );
+
+ expect(inputElement.value).toBe("updated");
+ });
+
+ it("should clear the search input when the user disables client-side search and see unfiltered results", () => {
+ const { getByPlaceholderText, rerender } = renderComponent({
+ enableClientSideSearch: true,
+ value: "initial",
+ });
+
+ const inputElement = getByPlaceholderText("Search...") as HTMLInputElement;
+ expect(inputElement.value).toBe("initial");
+
+ rerender(
+ ,
+ );
+
+ expect(inputElement.value).toBe("");
+ expect(onSearchMock).toHaveBeenCalledWith("");
+ });
+});
diff --git a/app/client/packages/design-system/widgets-old/src/SearchComponent/index.tsx b/app/client/packages/design-system/widgets-old/src/SearchComponent/index.tsx
index ab51942ff46b..77f94514e3a7 100644
--- a/app/client/packages/design-system/widgets-old/src/SearchComponent/index.tsx
+++ b/app/client/packages/design-system/widgets-old/src/SearchComponent/index.tsx
@@ -14,6 +14,7 @@ interface SearchProps {
value: string;
className?: string;
autoFocus?: boolean;
+ enableClientSideSearch?: boolean;
}
const SearchComponentWrapper = styled.div`
@@ -98,6 +99,15 @@ class SearchComponent extends React.Component<
if (prevProps.value !== this.props.value) {
this.setState({ localValue: this.props.value });
}
+
+ if (
+ prevProps.enableClientSideSearch !== this.props.enableClientSideSearch
+ ) {
+ this.setState({ localValue: "" }, () => {
+ // Trigger search with an empty value to reset the table
+ this.props.onSearch("");
+ });
+ }
}
handleSearch = (
@@ -108,11 +118,15 @@ class SearchComponent extends React.Component<
const search = event.target.value;
this.setState({ localValue: search });
- this.onDebouncedSearch(search);
+ if (this.props.enableClientSideSearch) {
+ this.onDebouncedSearch(search);
+ }
};
clearSearch = () => {
this.setState({ localValue: "" });
- this.onDebouncedSearch("");
+ if (this.props.enableClientSideSearch) {
+ this.onDebouncedSearch("");
+ }
};
render() {
diff --git a/app/client/src/widgets/TableWidgetV2/component/Table.tsx b/app/client/src/widgets/TableWidgetV2/component/Table.tsx
index 5caf25e08e38..5cb1bfe6b3d4 100644
--- a/app/client/src/widgets/TableWidgetV2/component/Table.tsx
+++ b/app/client/src/widgets/TableWidgetV2/component/Table.tsx
@@ -90,6 +90,7 @@ export interface TableProps {
prevPageClick: () => void;
serverSidePaginationEnabled: boolean;
selectedRowIndex: number;
+ enableClientSideSearch?: boolean;
selectedRowIndices: number[];
disableDrag: () => void;
enableDrag: () => void;
@@ -414,6 +415,7 @@ export function Table(props: TableProps) {
pageNo={props.pageNo}
pageOptions={pageOptions}
prevPageClick={props.prevPageClick}
+ enableClientSideSearch={props.enableClientSideSearch}
searchKey={props.searchKey}
searchTableData={props.searchTableData}
serverSidePaginationEnabled={
diff --git a/app/client/src/widgets/TableWidgetV2/component/header/actions/index.tsx b/app/client/src/widgets/TableWidgetV2/component/header/actions/index.tsx
index faf5a4316e74..5cf8dac0b019 100644
--- a/app/client/src/widgets/TableWidgetV2/component/header/actions/index.tsx
+++ b/app/client/src/widgets/TableWidgetV2/component/header/actions/index.tsx
@@ -98,6 +98,7 @@ export interface ActionsPropsType {
nextPageClick: () => void;
prevPageClick: () => void;
pageNo: number;
+ enableClientSideSearch?: boolean;
totalRecordsCount?: number;
tableData: Array>;
tableColumns: ReactTableColumnProps[];
@@ -142,6 +143,7 @@ function Actions(props: ActionsPropsType) {
onSearch={props.searchTableData}
placeholder="Search..."
value={props.searchKey}
+ enableClientSideSearch={props.enableClientSideSearch}
/>
)}
diff --git a/app/client/src/widgets/TableWidgetV2/component/header/index.tsx b/app/client/src/widgets/TableWidgetV2/component/header/index.tsx
index 5b8f14d0a884..f35766bebb21 100644
--- a/app/client/src/widgets/TableWidgetV2/component/header/index.tsx
+++ b/app/client/src/widgets/TableWidgetV2/component/header/index.tsx
@@ -12,6 +12,7 @@ function TableHeader(props: ActionsPropsType & BannerPropType) {
disabledAddNewRowSave,
isAddRowInProgress,
onAddNewRowAction,
+ enableClientSideSearch,
...ActionProps
} = props;
@@ -26,6 +27,7 @@ function TableHeader(props: ActionsPropsType & BannerPropType) {
/>
) : (
void;
handleReorderColumn: (columnOrder: string[]) => void;
+ enableClientSideSearch?: boolean;
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
searchTableData: (searchKey: any) => void;
@@ -125,6 +126,7 @@ function ReactTableComponent(props: ReactTableComponentProps) {
disableDrag,
editableCell,
editMode,
+ enableClientSideSearch,
filters,
handleColumnFreeze,
handleReorderColumn,
@@ -240,6 +242,7 @@ function ReactTableComponent(props: ReactTableComponentProps) {
editMode={editMode}
editableCell={editableCell}
enableDrag={memoziedEnableDrag}
+ enableClientSideSearch={props.enableClientSideSearch}
filters={filters}
handleColumnFreeze={handleColumnFreeze}
handleReorderColumn={handleReorderColumn}
@@ -339,6 +342,7 @@ export default React.memo(ReactTableComponent, (prev, next) => {
prev.allowSorting === next.allowSorting &&
prev.disabledAddNewRowSave === next.disabledAddNewRowSave &&
prev.canFreezeColumn === next.canFreezeColumn &&
- prev.showConnectDataOverlay === next.showConnectDataOverlay
+ prev.showConnectDataOverlay === next.showConnectDataOverlay &&
+ prev.enableClientSideSearch === next.enableClientSideSearch
);
});
diff --git a/app/client/src/widgets/TableWidgetV2/widget/index.tsx b/app/client/src/widgets/TableWidgetV2/widget/index.tsx
index b83902333947..d41e0d29368e 100644
--- a/app/client/src/widgets/TableWidgetV2/widget/index.tsx
+++ b/app/client/src/widgets/TableWidgetV2/widget/index.tsx
@@ -454,7 +454,7 @@ class TableWidgetV2 extends BaseWidget {
pageNo: "number",
pageSize: "number",
isVisible: DefaultAutocompleteDefinitions.isVisible,
- searchText: "string",
+ searchText: generateTypeDef(widget.searchText, extraDefsToDefine),
totalRecordsCount: "number",
sortOrder: {
column: "string",
@@ -1259,6 +1259,7 @@ class TableWidgetV2 extends BaseWidget {
disabledAddNewRowSave={this.hasInvalidColumnCell()}
editMode={this.props.renderMode === RenderModes.CANVAS}
editableCell={this.props.editableCell}
+ enableClientSideSearch={this.props?.enableClientSideSearch}
filters={this.props.filters}
handleColumnFreeze={this.handleColumnFreeze}
handleReorderColumn={this.handleReorderColumn}