diff --git a/apps/desktop/src/app/tools/send-v2/send-v2.component.ts b/apps/desktop/src/app/tools/send-v2/send-v2.component.ts
index 0df71a78412..271418ae5b2 100644
--- a/apps/desktop/src/app/tools/send-v2/send-v2.component.ts
+++ b/apps/desktop/src/app/tools/send-v2/send-v2.component.ts
@@ -1,14 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
-import {
- ChangeDetectorRef,
- Component,
- computed,
- effect,
- inject,
- signal,
- viewChild,
-} from "@angular/core";
+import { Component, computed, inject, signal, viewChild } from "@angular/core";
import { toSignal } from "@angular/core/rxjs-interop";
import { combineLatest, map, switchMap, lastValueFrom } from "rxjs";
@@ -92,7 +84,6 @@ export class SendV2Component {
private dialogService = inject(DialogService);
private toastService = inject(ToastService);
private logService = inject(LogService);
- private cdr = inject(ChangeDetectorRef);
protected readonly useDrawerEditMode = toSignal(
this.configService.getFeatureFlag$(FeatureFlag.DesktopUiMigrationMilestone2),
@@ -137,17 +128,6 @@ export class SendV2Component {
{ initialValue: null },
);
- constructor() {
- // WORKAROUND: Force change detection when data updates
- // This is needed because SendSearchComponent (shared lib) hasn't migrated to OnPush yet
- // and doesn't trigger CD properly when search/add operations complete
- // TODO: Remove this once SendSearchComponent migrates to OnPush (tracked in CL-764)
- effect(() => {
- this.filteredSends();
- this.cdr.markForCheck();
- });
- }
-
protected readonly selectedSendType = computed(() => {
const action = this.action();
@@ -171,8 +151,6 @@ export class SendV2Component {
} else {
this.action.set(Action.Add);
this.sendId.set(null);
-
- this.cdr.detectChanges();
void this.addEditComponent()?.resetAndLoad();
}
}
diff --git a/libs/tools/send/send-ui/src/send-search/send-search.component.html b/libs/tools/send/send-ui/src/send-search/send-search.component.html
index 7cf154c0ee8..fbbe436d158 100644
--- a/libs/tools/send/send-ui/src/send-search/send-search.component.html
+++ b/libs/tools/send/send-ui/src/send-search/send-search.component.html
@@ -1,7 +1 @@
-
-
+
diff --git a/libs/tools/send/send-ui/src/send-search/send-search.component.ts b/libs/tools/send/send-ui/src/send-search/send-search.component.ts
index 02cb5ef2eda..03eaf9b3430 100644
--- a/libs/tools/send/send-ui/src/send-search/send-search.component.ts
+++ b/libs/tools/send/send-ui/src/send-search/send-search.component.ts
@@ -1,50 +1,55 @@
-import { CommonModule } from "@angular/common";
-import { Component } from "@angular/core";
-import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
+import { ChangeDetectionStrategy, Component, inject, model } from "@angular/core";
+import { takeUntilDestroyed, toObservable } from "@angular/core/rxjs-interop";
import { FormsModule } from "@angular/forms";
-import { Subject, Subscription, debounceTime, filter } from "rxjs";
+import { debounceTime, filter } from "rxjs";
-import { JslibModule } from "@bitwarden/angular/jslib.module";
import { SearchModule } from "@bitwarden/components";
+import { I18nPipe } from "@bitwarden/ui-common";
import { SendItemsService } from "../services/send-items.service";
const SearchTextDebounceInterval = 200;
-// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
-// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
+/**
+ * Search component for filtering Send items.
+ *
+ * Provides a search input that filters the Send list with debounced updates.
+ * Syncs with the service's latest search text to maintain state across navigation.
+ */
@Component({
- imports: [CommonModule, SearchModule, JslibModule, FormsModule],
selector: "tools-send-search",
templateUrl: "send-search.component.html",
+ imports: [FormsModule, I18nPipe, SearchModule],
+ changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SendSearchComponent {
- searchText: string = "";
+ private sendListItemService = inject(SendItemsService);
- private searchText$ = new Subject();
+ /** The current search text entered by the user. */
+ protected readonly searchText = model("");
- constructor(private sendListItemService: SendItemsService) {
+ constructor() {
this.subscribeToLatestSearchText();
this.subscribeToApplyFilter();
}
- onSearchTextChanged() {
- this.searchText$.next(this.searchText);
- }
-
- subscribeToLatestSearchText(): Subscription {
- return this.sendListItemService.latestSearchText$
+ private subscribeToLatestSearchText(): void {
+ this.sendListItemService.latestSearchText$
.pipe(
takeUntilDestroyed(),
filter((data) => !!data),
)
.subscribe((text) => {
- this.searchText = text;
+ this.searchText.set(text);
});
}
- subscribeToApplyFilter(): Subscription {
- return this.searchText$
+ /**
+ * Applies the search filter to the Send list with a debounce delay.
+ * This prevents excessive filtering while the user is still typing.
+ */
+ private subscribeToApplyFilter(): void {
+ toObservable(this.searchText)
.pipe(debounceTime(SearchTextDebounceInterval), takeUntilDestroyed())
.subscribe((data) => {
this.sendListItemService.applyFilter(data);