1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-07 20:24:01 +00:00

[PM-30677] Convert SendSearchComponent to OnPush (#18322)

Converts SendSearchComponent to use OnPush change detection.
This commit is contained in:
Oscar Hinton
2026-02-05 22:03:42 +01:00
committed by GitHub
parent 2b6158668d
commit ad523179bf
3 changed files with 27 additions and 50 deletions

View File

@@ -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();
}
}

View File

@@ -1,7 +1 @@
<bit-search
[placeholder]="'search' | i18n"
[(ngModel)]="searchText"
(ngModelChange)="onSearchTextChanged()"
appAutofocus
>
</bit-search>
<bit-search [placeholder]="'search' | i18n" [(ngModel)]="searchText" appAutofocus />

View File

@@ -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<string>();
/** 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);