Skip to content

Commit e8c4d67

Browse files
authored
Fix/search filters (#360)
* fix(global-search-filters): Resolved TODOs * fix(global-search-filters): Fixed and simplified filters logic code * fix(global-search-resource-card): Made links open in a new tab * fix(global-search-filters): Added cardSearchResultCount to filter option * fix(global-search-filters): Fixed boolean filters selected state * fix(global-search-filters): Fixed after merge conflict * fix(global-search-filters): Fixed PR comments
1 parent 38570f5 commit e8c4d67

20 files changed

Lines changed: 197 additions & 201 deletions

src/app/shared/components/filter-chips/filter-chips.component.ts

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -29,51 +29,16 @@ export class FilterChipsComponent {
2929
});
3030

3131
filterOptions = computed(() => {
32-
// [RNi]: TODO check this with paging 5 for filter options and remove comment
33-
34-
// return this.filters()
35-
// .filter((filter) => filter.key && filter.options)
36-
// .map((filter) => ({
37-
// key: filter.key,
38-
// options: filter.options!.map((opt) => ({
39-
// id: String(opt.value || ''),
40-
// value: String(opt.value || ''),
41-
// label: opt.label,
42-
// })),
43-
// }));
44-
45-
const filtersData = this.filters();
46-
const cachedOptions = this.filterOptionsCache();
47-
const options: Record<string, { id: string; value: string; label: string }[]> = {};
48-
49-
filtersData.forEach((filter) => {
50-
if (filter.key && filter.options) {
51-
options[filter.key] = filter.options.map((opt) => ({
32+
return this.filters()
33+
.filter((filter) => filter.key && filter.options)
34+
.map((filter) => ({
35+
key: filter.key,
36+
options: filter.options!.map((opt) => ({
5237
id: String(opt.value || ''),
5338
value: String(opt.value || ''),
5439
label: opt.label,
55-
}));
56-
}
57-
});
58-
59-
Object.entries(cachedOptions).forEach(([filterKey, cachedOpts]) => {
60-
if (cachedOpts && cachedOpts.length > 0) {
61-
const existingOptions = options[filterKey] || [];
62-
const existingValues = new Set(existingOptions.map((opt) => opt.value));
63-
64-
const newCachedOptions = cachedOpts
65-
.filter((opt) => !existingValues.has(String(opt.value || '')))
66-
.map((opt) => ({
67-
id: String(opt.value || ''),
68-
value: String(opt.value || ''),
69-
label: opt.label,
70-
}));
71-
72-
options[filterKey] = [...newCachedOptions, ...existingOptions];
73-
}
74-
});
75-
76-
return options;
40+
})),
41+
}));
7742
});
7843

7944
chips = computed(() => {
@@ -85,8 +50,7 @@ export class FilterChipsComponent {
8550
.filter(([, value]) => value !== null && value !== '')
8651
.map(([key, value]) => {
8752
const filterLabel = labels.find((l) => l.key === key)?.label || key;
88-
//const filterOptionsList = options.find((o) => o.key === key)?.options || [];
89-
const filterOptionsList = options[key] || [];
53+
const filterOptionsList = options.find((o) => o.key === key)?.options || [];
9054
const option = filterOptionsList.find((opt) => opt.value === value || opt.id === value);
9155
const displayValue = option?.label || value || '';
9256

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
<div class="content-body filter dropdown-filter pb-4 z-5">
22
@if (isLoading()) {
33
<div class="flex justify-content-center align-items-center p-4">
4-
<osf-loading-spinner></osf-loading-spinner>
4+
<osf-loading-spinner />
55
</div>
66
} @else {
77
<div class="relative">
88
<p-select
99
[id]="filterType()"
1010
[options]="filterOptions()"
1111
optionLabel="label"
12-
optionValue="value"
1312
[ngModel]="selectedValue()"
1413
[placeholder]="currentSelectedOption() ? currentSelectedOption()?.label : placeholder()"
1514
styleClass="w-full"
@@ -22,24 +21,16 @@
2221
[lazy]="true"
2322
scrollHeight="200px"
2423
[autoOptionFocus]="false"
25-
[loading]="isLoading()"
24+
[loading]="isPaginationLoading() || isSearchLoading()"
2625
(onLazyLoad)="loadMoreItems($event)"
2726
(onChange)="onValueChange($event)"
2827
(onFilter)="onFilterChange($event)"
2928
[showClear]="!!selectedValue()"
30-
></p-select>
31-
32-
@if (isPaginationLoading()) {
33-
<div class="absolute top-1 right-8 pointer-events-none">
34-
<osf-loading-spinner />
35-
</div>
36-
}
37-
38-
@if (isSearchLoading()) {
39-
<div class="absolute top-1 right-14 pointer-events-none">
40-
<osf-loading-spinner />
41-
</div>
42-
}
29+
>
30+
<ng-template #item let-item>
31+
<p class="text-base">{{ item.label }} ({{ item.cardSearchResultCount }})</p>
32+
</ng-template>
33+
</p-select>
4334
</div>
4435
}
4536
</div>

src/app/shared/components/generic-filter/generic-filter.component.ts

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
1717
import { FormsModule } from '@angular/forms';
1818

19-
import { SelectOption } from '@shared/models';
19+
import { FilterOption } from '@shared/models';
2020

2121
import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component';
2222

@@ -29,8 +29,8 @@ import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.comp
2929
})
3030
export class GenericFilterComponent {
3131
private destroyRef = inject(DestroyRef);
32-
options = input<SelectOption[]>([]);
33-
searchResults = input<SelectOption[]>([]);
32+
options = input<FilterOption[]>([]);
33+
searchResults = input<FilterOption[]>([]);
3434
isLoading = input<boolean>(false);
3535
isPaginationLoading = input<boolean>(false);
3636
isSearchLoading = input<boolean>(false);
@@ -42,12 +42,12 @@ export class GenericFilterComponent {
4242
searchTextChanged = output<string>();
4343
loadMoreOptions = output<void>();
4444

45-
currentSelectedOption = signal<SelectOption | null>(null);
45+
currentSelectedOption = signal<FilterOption | null>(null);
4646
private searchSubject = new Subject<string>();
4747
private currentSearchText = signal<string>('');
48-
private searchResultOptions = signal<SelectOption[]>([]);
48+
private searchResultOptions = signal<FilterOption[]>([]);
4949
private isActivelySearching = signal<boolean>(false);
50-
private stableOptionsArray: SelectOption[] = [];
50+
private stableOptionsArray: FilterOption[] = [];
5151

5252
filterOptions = computed(() => {
5353
const searchResults = this.searchResultOptions();
@@ -59,7 +59,7 @@ export class GenericFilterComponent {
5959
}
6060

6161
const baseOptions = this.formatOptions(parentOptions);
62-
let newOptions: SelectOption[];
62+
let newOptions: FilterOption[];
6363

6464
if (searchResults.length > 0) {
6565
const searchFormatted = this.formatOptions(searchResults);
@@ -74,13 +74,13 @@ export class GenericFilterComponent {
7474
return this.stableOptionsArray;
7575
});
7676

77-
private formatOptions(options: SelectOption[]): SelectOption[] {
77+
private formatOptions(options: FilterOption[]): FilterOption[] {
7878
if (options.length > 0) {
7979
if (this.filterType() === 'dateCreated') {
8080
return options
8181
.filter((option) => option?.label)
82-
.sort((a, b) => b.label.localeCompare(a.label))
8382
.map((option) => ({
83+
...option,
8484
label: option.label || '',
8585
value: option.label || '',
8686
}));
@@ -89,6 +89,7 @@ export class GenericFilterComponent {
8989
.filter((option) => option?.label)
9090
.sort((a, b) => a.label.localeCompare(b.label))
9191
.map((option) => ({
92+
...option,
9293
label: option.label || '',
9394
value: option.value || '',
9495
}));
@@ -97,7 +98,7 @@ export class GenericFilterComponent {
9798
return [];
9899
}
99100

100-
private arraysEqual(a: SelectOption[], b: SelectOption[]): boolean {
101+
private arraysEqual(a: FilterOption[], b: FilterOption[]): boolean {
101102
if (a.length !== b.length) return false;
102103
for (let i = 0; i < a.length; i++) {
103104
if (a[i].value !== b[i].value || a[i].label !== b[i].label) {
@@ -107,7 +108,7 @@ export class GenericFilterComponent {
107108
return true;
108109
}
109110

110-
private updateStableArray(newOptions: SelectOption[]): void {
111+
private updateStableArray(newOptions: FilterOption[]): void {
111112
if (this.arraysEqual(this.stableOptionsArray, newOptions)) {
112113
return;
113114
}
@@ -163,10 +164,6 @@ export class GenericFilterComponent {
163164
}
164165
}
165166

166-
trackByOption(index: number, option: SelectOption): string {
167-
return option.value?.toString() || index.toString();
168-
}
169-
170167
onValueChange(event: SelectChangeEvent): void {
171168
const options = this.filterOptions();
172169
const selectedOption = event.value ? options.find((opt) => opt.value === event.value) : null;

src/app/shared/components/global-search/global-search.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<osf-search-results-container
1313
[provider]="provider()"
14+
[filters]="filters()"
1415
[tabOptions]="resourceTabOptions()"
1516
[resources]="resources()"
1617
[areResourcesLoading]="areResourcesLoading()"

src/app/shared/components/resource-card/components/file-secondary-metadata/file-secondary-metadata.component.html

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
<p>
1111
{{ 'resourceCard.labels.funder' | translate }}
1212
@for (funder of nodeFunders.slice(0, limit); track $index) {
13-
<a class="font-bold" [href]="funder.absoluteUrl" target="_blank">{{ funder.name }}{{ $last ? '' : ', ' }}</a>
13+
<a class="font-bold" [href]="funder.absoluteUrl" target="_blank" rel="noopener noreferrer"
14+
>{{ funder.name }}{{ $last ? '' : ', ' }}</a
15+
>
1416
}
1517
@if (nodeFunders.length > limit) {
1618
<span>{{ 'resourceCard.andCountMore' | translate: { count: nodeFunders.length - limit } }} </span>
@@ -26,22 +28,26 @@
2628
@if (nodeLicense) {
2729
<p>
2830
{{ 'resourceCard.labels.license' | translate }}
29-
<a class="font-bold" [attr.href]="nodeLicense!.absoluteUrl || null">{{ nodeLicense!.name }}</a>
31+
<a class="font-bold" [attr.href]="nodeLicense!.absoluteUrl || null" target="_blank" rel="noopener noreferrer">{{
32+
nodeLicense!.name
33+
}}</a>
3034
</p>
3135
}
3236

3337
@if (resourceValue.absoluteUrl) {
3438
<p>
3539
{{ 'resourceCard.labels.url' | translate }}
36-
<a class="font-bold" [href]="resourceValue.absoluteUrl">{{ resourceValue.absoluteUrl }}</a>
40+
<a class="font-bold" [href]="resourceValue.absoluteUrl" target="_blank" rel="noopener noreferrer">{{
41+
resourceValue.absoluteUrl
42+
}}</a>
3743
</p>
3844
}
3945

4046
@if (resourceValue.doi.length > 0) {
4147
<p>
4248
{{ 'resourceCard.labels.doi' | translate }}
4349
@for (doi of resourceValue.doi.slice(0, limit); track $index) {
44-
<a class="font-bold" [href]="doi" target="_blank">{{ doi }}{{ $last ? '' : ', ' }}</a>
50+
<a class="font-bold" [href]="doi" target="_blank" rel="noopener noreferrer">{{ doi }}{{ $last ? '' : ', ' }}</a>
4551
}
4652
@if (resourceValue.doi.length > limit) {
4753
<span>{{ 'resourceCard.andCountMore' | translate: { count: resourceValue.doi.length - limit } }} </span>

src/app/shared/components/resource-card/components/preprint-secondary-metadata/preprint-secondary-metadata.component.html

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
@if (resourceValue.provider) {
88
<p>
99
{{ 'resourceCard.labels.provider' | translate }}
10-
<a class="font-bold" [href]="resourceValue.provider!.absoluteUrl">{{ resourceValue.provider!.name }}</a>
10+
<a class="font-bold" [href]="resourceValue.provider!.absoluteUrl" target="_blank" rel="noopener noreferrer">{{
11+
resourceValue.provider!.name
12+
}}</a>
1113
</p>
1214
}
1315

1416
@if (resourceValue.hasDataResource) {
1517
<p>
1618
{{ 'resourceCard.labels.associatedData' | translate }}
17-
<a class="font-bold" [href]="resourceValue.hasDataResource">
19+
<a class="font-bold" [href]="resourceValue.hasDataResource" target="_blank" rel="noopener noreferrer">
1820
{{ resourceValue.hasDataResource }}
1921
</a>
2022
</p>
@@ -23,7 +25,12 @@
2325
@if (resourceValue.hasPreregisteredAnalysisPlan) {
2426
<p>
2527
{{ 'resourceCard.labels.associatedAnalysisPlan' | translate }}
26-
<a class="font-bold" [href]="resourceValue.hasPreregisteredAnalysisPlan">
28+
<a
29+
class="font-bold"
30+
[href]="resourceValue.hasPreregisteredAnalysisPlan"
31+
target="_blank"
32+
rel="noopener noreferrer"
33+
>
2734
{{ resourceValue.hasPreregisteredAnalysisPlan }}
2835
</a>
2936
</p>
@@ -32,7 +39,7 @@
3239
@if (resourceValue.hasPreregisteredStudyDesign) {
3340
<p>
3441
{{ 'resourceCard.labels.associatedStudyDesign' | translate }}
35-
<a class="font-bold" [href]="resourceValue.hasPreregisteredStudyDesign">
42+
<a class="font-bold" [href]="resourceValue.hasPreregisteredStudyDesign" target="_blank" rel="noopener noreferrer">
3643
{{ resourceValue.hasPreregisteredStudyDesign }}
3744
</a>
3845
</p>
@@ -53,16 +60,22 @@
5360
@if (resourceValue.license?.absoluteUrl) {
5461
<p>
5562
{{ 'resourceCard.labels.license' | translate }}
56-
<a class="font-bold" [attr.href]="resourceValue.license!.absoluteUrl || null">{{
57-
resourceValue.license!.name
58-
}}</a>
63+
<a
64+
class="font-bold"
65+
[attr.href]="resourceValue.license!.absoluteUrl || null"
66+
target="_blank"
67+
rel="noopener noreferrer"
68+
>{{ resourceValue.license!.name }}</a
69+
>
5970
</p>
6071
}
6172

6273
@if (resourceValue.absoluteUrl) {
6374
<p>
6475
{{ 'resourceCard.labels.url' | translate }}
65-
<a class="font-bold" [href]="resourceValue.absoluteUrl">{{ resourceValue.absoluteUrl }}</a>
76+
<a class="font-bold" [href]="resourceValue.absoluteUrl" target="_blank" rel="noopener noreferrer">{{
77+
resourceValue.absoluteUrl
78+
}}</a>
6679
</p>
6780
}
6881

@@ -71,7 +84,7 @@
7184
<p>
7285
{{ 'resourceCard.labels.doi' | translate }}
7386
@for (doi of resourceValue.doi.slice(0, limit); track $index) {
74-
<a class="font-bold" [href]="doi" target="_blank">{{ doi }}{{ $last ? '' : ', ' }}</a>
87+
<a class="font-bold" [href]="doi" target="_blank" rel="noopener noreferrer">{{ doi }}{{ $last ? '' : ', ' }}</a>
7588
}
7689
@if (resourceValue.doi.length > limit) {
7790
<span>{{ 'resourceCard.andCountMore' | translate: { count: resourceValue.doi.length - limit } }} </span>

0 commit comments

Comments
 (0)