diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.html b/modules/ui/src/app/components/list-layout/list-layout.component.html
index 55ffb7c1b..c33c614fa 100644
--- a/modules/ui/src/app/components/list-layout/list-layout.component.html
+++ b/modules/ui/src/app/components/list-layout/list-layout.component.html
@@ -38,10 +38,23 @@
-
- search
-
+
+
+
+ search
+
+
+
diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.scss b/modules/ui/src/app/components/list-layout/list-layout.component.scss
index c00a11764..d2e55371d 100644
--- a/modules/ui/src/app/components/list-layout/list-layout.component.scss
+++ b/modules/ui/src/app/components/list-layout/list-layout.component.scss
@@ -112,6 +112,10 @@
}
}
+.clear-search-button {
+ margin-right: 10px;
+}
+
::ng-deep .using-mouse .search-field input:focus {
outline: none;
}
diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.spec.ts b/modules/ui/src/app/components/list-layout/list-layout.component.spec.ts
index 02089934e..a0e8647eb 100644
--- a/modules/ui/src/app/components/list-layout/list-layout.component.spec.ts
+++ b/modules/ui/src/app/components/list-layout/list-layout.component.spec.ts
@@ -13,7 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import {
+ ComponentFixture,
+ fakeAsync,
+ TestBed,
+ tick,
+} from '@angular/core/testing';
import { ListLayoutComponent } from './list-layout.component';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatToolbarModule } from '@angular/material/toolbar';
@@ -22,6 +27,7 @@ import { MatButtonModule } from '@angular/material/button';
import { ListItemComponent } from '../list-item/list-item.component';
import { Component } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { By } from '@angular/platform-browser';
interface Entity {
id: number;
@@ -63,6 +69,7 @@ describe('ListLayoutComponent', () => {
let component: HostComponent;
let fixture: ComponentFixture;
let compiled: HTMLElement;
+ let listLayoutComponentInstance: ListLayoutComponent;
beforeEach(async () => {
await TestBed.configureTestingModule({
@@ -79,6 +86,13 @@ describe('ListLayoutComponent', () => {
fixture = TestBed.createComponent(HostComponent);
component = fixture.componentInstance;
compiled = fixture.nativeElement as HTMLElement;
+
+ const listLayoutDebugElement = fixture.debugElement.query(
+ By.directive(ListLayoutComponent)
+ );
+ listLayoutComponentInstance =
+ listLayoutDebugElement.componentInstance as ListLayoutComponent;
+
fixture.detectChanges();
});
@@ -146,5 +160,46 @@ describe('ListLayoutComponent', () => {
expect(listItemComponent.length).toEqual(2);
});
+
+ it('clearSearch() should reset searchText to an empty string and clear input', fakeAsync(() => {
+ const searchInputElement = compiled.querySelector(
+ '.search-field input'
+ ) as HTMLInputElement;
+ expect(searchInputElement).toBeTruthy();
+
+ searchInputElement.value = 'testing';
+ searchInputElement.dispatchEvent(new Event('input'));
+ fixture.detectChanges();
+ tick();
+
+ // Verify ListLayoutComponent's internal searchText is updated
+ expect(listLayoutComponentInstance.searchText()).toBe('testing');
+
+ const buttonClearSearch = compiled.querySelector(
+ '.clear-search-button'
+ ) as HTMLButtonElement;
+ expect(buttonClearSearch).toBeTruthy();
+
+ buttonClearSearch.click();
+ fixture.detectChanges();
+ tick();
+
+ // Verify ListLayoutComponent's internal searchText is cleared
+ expect(listLayoutComponentInstance.searchText()).toBe('');
+
+ // Verify the input field in the DOM is also cleared
+ expect(searchInputElement.value).toBe('');
+
+ // Verify the clear button is gone and search icon is back
+ const clearButtonAfterClear = compiled.querySelector(
+ '.clear-search-button'
+ );
+ expect(clearButtonAfterClear).toBeNull();
+ const searchIcon = compiled.querySelector(
+ '.search-field mat-icon:not(button mat-icon)'
+ );
+ expect(searchIcon).toBeTruthy();
+ expect(searchIcon?.textContent?.trim()).toBe('search');
+ }));
});
});
diff --git a/modules/ui/src/app/components/list-layout/list-layout.component.ts b/modules/ui/src/app/components/list-layout/list-layout.component.ts
index a89412897..b8647a4f7 100644
--- a/modules/ui/src/app/components/list-layout/list-layout.component.ts
+++ b/modules/ui/src/app/components/list-layout/list-layout.component.ts
@@ -82,6 +82,10 @@ export class ListLayoutComponent {
return this.actions();
};
+ clearSearch(): void {
+ this.searchText.set('');
+ }
+
updateQuery(e: Event) {
const input = e.target as HTMLInputElement;
const value = input.value;