Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7f61428
feat(search): added generic search component
volodyayakubovskyy Aug 4, 2025
c1fb0e7
feat(search): improved search for institutions
volodyayakubovskyy Aug 5, 2025
7184e54
feat(search): remove unused files
volodyayakubovskyy Aug 5, 2025
055fbe3
feat(search): fixed some issues
volodyayakubovskyy Aug 5, 2025
1ac38d4
Merge remote-tracking branch 'origin/main' into feat/398
nsemets Aug 6, 2025
8b55a14
fix(search): removed comments
nsemets Aug 6, 2025
ecfab6d
Merge remote-tracking branch 'origin/main' into feat/398
nsemets Aug 11, 2025
c98a37a
fix(profile): renamed it to profile
nsemets Aug 19, 2025
a264fca
Merge remote-tracking branch 'origin/feat/398' into fix/search-updates
nsemets Aug 19, 2025
b6fca34
fix(updates): updates
nsemets Aug 20, 2025
ed5f60b
Merge branch 'refs/heads/main' into fix/search-updates
rrromchIk Aug 22, 2025
c228a8a
Merge branch 'refs/heads/main' into fix/search-updates
rrromchIk Aug 22, 2025
0c5db72
Merge branch 'refs/heads/main' into fix/search-updates
rrromchIk Aug 22, 2025
e75f063
fix(branding): Minor fixed regarding provider hero for preprints and …
rrromchIk Aug 22, 2025
f7a9a44
refactor(search-results-container): Encapsulated some logic, reduced …
rrromchIk Aug 22, 2025
4dd8a34
refactor(search-results-container): Encapsulated tabs logic
rrromchIk Aug 22, 2025
1c0e7d1
refactor(search): Refactored partly search section for preprints and …
rrromchIk Aug 22, 2025
a452b61
refactor(search): Refactored search logic for global, institutions pa…
rrromchIk Aug 28, 2025
bb70182
Merge branch 'refs/heads/main' into fix/search-updates
rrromchIk Aug 28, 2025
ff0211b
refactor(search): Refactored search logic for global, institutions pa…
rrromchIk Aug 28, 2025
4d52403
refactor(search): Refactored search logic for profile
rrromchIk Aug 28, 2025
c35d955
feat(profile): Implemented my-profile and user/:id pages
rrromchIk Aug 29, 2025
c2e6ac7
refactor(preprint-provider-discover): Removed search section that use…
rrromchIk Aug 29, 2025
84540fd
refactor(search): Create shared component that encapsulates search lo…
rrromchIk Aug 31, 2025
de72321
refactor(shared-search): Extracted state model. Reduced duplications.…
rrromchIk Sep 1, 2025
81aa4f4
refactor(search): Using ResourceType instead of ResourceTab. Fixed pa…
rrromchIk Sep 1, 2025
ccf4b0a
Merge branch 'main' into fix/search-updates
rrromchIk Sep 1, 2025
17392f7
refactor(search-models): Cleaned up models - renamed files, moved mod…
rrromchIk Sep 2, 2025
9496e2c
Merge branch 'main' into fix/search-updates
rrromchIk Sep 2, 2025
30bac9e
refactor(index-card-search): Refactored models
rrromchIk Sep 2, 2025
dd07529
fix(resource-card): Fixed resource-card component
rrromchIk Sep 3, 2025
1bb26ba
fix(resource-card-secondary-metadata): Fixed resource-card component
rrromchIk Sep 3, 2025
702d618
Merge branch 'main' into fix/search-updates
rrromchIk Sep 3, 2025
9af6bb9
fix(search): Fixed PR comments and conflicts after merge
rrromchIk Sep 4, 2025
53bd68c
refactor(search): Renamed OsfSearch- to GlobalSearch-
rrromchIk Sep 4, 2025
636bb94
fix(unit-tests): fixed unit tests
nsemets Sep 4, 2025
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { ProfileState } from './features/profile/store';
import { RegistriesState } from './features/registries/store';
import { LicensesHandlers, ProjectsHandlers, ProvidersHandlers } from './features/registries/store/handlers';
import { FilesHandlers } from './features/registries/store/handlers/files.handlers';
import { ResourceFiltersOptionsState } from './features/search/components/filters/store';
import { ResourceFiltersState } from './features/search/components/resource-filters/store';
import { SearchState } from './features/search/store';
import { LicensesService } from './shared/services';

Expand Down Expand Up @@ -67,7 +65,7 @@ export const routes: Routes = [
{
path: 'search',
loadComponent: () => import('./features/search/search.component').then((mod) => mod.SearchComponent),
providers: [provideStates([ResourceFiltersState, ResourceFiltersOptionsState, SearchState])],
providers: [provideStates([SearchState])],
},
{
path: 'my-projects',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,27 @@ <h1>{{ institution().name }}</h1>
<osf-reusable-filters
[filters]="filters()"
[selectedValues]="selectedValues()"
[filterSearchResults]="filterSearchResults()"
[isLoading]="isResourcesLoading()"
[showEmptyState]="true"
(loadFilterOptions)="onLoadFilterOptions($event)"
(filterValueChanged)="onFilterChanged($event)"
(filterSearchChanged)="onFilterSearchChanged($event)"
(loadMoreFilterOptions)="onLoadMoreFilterOptions($event)"
/>
</div>

<div slot="mobile-filters">
<osf-reusable-filters
[filters]="filters()"
[selectedValues]="selectedValues()"
[filterSearchResults]="filterSearchResults()"
[isLoading]="isResourcesLoading()"
[showEmptyState]="true"
(loadFilterOptions)="onLoadFilterOptions($event)"
(filterValueChanged)="onFilterChanged($event)"
(filterSearchChanged)="onFilterSearchChanged($event)"
(loadMoreFilterOptions)="onLoadMoreFilterOptions($event)"
/>
</div>
</osf-search-results-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@ import { SEARCH_TAB_OPTIONS } from '@osf/shared/constants';
import { ResourceTab } from '@osf/shared/enums';
import { DiscoverableFilter } from '@osf/shared/models';
import {
ClearFilterSearchResults,
FetchInstitutionById,
FetchResources,
FetchResourcesByLink,
InstitutionsSearchSelectors,
LoadFilterOptions,
LoadFilterOptionsAndSetValues,
LoadFilterOptionsWithSearch,
LoadMoreFilterOptions,
SetFilterValues,
UpdateFilterValue,
UpdateResourceType,
Expand Down Expand Up @@ -75,13 +78,17 @@ export class InstitutionsSearchComponent implements OnInit {
first = select(InstitutionsSearchSelectors.getFirst);
next = select(InstitutionsSearchSelectors.getNext);
previous = select(InstitutionsSearchSelectors.getPrevious);
filterSearchResults = select(InstitutionsSearchSelectors.getFilterSearchCache);

private readonly actions = createDispatchMap({
fetchInstitution: FetchInstitutionById,
updateResourceType: UpdateResourceType,
updateSortBy: UpdateSortBy,
loadFilterOptions: LoadFilterOptions,
loadFilterOptionsAndSetValues: LoadFilterOptionsAndSetValues,
loadFilterOptionsWithSearch: LoadFilterOptionsWithSearch,
clearFilterSearchResults: ClearFilterSearchResults,
loadMoreFilterOptions: LoadMoreFilterOptions,
setFilterValues: SetFilterValues,
updateFilterValue: UpdateFilterValue,
fetchResourcesByLink: FetchResourcesByLink,
Expand Down Expand Up @@ -148,6 +155,18 @@ export class InstitutionsSearchComponent implements OnInit {
this.actions.loadFilterOptions(event.filterType);
}

onFilterSearchChanged(event: { filterType: string; searchText: string }): void {
if (event.searchText.trim()) {
this.actions.loadFilterOptionsWithSearch(event.filterType, event.searchText);
} else {
this.actions.clearFilterSearchResults(event.filterType);
}
}

onLoadMoreFilterOptions(event: { filterType: string; filter: DiscoverableFilter }): void {
this.actions.loadMoreFilterOptions(event.filterType);
}

onFilterChanged(event: { filterType: string; value: string | null }): void {
this.actions.updateFilterValue(event.filterType, event.value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { Skeleton } from 'primeng/skeleton';
import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
import { RouterLink } from '@angular/router';

import { ResourceTab } from '@shared/enums';
import { SubjectModel } from '@shared/models';

@Component({
Expand All @@ -20,14 +19,8 @@ export class BrowseBySubjectsComponent {
subjects = input.required<SubjectModel[]>();
linksToSearchPageForSubject = computed(() => {
return this.subjects().map((subject) => ({
resourceTab: ResourceTab.Preprints,
activeFilters: JSON.stringify([
{
filterName: 'Subject',
label: subject.name,
value: subject.iri,
},
]),
tab: 'preprints',
filter_subject: subject.iri,
}));
});
areSubjectsLoading = input.required<boolean>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { inject, Injectable } from '@angular/core';

import { PreprintsDiscoverSelectors } from '@osf/features/preprints/store/preprints-discover';
import { PreprintsResourcesFiltersSelectors } from '@osf/features/preprints/store/preprints-resources-filters';
import { ResourceFiltersStateModel } from '@osf/features/search/components/resource-filters/store';
import { ProfileResourceFiltersStateModel } from '@osf/features/profile/components/profile-resource-filters/store';
import { addFiltersParams, getResourceTypes } from '@osf/shared/helpers';
import {
Creator,
Expand All @@ -27,7 +27,9 @@ export class PreprintsFiltersOptionsService {
filtersOptions = inject(FiltersOptionsService);

private getFilterParams(): Record<string, string> {
return addFiltersParams(select(PreprintsResourcesFiltersSelectors.getAllFilters)() as ResourceFiltersStateModel);
return addFiltersParams(
select(PreprintsResourcesFiltersSelectors.getAllFilters)() as ProfileResourceFiltersStateModel
);
}

private getParams(): Record<string, string> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from '@osf/features/preprints/store/preprints-discover/preprints-discover.actions';
import { PreprintsDiscoverStateModel } from '@osf/features/preprints/store/preprints-discover/preprints-discover.model';
import { PreprintsResourcesFiltersSelectors } from '@osf/features/preprints/store/preprints-resources-filters';
import { ResourceFiltersStateModel } from '@osf/features/search/components/resource-filters/store';
import { ProfileResourceFiltersStateModel } from '@osf/features/profile/components/profile-resource-filters/store';
import { addFiltersParams, getResourceTypes } from '@osf/shared/helpers';
import { GetResourcesRequestTypeEnum, ResourceTab } from '@shared/enums';
import { SearchService } from '@shared/services';
Expand Down Expand Up @@ -51,7 +51,7 @@ export class PreprintsDiscoverState implements NgxsOnInit {
ctx.patchState({ resources: { ...state.resources, isLoading: true } });
if (query.type === GetResourcesRequestTypeEnum.GetResources) {
const filters = this.store.selectSnapshot(PreprintsResourcesFiltersSelectors.getAllFilters);
const filtersParams = addFiltersParams(filters as ResourceFiltersStateModel);
const filtersParams = addFiltersParams(filters as ProfileResourceFiltersStateModel);
const searchText = state.searchText;
const sortBy = state.sortBy;
const resourceTab = ResourceTab.Preprints;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { tap } from 'rxjs';

import { inject, Injectable } from '@angular/core';

import { MyProfileFiltersOptionsService } from '@osf/features/profile/services';
import { ResourceFiltersOptionsStateModel } from '@osf/features/search/components/filters/store';
import { ProfileFiltersOptionsService } from '@osf/features/profile/services/profile-resource-filters.service';

import {
GetAllOptions,
Expand Down Expand Up @@ -36,10 +35,10 @@ import { ProfileResourceFiltersOptionsStateModel } from './profile-resource-filt
@Injectable()
export class ProfileResourceFiltersOptionsState {
readonly store = inject(Store);
readonly filtersOptionsService = inject(MyProfileFiltersOptionsService);
readonly filtersOptionsService = inject(ProfileFiltersOptionsService);

@Action(GetDatesCreatedOptions)
getDatesCreated(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getDatesCreated(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getDates().pipe(
tap((datesCreated) => {
ctx.patchState({ datesCreated: datesCreated });
Expand All @@ -48,7 +47,7 @@ export class ProfileResourceFiltersOptionsState {
}

@Action(GetFundersOptions)
getFunders(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getFunders(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getFunders().pipe(
tap((funders) => {
ctx.patchState({ funders: funders });
Expand All @@ -57,7 +56,7 @@ export class ProfileResourceFiltersOptionsState {
}

@Action(GetSubjectsOptions)
getSubjects(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getSubjects(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getSubjects().pipe(
tap((subjects) => {
ctx.patchState({ subjects: subjects });
Expand All @@ -66,7 +65,7 @@ export class ProfileResourceFiltersOptionsState {
}

@Action(GetLicensesOptions)
getLicenses(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getLicenses(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getLicenses().pipe(
tap((licenses) => {
ctx.patchState({ licenses: licenses });
Expand All @@ -75,7 +74,7 @@ export class ProfileResourceFiltersOptionsState {
}

@Action(GetResourceTypesOptions)
getResourceTypes(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getResourceTypes(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getResourceTypes().pipe(
tap((resourceTypes) => {
ctx.patchState({ resourceTypes: resourceTypes });
Expand All @@ -84,7 +83,7 @@ export class ProfileResourceFiltersOptionsState {
}

@Action(GetInstitutionsOptions)
getInstitutions(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getInstitutions(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getInstitutions().pipe(
tap((institutions) => {
ctx.patchState({ institutions: institutions });
Expand All @@ -93,15 +92,15 @@ export class ProfileResourceFiltersOptionsState {
}

@Action(GetProvidersOptions)
getProviders(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getProviders(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getProviders().pipe(
tap((providers) => {
ctx.patchState({ providers: providers });
})
);
}
@Action(GetPartOfCollectionOptions)
getPartOfCollection(ctx: StateContext<ResourceFiltersOptionsStateModel>) {
getPartOfCollection(ctx: StateContext<ProfileResourceFiltersOptionsStateModel>) {
return this.filtersOptionsService.getPartOtCollections().pipe(
tap((partOfCollection) => {
ctx.patchState({ partOfCollection: partOfCollection });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
import { Selector } from '@ngxs/store';

import { ResourceFiltersStateModel } from '@osf/features/search/components/resource-filters/store';
import { ResourceFilterLabel } from '@shared/models';

import { ProfileResourceFiltersStateModel } from './profile-resource-filters.model';
import { ProfileResourceFiltersState } from './profile-resource-filters.state';

export class ProfileResourceFiltersSelectors {
@Selector([ProfileResourceFiltersState])
static getAllFilters(state: ResourceFiltersStateModel): ResourceFiltersStateModel {
static getAllFilters(state: ProfileResourceFiltersStateModel): ProfileResourceFiltersStateModel {
return {
...state,
};
}

@Selector([ProfileResourceFiltersState])
static getCreator(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getCreator(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.creator;
}

@Selector([ProfileResourceFiltersState])
static getDateCreated(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getDateCreated(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.dateCreated;
}

@Selector([ProfileResourceFiltersState])
static getFunder(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getFunder(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.funder;
}

@Selector([ProfileResourceFiltersState])
static getSubject(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getSubject(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.subject;
}

@Selector([ProfileResourceFiltersState])
static getLicense(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getLicense(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.license;
}

@Selector([ProfileResourceFiltersState])
static getResourceType(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getResourceType(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.resourceType;
}

@Selector([ProfileResourceFiltersState])
static getInstitution(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getInstitution(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.institution;
}

@Selector([ProfileResourceFiltersState])
static getProvider(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getProvider(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.provider;
}

@Selector([ProfileResourceFiltersState])
static getPartOfCollection(state: ResourceFiltersStateModel): ResourceFilterLabel {
static getPartOfCollection(state: ProfileResourceFiltersStateModel): ResourceFilterLabel {
return state.partOfCollection;
}
}
3 changes: 0 additions & 3 deletions src/app/features/profile/profile.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { toSignal } from '@angular/core/rxjs-interop';
import { Router } from '@angular/router';

import { UserSelectors } from '@osf/core/store/user';
import { ResetFiltersState } from '@osf/features/search/components/resource-filters/store';
import { ResetSearchState } from '@osf/features/search/store';
import { EducationHistoryComponent, EmploymentHistoryComponent } from '@osf/shared/components';
import { IS_MEDIUM } from '@osf/shared/helpers';
Expand Down Expand Up @@ -39,7 +38,6 @@ export class ProfileComponent implements OnDestroy {
readonly isMedium = toSignal(inject(IS_MEDIUM));
readonly currentUser = select(UserSelectors.getCurrentUser);
readonly actions = createDispatchMap({
resetFiltersState: ResetFiltersState,
resetSearchState: ResetSearchState,
setIsMyProfile: SetIsMyProfile,
});
Expand All @@ -53,7 +51,6 @@ export class ProfileComponent implements OnDestroy {
}

ngOnDestroy(): void {
this.actions.resetFiltersState();
this.actions.resetSearchState();
this.actions.setIsMyProfile(false);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Action, NgxsOnInit, State, StateContext } from '@ngxs/store';
import { patch } from '@ngxs/store/operators';

import { BehaviorSubject, catchError, EMPTY, forkJoin, of, switchMap, tap } from 'rxjs';
import { BehaviorSubject, catchError, EMPTY, forkJoin, switchMap, tap } from 'rxjs';

import { inject, Injectable } from '@angular/core';

Expand Down Expand Up @@ -141,7 +141,8 @@ export class RegistriesProviderSearchState implements NgxsOnInit {
ctx.patchState({ filters: loadingFilters });

return this.searchService.getFilterOptions(filterKey).pipe(
tap((options) => {
tap((response) => {
const options = response.options;
const updatedCache = { ...ctx.getState().filterOptionsCache, [filterKey]: options };
const updatedFilters = ctx
.getState()
Expand Down Expand Up @@ -189,14 +190,14 @@ export class RegistriesProviderSearchState implements NgxsOnInit {

const observables = filterKeys.map((key) =>
this.searchService.getFilterOptions(key).pipe(
tap((options) => {
tap((response) => {
const options = response.options;
const updatedCache = { ...ctx.getState().filterOptionsCache, [key]: options };
const updatedFilters = ctx
.getState()
.filters.map((f) => (f.key === key ? { ...f, options, isLoaded: true, isLoading: false } : f));
ctx.patchState({ filters: updatedFilters, filterOptionsCache: updatedCache });
}),
catchError(() => of({ filterKey: key, options: [] }))
})
)
);

Expand Down
Loading