Skip to content

Commit

Permalink
Full width search bar + explicit action buttons for search facets (#1434
Browse files Browse the repository at this point in the history
)

* Full width search bar (#1426)

* First steps

* Beautify

* Use shared search bar component

* Remove search bar from facets

* Some clean ups

* Some clean ups

* Some clean ups

* Code formatting

* Separating full text search from shared search bar

* Add search and clear buttons; some clean ups

* Fix lint issue

* Fix lint issue

* Fix lint issue

* Explicit action button search facets (#1457)

* Change label

* Add button

* Add button

* Full width search bar (#1426)

* First steps

* Beautify

* Use shared search bar component

* Remove search bar from facets

* Some clean ups

* Some clean ups

* Some clean ups

* Code formatting

* Fix layout

* Add functionality to the button

* Fix lint issue, finally?!

* Fix lint issue, finally!

* Fix tests

* Click Search button after typing search query

* Refactor full text search

* Apply prettier

* Convert onChange to reactive stream

* Fix elastic search test

* refactored fulltext-searchbar component and minor css changes for the search bar container

* test fix for naming change of the clear button to reset button

---------

Co-authored-by: junjiequan <[email protected]>
  • Loading branch information
Ingvord and Junjiequan authored May 21, 2024
1 parent 3d8220b commit f137de8
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 25 deletions.
29 changes: 20 additions & 9 deletions cypress/e2e/other/elastic-search.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ describe("Elastic search", () => {

cy.finishedLoading();

cy.get('[data-cy="text-search"] input[type="search"]')
.clear()
.type(searchQuery1);
cy.get('[data-cy="search-clear-button"]').click();

cy.get('[data-cy="text-search"] input[type="search"]').type(searchQuery1);

// Click the search button
cy.get('[data-cy="search-button"]').click();

cy.finishedLoading();

Expand All @@ -45,9 +48,12 @@ describe("Elastic search", () => {

cy.finishedLoading();

cy.get('[data-cy="text-search"] input[type="search"]')
.clear()
.type(searchQuery2);
cy.get('[data-cy="search-clear-button"]').click();

cy.get('[data-cy="text-search"] input[type="search"]').type(searchQuery2);

// Click the search button
cy.get('[data-cy="search-button"]').click();

cy.finishedLoading();

Expand All @@ -64,9 +70,14 @@ describe("Elastic search", () => {

cy.finishedLoading();

cy.get('[data-cy="text-search"] input[type="search"]')
.clear()
.type(searchQueryIrrelevant);
cy.get('[data-cy="search-clear-button"]').click();

cy.get('[data-cy="text-search"] input[type="search"]').type(
searchQueryIrrelevant,
);

// Click the search button
cy.get('[data-cy="search-button"]').click();

cy.finishedLoading();

Expand Down
6 changes: 6 additions & 0 deletions src/app/datasets/dashboard/dashboard.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
<breadcrumb></breadcrumb>
<full-text-search-bar
#searchBar
data-cy="text-search"
[placeholder]="'Text Search'"
>
</full-text-search-bar>
<mat-sidenav-container [hasBackdrop]="false">
<mat-sidenav-content>
<div fxLayout="row" fxLayout.xs="column">
Expand Down
2 changes: 2 additions & 0 deletions src/app/datasets/dashboard/dashboard.component.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@


mat-sidenav-container {
mat-sidenav-content {
padding: 0.5rem;
Expand Down
7 changes: 5 additions & 2 deletions src/app/datasets/dashboard/dashboard.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
addDatasetAction,
fetchDatasetCompleteAction,
fetchMetadataKeysAction,
setSearchTermsAction,
} from "state-management/actions/datasets.actions";

import {
Expand All @@ -22,6 +23,7 @@ import {
selectDatasetsInBatch,
selectCurrentDataset,
selectSelectedDatasets,
selectSearchTerms,
} from "state-management/selectors/datasets.selectors";
import { distinctUntilChanged, filter, map, take } from "rxjs/operators";
import { MatDialog } from "@angular/material/dialog";
Expand Down Expand Up @@ -180,13 +182,14 @@ export class DashboardComponent implements OnInit, OnDestroy {
ngOnInit() {
this.store.dispatch(prefillBatchAction());
this.store.dispatch(fetchMetadataKeysAction());
this.store.dispatch(fetchDatasetsAction());

this.updateColumnSubscription();

this.subscriptions.push(
combineLatest([this.filters$, this.readyToFetch$, this.loggedIn$])
combineLatest([this.readyToFetch$, this.loggedIn$])
.pipe(
map(([filters, _, loggedIn]) => [filters, loggedIn]),
map(([_, loggedIn]) => [loggedIn]),
distinctUntilChanged(deepEqual),
)
.subscribe((obj) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<mat-card>
<div class="search-card-container">
<mat-form-field appearance="fill" class="full-text-search-field">
<mat-label>Search</mat-label>
<input
matInput
placeholder="Type to search..."
type="search"
[(ngModel)]="searchTerm"
(ngModelChange)="onSearchTermChange($event)"
/>
</mat-form-field>
<div class="search-button-group">
<button
mat-flat-button
color="accent"
data-cy="search-button"
(click)="onSearch()"
>
<mat-icon>search</mat-icon>
Search
</button>
<button mat-flat-button data-cy="search-clear-button" (click)="onClear()">
<mat-icon>close</mat-icon>
Clear
</button>
</div>
</div>
</mat-card>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
mat-card {
padding: 0.4em;
margin: 1.5em 0.5em 0.5em;

.search-card-container {
display: flex;
width: 100%;
align-items: center;
margin: 0.5em;
}
.search-button-group {
flex-shrink: 0.6;
margin: 0 0.5em;
}

mat-form-field.full-text-search-field {
flex: 1;
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Component, Input, OnDestroy, OnInit } from "@angular/core";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { MatSelectModule } from "@angular/material/select";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatInputModule } from "@angular/material/input";
import { MatCardModule } from "@angular/material/card";
import { MatIconModule } from "@angular/material/icon";
import { MatButtonModule } from "@angular/material/button";
import {
fetchDatasetsAction,
fetchFacetCountsAction,
setSearchTermsAction,
setTextFilterAction,
} from "../../../state-management/actions/datasets.actions";
import { Store } from "@ngrx/store";
import { BehaviorSubject, Subject, Subscription } from "rxjs";
import {
debounceTime,
distinctUntilChanged,
withLatestFrom,
} from "rxjs/operators";
import { selectSearchTerms } from "../../../state-management/selectors/datasets.selectors";

@Component({
selector: "full-text-search-bar",
templateUrl: "./full-text-search-bar.component.html",
styleUrls: ["./full-text-search-bar.component.scss"],
standalone: true,
imports: [
MatFormFieldModule,
MatSelectModule,
FormsModule,
ReactiveFormsModule,
MatInputModule,
MatIconModule,
MatCardModule,
MatButtonModule,
],
})
export class FullTextSearchBarComponent implements OnInit, OnDestroy {
@Input() prefilledValue = "";
@Input() placeholder = "Text Search";
@Input() clear: boolean;

searchTerm = "";

searchTermSubject = new BehaviorSubject<string>("");
searchClickSubject = new Subject<void>();
subscriptions: Subscription[] = [];

constructor(private store: Store) {}

ngOnInit(): void {
this.searchTermSubject.next(this.prefilledValue);

this.subscriptions.push(
this.searchTermSubject
.pipe(debounceTime(200), distinctUntilChanged())
.subscribe((terms) => {
console.log(`set terms: ${terms}`);
this.store.dispatch(setSearchTermsAction({ terms }));
this.store.dispatch(setTextFilterAction({ text: terms }));
}),
);

const searchTerms$ = this.store.select(selectSearchTerms);

this.subscriptions.push(
this.searchClickSubject
.pipe(debounceTime(250), withLatestFrom(searchTerms$))
.subscribe(([_, terms]) => {
console.log(`latest terms: ${terms}`);
this.store.dispatch(fetchDatasetsAction());
this.store.dispatch(fetchFacetCountsAction());
}),
);
}

onSearch(): void {
this.searchClickSubject.next();
}

onSearchTermChange(terms: string) {
this.searchTermSubject.next(terms);
}

onClear(): void {
this.searchTerm = "";
this.searchTermSubject.next(undefined);
this.searchClickSubject.next();
}

ngOnDestroy(): void {
this.subscriptions.forEach((s) => s.unsubscribe());
}
}
26 changes: 13 additions & 13 deletions src/app/datasets/datasets-filter/datasets-filter.component.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<mat-card>
<mat-card-header class="section-container">
<mat-card-title>Search</mat-card-title>
<mat-card-title>Filter by...</mat-card-title>
<button
[disabled]="(hasAppliedFilters$ | async) === false"
mat-button
class="clear-button"
color="primary"
(click)="clearFacets()"
>
<mat-icon>clear_all</mat-icon> Clear
<mat-icon>clear_all</mat-icon> Reset
</button>
</mat-card-header>

Expand All @@ -23,17 +23,6 @@
>
</app-search-bar>

<app-search-bar
#searchBar
[prefilledValue]="searchTerms$ | async"
data-cy="text-search"
[placeholder]="'Text Search'"
[clear]="clearSearchBar"
(search)="textSearchChanged($event)"
(searchBarFocus)="textSearchChanged($event)"
>
</app-search-bar>

<mat-form-field>
<mat-label>Location</mat-label>
<mat-chip-grid #locationChipList>
Expand Down Expand Up @@ -213,5 +202,16 @@
</mat-chip-option>
</mat-chip-listbox>
</div>

<div class="section-container">
<button
mat-raised-button
color="primary"
class="applyButton"
(click)="applyFilters()"
>
Apply
</button>
</div>
</mat-card-content>
</mat-card>
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ mat-card {
white-space: normal;
word-break: break-all;
}

.applyButton {
width: 100%;
}
}

.section-container:first-child {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ describe("DatasetsFilterComponent", () => {
it("should contain a clear button", () => {
const compiled = fixture.debugElement.nativeElement;
const btn = compiled.querySelector(".clear-button");
expect(btn.textContent).toContain("Clear");
expect(btn.textContent).toContain("Reset");
});

describe("#getFacetId()", () => {
Expand Down
7 changes: 7 additions & 0 deletions src/app/datasets/datasets-filter/datasets-filter.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import {
removeScientificConditionAction,
setPidTermsAction,
setPidTermsFilterAction,
fetchDatasetsAction,
fetchFacetCountsAction,
} from "state-management/actions/datasets.actions";
import { combineLatest, BehaviorSubject, Observable, Subscription } from "rxjs";
import {
Expand Down Expand Up @@ -299,6 +301,11 @@ export class DatasetsFilterComponent implements OnInit, OnDestroy {
});
}

applyFilters() {
this.store.dispatch(fetchDatasetsAction());
this.store.dispatch(fetchFacetCountsAction());
}

removeCondition(condition: ScientificCondition, index: number) {
this.store.dispatch(removeScientificConditionAction({ index }));
this.store.dispatch(
Expand Down
2 changes: 2 additions & 0 deletions src/app/datasets/datasets.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import { AdminTabComponent } from "./admin-tab/admin-tab.component";
import { instrumentsReducer } from "state-management/reducers/instruments.reducer";
import { InstrumentEffects } from "state-management/effects/instruments.effects";
import { RelatedDatasetsComponent } from "./related-datasets/related-datasets.component";
import { FullTextSearchBarComponent } from "./dashboard/full-text-search/full-text-search-bar.component";

@NgModule({
imports: [
Expand Down Expand Up @@ -136,6 +137,7 @@ import { RelatedDatasetsComponent } from "./related-datasets/related-datasets.co
StoreModule.forFeature("publishedData", publishedDataReducer),
StoreModule.forFeature("logbooks", logbooksReducer),
LogbooksModule,
FullTextSearchBarComponent,
],
declarations: [
BatchViewComponent,
Expand Down

0 comments on commit f137de8

Please sign in to comment.