mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-22 16:29:09 +01:00
[PM-8553] browser v2 search bar defects (#9506)
* update no results icon and no results scrolling * update v2 search so the term persist when the user clicks into an item and exits the item
This commit is contained in:
parent
7e86c0afd4
commit
cb0927ac5d
@ -1,12 +1,14 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, Output, EventEmitter } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { FormsModule } from "@angular/forms";
|
import { FormsModule } from "@angular/forms";
|
||||||
import { Subject, debounceTime } from "rxjs";
|
import { Subject, Subscription, debounceTime, filter } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import { SearchModule } from "@bitwarden/components";
|
import { SearchModule } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { VaultPopupItemsService } from "../../../services/vault-popup-items.service";
|
||||||
|
|
||||||
const SearchTextDebounceInterval = 200;
|
const SearchTextDebounceInterval = 200;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -17,19 +19,34 @@ const SearchTextDebounceInterval = 200;
|
|||||||
})
|
})
|
||||||
export class VaultV2SearchComponent {
|
export class VaultV2SearchComponent {
|
||||||
searchText: string;
|
searchText: string;
|
||||||
@Output() searchTextChanged = new EventEmitter<string>();
|
|
||||||
|
|
||||||
private searchText$ = new Subject<string>();
|
private searchText$ = new Subject<string>();
|
||||||
|
|
||||||
constructor() {
|
constructor(private vaultPopupItemsService: VaultPopupItemsService) {
|
||||||
this.searchText$
|
this.subscribeToLatestSearchText();
|
||||||
.pipe(debounceTime(SearchTextDebounceInterval), takeUntilDestroyed())
|
this.subscribeToApplyFilter();
|
||||||
.subscribe((data) => {
|
|
||||||
this.searchTextChanged.emit(data);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchTextChanged() {
|
onSearchTextChanged() {
|
||||||
this.searchText$.next(this.searchText);
|
this.searchText$.next(this.searchText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscribeToLatestSearchText(): Subscription {
|
||||||
|
return this.vaultPopupItemsService.latestSearchText$
|
||||||
|
.pipe(
|
||||||
|
takeUntilDestroyed(),
|
||||||
|
filter((data) => !!data),
|
||||||
|
)
|
||||||
|
.subscribe((text) => {
|
||||||
|
this.searchText = text;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeToApplyFilter(): Subscription {
|
||||||
|
return this.searchText$
|
||||||
|
.pipe(debounceTime(SearchTextDebounceInterval), takeUntilDestroyed())
|
||||||
|
.subscribe((data) => {
|
||||||
|
this.vaultPopupItemsService.applyFilter(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,18 +22,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-container *ngIf="!(showEmptyState$ | async)">
|
<ng-container *ngIf="!(showEmptyState$ | async)">
|
||||||
<div class="tw-fixed">
|
<app-vault-v2-search> </app-vault-v2-search>
|
||||||
<app-vault-v2-search (searchTextChanged)="handleSearchTextChange($event)">
|
|
||||||
</app-vault-v2-search>
|
|
||||||
|
|
||||||
<app-vault-list-filters></app-vault-list-filters>
|
<app-vault-list-filters></app-vault-list-filters>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
*ngIf="(showNoResultsState$ | async) && !(showDeactivatedOrg$ | async)"
|
*ngIf="(showNoResultsState$ | async) && !(showDeactivatedOrg$ | async)"
|
||||||
class="tw-flex tw-flex-col tw-h-full tw-justify-center"
|
class="tw-flex tw-flex-col tw-justify-center tw-h-auto tw-pt-12"
|
||||||
>
|
>
|
||||||
<bit-no-items>
|
<bit-no-items [icon]="noResultsIcon">
|
||||||
<ng-container slot="title">{{ "noItemsMatchSearch" | i18n }}</ng-container>
|
<ng-container slot="title">{{ "noItemsMatchSearch" | i18n }}</ng-container>
|
||||||
<ng-container slot="description">{{ "clearFiltersOrTryAnother" | i18n }}</ng-container>
|
<ng-container slot="description">{{ "clearFiltersOrTryAnother" | i18n }}</ng-container>
|
||||||
</bit-no-items>
|
</bit-no-items>
|
||||||
@ -41,7 +38,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
*ngIf="showDeactivatedOrg$ | async"
|
*ngIf="showDeactivatedOrg$ | async"
|
||||||
class="tw-flex tw-flex-col tw-h-full tw-justify-center"
|
class="tw-flex tw-flex-col tw-justify-center tw-h-auto tw-pt-12"
|
||||||
>
|
>
|
||||||
<bit-no-items [icon]="deactivatedIcon">
|
<bit-no-items [icon]="deactivatedIcon">
|
||||||
<ng-container slot="title">{{ "organizationIsDeactivated" | i18n }}</ng-container>
|
<ng-container slot="title">{{ "organizationIsDeactivated" | i18n }}</ng-container>
|
||||||
|
@ -44,6 +44,7 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
protected vaultIcon = Icons.Vault;
|
protected vaultIcon = Icons.Vault;
|
||||||
protected deactivatedIcon = Icons.DeactivatedOrg;
|
protected deactivatedIcon = Icons.DeactivatedOrg;
|
||||||
|
protected noResultsIcon = Icons.NoResults;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private vaultPopupItemsService: VaultPopupItemsService,
|
private vaultPopupItemsService: VaultPopupItemsService,
|
||||||
@ -54,10 +55,6 @@ export class VaultV2Component implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
ngOnDestroy(): void {}
|
ngOnDestroy(): void {}
|
||||||
|
|
||||||
handleSearchTextChange(searchText: string) {
|
|
||||||
this.vaultPopupItemsService.applyFilter(searchText);
|
|
||||||
}
|
|
||||||
|
|
||||||
addCipher() {
|
addCipher() {
|
||||||
// TODO: Add currently filtered organization to query params if available
|
// TODO: Add currently filtered organization to query params if available
|
||||||
void this.router.navigate(["/add-cipher"], {});
|
void this.router.navigate(["/add-cipher"], {});
|
||||||
|
@ -38,7 +38,8 @@ import { MY_VAULT_ID, VaultPopupListFiltersService } from "./vault-popup-list-fi
|
|||||||
})
|
})
|
||||||
export class VaultPopupItemsService {
|
export class VaultPopupItemsService {
|
||||||
private _refreshCurrentTab$ = new Subject<void>();
|
private _refreshCurrentTab$ = new Subject<void>();
|
||||||
private searchText$ = new BehaviorSubject<string>("");
|
private _searchText$ = new BehaviorSubject<string>("");
|
||||||
|
latestSearchText$: Observable<string> = this._searchText$.asObservable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observable that contains the list of other cipher types that should be shown
|
* Observable that contains the list of other cipher types that should be shown
|
||||||
@ -105,7 +106,7 @@ export class VaultPopupItemsService {
|
|||||||
|
|
||||||
private _filteredCipherList$: Observable<PopupCipherView[]> = combineLatest([
|
private _filteredCipherList$: Observable<PopupCipherView[]> = combineLatest([
|
||||||
this._cipherList$,
|
this._cipherList$,
|
||||||
this.searchText$,
|
this._searchText$,
|
||||||
this.vaultPopupListFiltersService.filterFunction$,
|
this.vaultPopupListFiltersService.filterFunction$,
|
||||||
]).pipe(
|
]).pipe(
|
||||||
map(([ciphers, searchText, filterFunction]): [CipherView[], string] => [
|
map(([ciphers, searchText, filterFunction]): [CipherView[], string] => [
|
||||||
@ -179,7 +180,7 @@ export class VaultPopupItemsService {
|
|||||||
* Observable that indicates whether a filter is currently applied to the ciphers.
|
* Observable that indicates whether a filter is currently applied to the ciphers.
|
||||||
*/
|
*/
|
||||||
hasFilterApplied$ = combineLatest([
|
hasFilterApplied$ = combineLatest([
|
||||||
this.searchText$,
|
this._searchText$,
|
||||||
this.vaultPopupListFiltersService.filters$,
|
this.vaultPopupListFiltersService.filters$,
|
||||||
]).pipe(
|
]).pipe(
|
||||||
switchMap(([searchText, filters]) => {
|
switchMap(([searchText, filters]) => {
|
||||||
@ -242,7 +243,7 @@ export class VaultPopupItemsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyFilter(newSearchText: string) {
|
applyFilter(newSearchText: string) {
|
||||||
this.searchText$.next(newSearchText);
|
this._searchText$.next(newSearchText);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,3 +2,4 @@ export * from "./deactivated-org";
|
|||||||
export * from "./search";
|
export * from "./search";
|
||||||
export * from "./no-access";
|
export * from "./no-access";
|
||||||
export * from "./vault";
|
export * from "./vault";
|
||||||
|
export * from "./no-results";
|
||||||
|
18
libs/components/src/icon/icons/no-results.ts
Normal file
18
libs/components/src/icon/icons/no-results.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { svgIcon } from "../icon";
|
||||||
|
|
||||||
|
export const NoResults = svgIcon`
|
||||||
|
<svg width="98" height="96" viewBox="0 0 98 96" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path class="tw-stroke-primary-700" d="M8.8545 86.7919L56.9901 86.7919C60.2321 86.7919 62.8603 84.1637 62.8603 80.9217L62.8603 32.2678C62.8603 30.7472 62.2702 29.2859 61.2143 28.1916L47.5536 14.0345C46.4473 12.8881 44.9225 12.2405 43.3293 12.2405L8.85451 12.2405C5.61249 12.2405 2.98431 14.8687 2.98431 18.1107L2.98431 80.9217C2.98431 84.1637 5.61248 86.7919 8.8545 86.7919Z" stroke-width="1.76106"/>
|
||||||
|
<path class="tw-fill-background tw-stroke-primary-700" d="M18.8335 76.8125L66.9691 76.8125C70.2111 76.8125 72.8393 74.1844 72.8393 70.9423L72.8393 21.8271C72.8393 20.3144 72.2554 18.8601 71.2093 17.7675L57.5349 3.48471C56.4276 2.32814 54.8959 1.67408 53.2947 1.67408L18.8335 1.67407C15.5915 1.67407 12.9633 4.30225 12.9633 7.54427L12.9633 70.9423C12.9633 74.1844 15.5915 76.8125 18.8335 76.8125Z" stroke-width="1.76106"/>
|
||||||
|
<path class="tw-stroke-primary-700" d="M54.3484 2.26123L54.3484 14.0016C54.3484 17.2436 56.9766 19.8718 60.2186 19.8718L72.546 19.8718" stroke-width="1.76106"/>
|
||||||
|
<path class="tw-stroke-success-600" d="M20.0914 15.9861L43.5722 15.9861" stroke-width="0.880529" stroke-linecap="round" stroke-dasharray="11.74 4.7"/>
|
||||||
|
<path class="tw-stroke-success-600" d="M20.0914 30.8945L51.2034 30.8945" stroke-width="0.880529" stroke-linecap="round" stroke-dasharray="11.74 4.7"/>
|
||||||
|
<path class="tw-stroke-success-600" d="M20.0914 45.803L45.9203 45.803" stroke-width="0.880529" stroke-linecap="round" stroke-dasharray="11.74 4.7"/>
|
||||||
|
<path class="tw-stroke-success-600" d="M20.0914 60.7112L45.9203 60.7112" stroke-width="0.880529" stroke-linecap="round" stroke-dasharray="11.74 4.7"/>
|
||||||
|
<path class="tw-fill-background tw-stroke-primary-700" d="M85.4233 53.9449C81.9863 66.772 68.6684 74.3484 55.6768 70.8674C42.6853 67.3863 34.9398 54.1659 38.3768 41.3388C41.8138 28.5117 55.1318 20.9353 68.1234 24.4163C81.1149 27.8974 88.8604 41.1178 85.4233 53.9449Z" stroke-width="1.76106" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path class="tw-stroke-success-600" d="M55.1859 41.5395C55.1859 41.5395 55.2828 39.2314 57.5434 37.273C58.8998 36.084 60.5145 35.7692 61.9678 35.7343C63.2919 35.6993 64.4868 35.9441 65.1649 36.3288C66.3921 36.9583 68.7497 38.462 68.7497 41.7144C68.7497 45.1416 66.6828 46.6804 64.3576 48.394C62.0324 50.1076 62.3667 52.3385 62.3667 54.227" stroke-width="1.76106" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path class="tw-fill-success-600 tw-stroke-secondary-600" d="M62.2727 59.2015C62.759 59.2015 63.1533 58.8073 63.1533 58.321C63.1533 57.8347 62.759 57.4404 62.2727 57.4404C61.7864 57.4404 61.3922 57.8347 61.3922 58.321C61.3922 58.8073 61.7864 59.2015 62.2727 59.2015Z"/>
|
||||||
|
<path class="tw-fill-secondary-300 tw-stroke-primary-700" d="M96.0333 89.0621L95.4703 89.5329C94.2269 90.5728 92.3758 90.4078 91.3359 89.1644L78.2766 73.5488L74.79 69.3798C74.4843 69.0105 74.6096 68.4514 75.0271 68.2155C76.7198 67.2592 78.097 65.9974 78.8894 65.1364C79.1502 64.853 79.6089 64.8477 79.856 65.1431L83.3425 69.3121L96.4018 84.9277C97.4418 86.1712 97.2768 88.0222 96.0333 89.0621Z" stroke-width="1.76106" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
`;
|
Loading…
Reference in New Issue
Block a user