-
Notifications
You must be signed in to change notification settings - Fork 33
refactor: relocate and redesign search bar in dataset and proposal pages #2095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
abdimo101
wants to merge
4
commits into
master
Choose a base branch
from
relocate-search-bar
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Contributor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/app/shared/modules/dynamic-material-table/table/dynamic-mat-table.component.scss:362-360` </location>
<code_context>
background-color: #ffffff;
}
+
+.table-header-controls {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ margin: 1rem 0;
+
+ &.with-side-filter {
+ margin-left: 3rem;
+ }
+
+ .global-search-wrapper {
</code_context>
<issue_to_address>
**suggestion:** Use of ::ng-deep for styling may lead to maintenance issues.
Since ::ng-deep is deprecated and may be removed in future Angular releases, please explore alternatives like custom themes or encapsulation to achieve the desired styling.
Suggested implementation:
```
.custom-text-field-wrapper .mat-mdc-text-field-wrapper {
background-color: white;
```
To complete this change, you must also:
1. Add the `custom-text-field-wrapper` class to the `mat-form-field` element in your component's template, e.g.:
```html
<mat-form-field class="custom-text-field-wrapper">
```
2. If you are using Angular's default view encapsulation, this selector will work. If you have issues with specificity, consider using `ViewEncapsulation.None` in your component decorator, but this is usually not necessary if you use a custom class.
</issue_to_address>
### Comment 2
<location> `src/app/proposals/proposal-table/proposal-table.component.ts:311` </location>
<code_context>
+ );
+ }
+
+ onTextSearchChange(term: string) {
+ this.globalTextSearch = term;
+ this.store.dispatch(setSearchTermsAction({ terms: term }));
</code_context>
<issue_to_address>
**issue (complexity):** Consider moving search query parsing and router logic into a dedicated service and using a reactive FormControl for input handling.
Consider extracting the “searchQuery” parsing/serialization + router calls into a small service and driving your input via a reactive FormControl. That will remove the three new methods, the manual JSON.parse/stringify and the tight coupling to ActivatedRoute/Router in your component.
Example service (search-query.service.ts):
```ts
import { Injectable } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
interface SearchQuery { text?: string; /*…other filters…*/ }
@Injectable({ providedIn: 'root' })
export class SearchQueryService {
constructor(private route: ActivatedRoute, private router: Router) {}
// Observable of current text search
get text$(): Observable<string | undefined> {
return this.route.queryParamMap.pipe(
map(mp => {
const raw = mp.get('searchQuery');
return raw ? (JSON.parse(raw) as SearchQuery).text : undefined;
})
);
}
// Update text search and reset pageIndex
setText(text?: string) {
const raw = this.route.snapshot.queryParamMap.get('searchQuery');
const q = (raw ? JSON.parse(raw) : {}) as SearchQuery;
if (text) { q.text = text; } else { delete q.text; }
return this.router.navigate([], {
queryParams: { searchQuery: JSON.stringify(q), pageIndex: 0 },
queryParamsHandling: 'merge'
});
}
}
```
Then in your component:
```ts
import { FormControl } from '@angular/forms';
import { debounceTime } from 'rxjs/operators';
export class ProposalTableComponent implements OnInit, OnDestroy {
textControl = new FormControl('');
private subs: Subscription[] = [];
constructor(private searchQs: SearchQueryService, /*…*/) {}
ngOnInit() {
this.subs.push(
// seed input from URL
this.searchQs.text$.subscribe(t => this.textControl.setValue(t || '', { emitEvent: false })),
// update URL/store on user input
this.textControl.valueChanges
.pipe(debounceTime(300))
.subscribe(text => {
this.searchQs.setText(text || undefined);
this.store.dispatch(addProposalFilterAction({ key: 'text', value: text, filterType: 'text' }));
})
);
}
ngOnDestroy() { this.subs.forEach(s => s.unsubscribe()); }
}
```
This removes onTextSearchChange, getTextSearchParam and onTextSearchAction, centralizes parsing logic, and makes your component far simpler.
</issue_to_address>
### Comment 3
<location> `src/app/datasets/dataset-table/dataset-table.component.ts:566` </location>
<code_context>
}),
);
+
+ this.subscriptions.push(
+ this.route.queryParams.subscribe((queryParams) => {
+ const searchQuery = JSON.parse(queryParams.searchQuery || "{}");
</code_context>
<issue_to_address>
**issue (complexity):** Consider moving query parameter subscriptions and related action dispatches from the component into NgRx Effects to streamline the component logic.
```markdown
Rather than having the component manually subscribe to `route.queryParams` and dispatch multiple actions in two separate handlers, you can push that logic into NgRx Effects. Your component then only needs a single “set‐text” dispatch and no manual subscriptions.
**1) Create two Effects in `dataset.effects.ts`:**
```ts
// dataset.effects.ts
import { Injectable } from '@angular/core';
import { RouterNavigationAction, ROUTER_NAVIGATION } from '@ngrx/router-store';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import {
setTextFilterAction,
fetchDatasetsAction,
fetchFacetCountsAction
} from 'state-management/actions/datasets.actions';
import { map, switchMap } from 'rxjs/operators';
@Injectable()
export class DatasetEffects {
// Listen for router‐store navigation and pull out ?searchQuery
initSearchFromUrl$ = createEffect(() =>
this.actions$.pipe(
ofType<RouterNavigationAction>(ROUTER_NAVIGATION),
map(action => {
const qp = action.payload.routerState.root.queryParams?.searchQuery;
const { text = '' } = qp ? JSON.parse(qp) : {};
return setTextFilterAction({ text });
})
)
);
// Whenever setTextFilterAction fires, fetch data + facets
fetchOnFilter$ = createEffect(() =>
this.actions$.pipe(
ofType(setTextFilterAction),
switchMap(() => [
fetchDatasetsAction(),
fetchFacetCountsAction()
])
)
);
constructor(private actions$: Actions) {}
}
```
**2) Simplify your component:**
- Remove the `route.queryParams` subscription and `subscriptions` array
- Remove `onTextSearchAction()`
- Let `onTextSearchChange()` only dispatch the single action
```ts
// your-table.component.ts (excerpt)
export class YourTableComponent {
globalTextSearch = '';
constructor(private store: Store) {}
// now just emit one action
onTextSearchChange(term: string) {
this.globalTextSearch = term;
this.store.dispatch(setTextFilterAction({ text: term }));
}
// drop onTextSearchAction() entirely
}
```
With this:
- The Effect `initSearchFromUrl$` handles URL → store
- `fetchOnFilter$` handles store → side-effects (fetch + facet)
- The component is flatter and only responsible for wiring UI → `setTextFilterAction`
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
This PR relocates the search bar into the dynamic-mat-table header with improved styling.
Dataset page:

Proposal page:

Search bar when writing:

Motivation
Fixes:
Please provide a list of the fixes implemented in this PR
Changes:
Please provide a list of the changes implemented by this PR
Tests included
Documentation
official documentation info
If you have updated the official documentation, please provide PR # and URL of the pages where the updates are included
Backend version
Summary by Sourcery
Relocate and redesign the global search bar by embedding it within the dynamic material table header on both dataset and proposal pages, revamp layout and styling of dashboard and table header controls, and wire up new search event handling in table components.
New Features:
Enhancements:
Chores: