From 75937c2664f5f5391f6a014bdcde5209ca955185 Mon Sep 17 00:00:00 2001
From: nsemets
Date: Thu, 16 Oct 2025 10:51:47 +0300
Subject: [PATCH 1/2] fix(my-projects): added new filter for projects
---
.../pages/dashboard/dashboard.component.html | 8 +-
.../dashboard/dashboard.component.spec.ts | 17 +-
.../pages/dashboard/dashboard.component.ts | 4 +-
.../constants/project-filter-options.const.ts | 17 ++
.../my-projects/my-projects.component.html | 35 +++-
.../my-projects/my-projects.component.spec.ts | 176 +++++-------------
.../my-projects/my-projects.component.ts | 27 ++-
.../my-projects-table.component.html | 132 +++++++------
.../my-projects-table.component.spec.ts | 25 +--
.../my-projects-table.component.ts | 6 +-
.../shared/enums/resource-search-mode.enum.ts | 6 +-
.../shared/services/my-resources.service.ts | 8 +
src/assets/i18n/en.json | 5 +
13 files changed, 223 insertions(+), 243 deletions(-)
create mode 100644 src/app/features/my-projects/constants/project-filter-options.const.ts
diff --git a/src/app/features/home/pages/dashboard/dashboard.component.html b/src/app/features/home/pages/dashboard/dashboard.component.html
index d2e420a6d..059bf4be3 100644
--- a/src/app/features/home/pages/dashboard/dashboard.component.html
+++ b/src/app/features/home/pages/dashboard/dashboard.component.html
@@ -25,14 +25,18 @@
{{ 'home.loggedIn.dashboard.quickSearch.osf' | translate }}
+
+
{
+describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture;
@@ -31,7 +37,7 @@ describe.skip('DashboardComponent', () => {
imports: [
DashboardComponent,
OSFTestingStoreModule,
- ...MockComponents(SubHeaderComponent, MyProjectsTableComponent, LoadingSpinnerComponent),
+ ...MockComponents(SubHeaderComponent, MyProjectsTableComponent, LoadingSpinnerComponent, SearchInputComponent),
],
providers: [
{
@@ -46,6 +52,7 @@ describe.skip('DashboardComponent', () => {
dispatch: jest.fn(),
},
},
+ MockProviders(CustomDialogService, CustomConfirmationService, ProjectRedirectDialogService),
],
}).compileComponents();
@@ -53,7 +60,7 @@ describe.skip('DashboardComponent', () => {
component = fixture.componentInstance;
});
- it('should show loading s pinner when projects are loading', () => {
+ it('should show loading spinner when projects are loading', () => {
areProjectsLoadingSignal.set(true);
fixture.detectChanges();
diff --git a/src/app/features/home/pages/dashboard/dashboard.component.ts b/src/app/features/home/pages/dashboard/dashboard.component.ts
index 4d3ce1082..54aa5bba9 100644
--- a/src/app/features/home/pages/dashboard/dashboard.component.ts
+++ b/src/app/features/home/pages/dashboard/dashboard.component.ts
@@ -19,6 +19,7 @@ import {
IconComponent,
LoadingSpinnerComponent,
MyProjectsTableComponent,
+ SearchInputComponent,
SubHeaderComponent,
} from '@osf/shared/components';
import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants';
@@ -34,6 +35,7 @@ import { ClearMyResources, GetMyProjects, MyResourcesSelectors } from '@osf/shar
Button,
SubHeaderComponent,
MyProjectsTableComponent,
+ SearchInputComponent,
IconComponent,
TranslatePipe,
LoadingSpinnerComponent,
@@ -68,8 +70,6 @@ export class DashboardComponent implements OnInit {
readonly existsProjects = computed(() => this.projects().length || !!this.searchControl.value?.length);
- emailAddress = '';
-
constructor() {
this.setupSearchSubscription();
this.setupTotalRecordsEffect();
diff --git a/src/app/features/my-projects/constants/project-filter-options.const.ts b/src/app/features/my-projects/constants/project-filter-options.const.ts
new file mode 100644
index 000000000..8c3e2ea27
--- /dev/null
+++ b/src/app/features/my-projects/constants/project-filter-options.const.ts
@@ -0,0 +1,17 @@
+import { ResourceSearchMode } from '@osf/shared/enums';
+import { TabOption } from '@osf/shared/models';
+
+export const PROJECT_FILTER_OPTIONS: TabOption[] = [
+ {
+ value: ResourceSearchMode.User,
+ label: 'myProjects.tabOptions.all',
+ },
+ {
+ value: ResourceSearchMode.Root,
+ label: 'myProjects.tabOptions.root',
+ },
+ {
+ value: ResourceSearchMode.Component,
+ label: 'myProjects.tabOptions.component',
+ },
+];
diff --git a/src/app/features/my-projects/my-projects.component.html b/src/app/features/my-projects/my-projects.component.html
index 543ed4e40..725a1ac05 100644
--- a/src/app/features/my-projects/my-projects.component.html
+++ b/src/app/features/my-projects/my-projects.component.html
@@ -28,10 +28,25 @@
}
+
+
+
+
+
+
+
+
+
+
+
+
{
let component: MyProjectsComponent;
let fixture: ComponentFixture;
+ let mockRouter: ReturnType;
+ let mockActivatedRoute: ReturnType;
let isMediumSubject: BehaviorSubject;
- let queryParamsSubject: BehaviorSubject>;
- let store: jest.Mocked;
- let router: jest.Mocked;
beforeEach(async () => {
isMediumSubject = new BehaviorSubject(false);
- queryParamsSubject = new BehaviorSubject>({});
-
- queryParamsSubject.next({});
-
- (MOCK_STORE.selectSignal as jest.Mock).mockImplementation((selector) => {
- if (
- selector === MyResourcesSelectors.getTotalProjects ||
- selector === MyResourcesSelectors.getTotalRegistrations ||
- selector === MyResourcesSelectors.getTotalPreprints ||
- selector === MyResourcesSelectors.getTotalBookmarks
- )
- return () => 0;
- if (selector === BookmarksSelectors.getBookmarksCollectionId) return () => null;
- if (
- selector === MyResourcesSelectors.getProjects ||
- selector === MyResourcesSelectors.getRegistrations ||
- selector === MyResourcesSelectors.getPreprints ||
- selector === MyResourcesSelectors.getBookmarks
- )
- return () => [];
- return () => undefined;
- });
+ mockActivatedRoute = ActivatedRouteMockBuilder.create().withQueryParams({ tab: '1' }).build();
+ mockRouter = RouterMockBuilder.create().build();
await TestBed.configureTestingModule({
imports: [
MyProjectsComponent,
OSFTestingModule,
- ...MockComponents(SubHeaderComponent, MyProjectsTableComponent, SelectComponent),
+ ...MockComponents(SubHeaderComponent, MyProjectsTableComponent, SelectComponent, SearchInputComponent),
],
providers: [
- MockProvider(Store, MOCK_STORE),
- MockProvider(DialogService, { open: jest.fn() }),
- MockProvider(ConfirmationService, { confirm: jest.fn() }),
- MockProvider(ActivatedRoute, { queryParams: queryParamsSubject.asObservable() }),
- MockProvider(Router, { navigate: jest.fn() }),
+ provideMockStore({
+ signals: [
+ { selector: MyResourcesSelectors.getTotalProjects, value: 0 },
+ { selector: MyResourcesSelectors.getTotalRegistrations, value: 0 },
+ { selector: MyResourcesSelectors.getTotalPreprints, value: 0 },
+ { selector: MyResourcesSelectors.getTotalBookmarks, value: 0 },
+ { selector: BookmarksSelectors.getBookmarksCollectionId, value: null },
+ { selector: MyResourcesSelectors.getProjects, value: [] },
+ { selector: MyResourcesSelectors.getRegistrations, value: [] },
+ { selector: MyResourcesSelectors.getPreprints, value: [] },
+ { selector: MyResourcesSelectors.getBookmarks, value: [] },
+ ],
+ }),
+ { provide: ActivatedRoute, useValue: mockActivatedRoute },
+ { provide: Router, useValue: mockRouter },
+ MockProvider(CustomDialogService),
MockProvider(IS_MEDIUM, isMediumSubject),
- MockProvider(ProjectRedirectDialogService, { showProjectRedirectDialog: jest.fn() }),
+ MockProvider(ProjectRedirectDialogService),
],
}).compileComponents();
fixture = TestBed.createComponent(MyProjectsComponent);
component = fixture.componentInstance;
- store = TestBed.inject(Store) as jest.Mocked;
- router = TestBed.inject(Router) as jest.Mocked;
-
- store.dispatch.mockReturnValue(of(undefined));
-
- (component as any).queryParams = () => ({});
-
fixture.detectChanges();
});
@@ -88,110 +73,43 @@ describe('MyProjectsComponent', () => {
expect(component).toBeTruthy();
});
- it('should update component state from query params', () => {
- component.updateComponentState({ page: 2, size: 20, search: 'q', sortColumn: 'name', sortOrder: SortOrder.Desc });
-
- expect(component.currentPage()).toBe(2);
- expect(component.currentPageSize()).toBe(20);
- expect(component.searchControl.value).toBe('q');
- expect(component.sortColumn()).toBe('name');
- expect(component.sortOrder()).toBe(SortOrder.Desc);
- expect(component.tableParams().firstRowIndex).toBe(20);
- expect(component.tableParams().rows).toBe(20);
- });
-
- it('should create filters depending on tab', () => {
- const filtersProjects = component.createFilters({
- page: 1,
- size: 10,
- search: 's',
- sortColumn: 'name',
- sortOrder: SortOrder.Asc,
- });
- expect(filtersProjects.searchValue).toBe('s');
- expect(filtersProjects.searchFields).toEqual(['title', 'tags', 'description']);
-
- component.selectedTab.set(MyProjectsTab.Preprints);
- const filtersPreprints = component.createFilters({
- page: 2,
- size: 25,
- search: 's2',
- sortColumn: 'date',
- sortOrder: SortOrder.Desc,
- });
- expect(filtersPreprints.searchFields).toEqual(['title', 'tags']);
- });
-
- it('should fetch data for projects tab and stop loading', () => {
- jest.clearAllMocks();
- store.dispatch.mockReturnValue(of(undefined));
-
- component.fetchDataForCurrentTab({ page: 1, size: 10, search: 's', sortColumn: 'name', sortOrder: SortOrder.Asc });
-
- expect(store.dispatch).toHaveBeenCalledWith(expect.any(GetMyProjects));
+ it('should fetch data for projects tab', () => {
+ expect(component.selectedTab()).toBe(MyProjectsTab.Projects);
expect(component.isLoading()).toBe(false);
});
- it('should handle search and update query params', () => {
- jest.clearAllMocks();
- queryParamsSubject.next({ sortColumn: 'name', sortOrder: 'desc', size: '25' });
-
- component.handleSearch('query');
-
- expect(router.navigate).toHaveBeenCalledWith([], {
- relativeTo: TestBed.inject(ActivatedRoute),
- queryParams: { page: '1', search: 'query', tab: '1' },
- });
- });
-
it('should paginate and update query params', () => {
- jest.clearAllMocks();
- queryParamsSubject.next({ sortColumn: 'title', sortOrder: 'asc' });
-
component.onPageChange({ first: 30, rows: 15 } as any);
- expect(router.navigate).toHaveBeenCalledWith([], {
- relativeTo: TestBed.inject(ActivatedRoute),
+ expect(mockRouter.navigate).toHaveBeenCalledWith([], {
+ relativeTo: mockActivatedRoute,
queryParams: { page: '3', size: '15', tab: '1' },
});
});
it('should sort and update query params', () => {
- jest.clearAllMocks();
-
component.onSort({ field: 'updated', order: SortOrder.Desc } as any);
- expect(router.navigate).toHaveBeenCalledWith([], {
- relativeTo: TestBed.inject(ActivatedRoute),
+ expect(mockRouter.navigate).toHaveBeenCalledWith([], {
+ relativeTo: mockActivatedRoute,
queryParams: { sortColumn: 'updated', sortOrder: 'desc', tab: '1' },
});
});
it('should clear and reset on tab change', () => {
- jest.clearAllMocks();
- queryParamsSubject.next({ size: '50' });
-
- component.onTabChange(1);
+ component.onTabChange(MyProjectsTab.Registrations);
- expect(router.navigate).toHaveBeenCalledWith([], {
- relativeTo: TestBed.inject(ActivatedRoute),
- queryParams: { page: '1', tab: '1' },
+ expect(mockRouter.navigate).toHaveBeenCalledWith([], {
+ relativeTo: mockActivatedRoute,
+ queryParams: { page: '1', tab: '2' },
});
-
- expect(store.dispatch).toHaveBeenCalled();
});
- it('should navigate to project and set active project', () => {
+ it('should navigate to project', () => {
const project = { id: 'p1' } as any;
component.navigateToProject(project);
- expect(component.activeProject()).toEqual(project);
- expect(router.navigate).toHaveBeenCalledWith(['p1']);
- });
- it('should navigate to registry and set active project', () => {
- const reg = { id: 'r1' } as any;
- component.navigateToRegistry(reg);
- expect(component.activeProject()).toEqual(reg);
- expect(router.navigate).toHaveBeenCalledWith(['r1']);
+ expect(component.activeProject()).toEqual(project);
+ expect(mockRouter.navigate).toHaveBeenCalledWith(['p1']);
});
});
diff --git a/src/app/features/my-projects/my-projects.component.ts b/src/app/features/my-projects/my-projects.component.ts
index 403912687..b9381dc6a 100644
--- a/src/app/features/my-projects/my-projects.component.ts
+++ b/src/app/features/my-projects/my-projects.component.ts
@@ -23,7 +23,12 @@ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
import { FormControl, FormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
-import { MyProjectsTableComponent, SelectComponent, SubHeaderComponent } from '@osf/shared/components';
+import {
+ MyProjectsTableComponent,
+ SearchInputComponent,
+ SelectComponent,
+ SubHeaderComponent,
+} from '@osf/shared/components';
import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants';
import { ResourceType, SortOrder } from '@osf/shared/enums';
import { IS_MEDIUM } from '@osf/shared/helpers';
@@ -40,6 +45,7 @@ import {
} from '@osf/shared/stores';
import { CustomDialogService, ProjectRedirectDialogService } from '@shared/services';
+import { PROJECT_FILTER_OPTIONS } from './constants/project-filter-options.const';
import { MyProjectsQueryService } from './services/my-projects-query.service';
import { MyProjectsTableParamsService } from './services/my-projects-table-params.service';
import { CreateProjectDialogComponent } from './components';
@@ -49,16 +55,17 @@ import { MyProjectsTab } from './enums';
@Component({
selector: 'osf-my-projects',
imports: [
- SubHeaderComponent,
FormsModule,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
+ SubHeaderComponent,
MyProjectsTableComponent,
- TranslatePipe,
+ SearchInputComponent,
SelectComponent,
+ TranslatePipe,
],
templateUrl: './my-projects.component.html',
styleUrl: './my-projects.component.scss',
@@ -78,6 +85,8 @@ export class MyProjectsComponent implements OnInit {
readonly isMedium = toSignal(inject(IS_MEDIUM));
readonly tabOptions = MY_PROJECTS_TABS;
readonly tabOption = MyProjectsTab;
+ readonly projectFilterOption = PROJECT_FILTER_OPTIONS;
+ readonly selectedProjectFilterOption = signal(PROJECT_FILTER_OPTIONS[0].value);
readonly searchControl = new FormControl('');
@@ -137,10 +146,20 @@ export class MyProjectsComponent implements OnInit {
onTabChange(tabIndex: number): void {
this.actions.clearMyProjects();
this.selectedTab.set(tabIndex);
+ this.selectedProjectFilterOption.set(PROJECT_FILTER_OPTIONS[0].value);
const current = this.queryService.getRawParams();
this.queryService.handleTabSwitch(current, this.selectedTab());
}
+ onProjectFilterChange(): void {
+ const params = this.queryParams();
+
+ if (params) {
+ const queryParams = this.queryService.toQueryModel(params);
+ this.fetchDataForCurrentTab(queryParams);
+ }
+ }
+
createProject(): void {
this.customDialogService
.open(CreateProjectDialogComponent, {
@@ -283,7 +302,7 @@ export class MyProjectsComponent implements OnInit {
let action$;
switch (this.selectedTab()) {
case MyProjectsTab.Projects:
- action$ = this.actions.getMyProjects(pageNumber, pageSize, filters);
+ action$ = this.actions.getMyProjects(pageNumber, pageSize, filters, this.selectedProjectFilterOption());
break;
case MyProjectsTab.Registrations:
action$ = this.actions.getMyRegistrations(pageNumber, pageSize, filters);
diff --git a/src/app/shared/components/my-projects-table/my-projects-table.component.html b/src/app/shared/components/my-projects-table/my-projects-table.component.html
index 7ea9b8def..d56a1cb68 100644
--- a/src/app/shared/components/my-projects-table/my-projects-table.component.html
+++ b/src/app/shared/components/my-projects-table/my-projects-table.component.html
@@ -1,70 +1,66 @@
-
-
-
-
-
-
-
- {{ 'myProjects.table.columns.title' | translate }}
-
- |
- {{ 'myProjects.table.columns.contributors' | translate }} |
-
- {{ 'myProjects.table.columns.modified' | translate }}
-
- |
+
+
+
+
+ {{ 'myProjects.table.columns.title' | translate }}
+
+ |
+ {{ 'myProjects.table.columns.contributors' | translate }} |
+
+ {{ 'myProjects.table.columns.modified' | translate }}
+
+ |
+
+
+
+ @if (item?.id) {
+
+
+
+
+ {{ item.title }}
+
+ |
+
+ @for (contributor of item.contributors; track contributor) {
+ {{ contributor.fullName }}{{ $last ? '' : ', ' }}
+ }
+ |
+ {{ item.dateModified | date: 'MMM d, y, h:mm a' }} |
-
-
- @if (item?.id) {
-
-
-
-
- {{ item.title }}
-
- |
-
- @for (contributor of item.contributors; track contributor) {
- {{ contributor.fullName }}{{ $last ? '' : ', ' }}
- }
- |
- {{ item.dateModified | date: 'MMM d, y, h:mm a' }} |
-
- } @else {
-
-
-
- |
-
- }
-
-
-
-
- {{ 'common.search.noResultsFound' | translate }} |
+ } @else {
+
+
+
+ |
-
-
-
+ }
+
+
+
+
+ {{ 'common.search.noResultsFound' | translate }} |
+
+
+
diff --git a/src/app/shared/components/my-projects-table/my-projects-table.component.spec.ts b/src/app/shared/components/my-projects-table/my-projects-table.component.spec.ts
index e698feb51..0843ffe6a 100644
--- a/src/app/shared/components/my-projects-table/my-projects-table.component.spec.ts
+++ b/src/app/shared/components/my-projects-table/my-projects-table.component.spec.ts
@@ -1,13 +1,13 @@
import { MockComponent } from 'ng-mocks';
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { FormControl } from '@angular/forms';
import { SortOrder } from '@osf/shared/enums/sort-order.enum';
import { TableParameters } from '@osf/shared/models/table-parameters.model';
-import { SearchInputComponent } from '@shared/components';
import { MyResourcesItem } from '@shared/models/my-resources/my-resources.models';
+import { IconComponent } from '../icon/icon.component';
+
import { MyProjectsTableComponent } from './my-projects-table.component';
import { MOCK_CONTRIBUTOR, TranslateServiceMock } from '@testing/mocks';
@@ -39,11 +39,9 @@ describe('MyProjectsTableComponent', () => {
},
];
- const mockSearchControl = new FormControl('');
-
beforeEach(async () => {
await TestBed.configureTestingModule({
- imports: [MyProjectsTableComponent, MockComponent(SearchInputComponent)],
+ imports: [MyProjectsTableComponent, MockComponent(IconComponent)],
providers: [TranslateServiceMock],
}).compileComponents();
@@ -52,11 +50,9 @@ describe('MyProjectsTableComponent', () => {
fixture.componentRef.setInput('items', mockItems);
fixture.componentRef.setInput('tableParams', mockTableParams);
- fixture.componentRef.setInput('searchControl', mockSearchControl);
fixture.componentRef.setInput('sortColumn', 'title');
fixture.componentRef.setInput('sortOrder', SortOrder.Asc);
fixture.componentRef.setInput('isLoading', false);
- fixture.componentRef.setInput('searchPlaceholder', 'myProjects.table.searchPlaceholder');
fixture.detectChanges();
});
@@ -73,10 +69,6 @@ describe('MyProjectsTableComponent', () => {
expect(component.tableParams()).toEqual(mockTableParams);
});
- it('should set searchControl input', () => {
- expect(component.searchControl()).toBe(mockSearchControl);
- });
-
it('should set sortColumn input', () => {
expect(component.sortColumn()).toBe('title');
});
@@ -89,17 +81,6 @@ describe('MyProjectsTableComponent', () => {
expect(component.isLoading()).toBe(false);
});
- it('should set searchPlaceholder input', () => {
- expect(component.searchPlaceholder()).toBe('myProjects.table.searchPlaceholder');
- });
-
- it('should render search input when not loading', () => {
- const compiled = fixture.nativeElement;
- const searchInput = compiled.querySelector('osf-search-input');
-
- expect(searchInput).toBeTruthy();
- });
-
it('should render table when not loading', () => {
const compiled = fixture.nativeElement;
const table = compiled.querySelector('p-table');
diff --git a/src/app/shared/components/my-projects-table/my-projects-table.component.ts b/src/app/shared/components/my-projects-table/my-projects-table.component.ts
index 2413698b8..4bfaab38e 100644
--- a/src/app/shared/components/my-projects-table/my-projects-table.component.ts
+++ b/src/app/shared/components/my-projects-table/my-projects-table.component.ts
@@ -6,17 +6,15 @@ import { TableModule, TablePageEvent } from 'primeng/table';
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';
-import { FormControl } from '@angular/forms';
import { SortOrder } from '@osf/shared/enums';
import { MyResourcesItem, TableParameters } from '@osf/shared/models';
import { IconComponent } from '../icon/icon.component';
-import { SearchInputComponent } from '../search-input/search-input.component';
@Component({
selector: 'osf-my-projects-table',
- imports: [CommonModule, TableModule, SearchInputComponent, IconComponent, Skeleton, TranslatePipe],
+ imports: [CommonModule, TableModule, IconComponent, Skeleton, TranslatePipe],
templateUrl: './my-projects-table.component.html',
styleUrl: './my-projects-table.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -24,11 +22,9 @@ import { SearchInputComponent } from '../search-input/search-input.component';
export class MyProjectsTableComponent {
items = input([]);
tableParams = input.required();
- searchControl = input(new FormControl(''));
sortColumn = input(undefined);
sortOrder = input(SortOrder.Asc);
isLoading = input(false);
- searchPlaceholder = input('myProjects.table.searchPlaceholder');
pageChange = output();
sort = output();
diff --git a/src/app/shared/enums/resource-search-mode.enum.ts b/src/app/shared/enums/resource-search-mode.enum.ts
index 74508a4f0..9d758a251 100644
--- a/src/app/shared/enums/resource-search-mode.enum.ts
+++ b/src/app/shared/enums/resource-search-mode.enum.ts
@@ -1,4 +1,6 @@
export enum ResourceSearchMode {
- User = 'user',
- All = 'all',
+ All = 1,
+ Root,
+ Component,
+ User,
}
diff --git a/src/app/shared/services/my-resources.service.ts b/src/app/shared/services/my-resources.service.ts
index 6599bc8b8..60c9d6723 100644
--- a/src/app/shared/services/my-resources.service.ts
+++ b/src/app/shared/services/my-resources.service.ts
@@ -99,6 +99,14 @@ export class MyResourcesService {
url = endpoint.startsWith('collections/') ? `${this.apiUrl}/${endpoint}` : `${this.apiUrl}/users/me/${endpoint}`;
}
+ if (searchMode === ResourceSearchMode.Component) {
+ params['filter[parent][ne]'] = null;
+ }
+
+ if (searchMode === ResourceSearchMode.Root) {
+ params['filter[parent]'] = null;
+ }
+
return this.jsonApiService.get(url, params).pipe(
map((response: MyResourcesResponseJsonApi) => ({
data: response.data.map((item: MyResourcesItemGetResponseJsonApi) => MyResourcesMapper.fromResponse(item)),
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 8aa227335..380a419ad 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -422,6 +422,11 @@
"myPreprints": "My Preprints",
"bookmarks": "Bookmarks"
},
+ "tabOptions": {
+ "all": "All",
+ "root": "Projects",
+ "component": "Components"
+ },
"bookmarks": {
"emptyState": "You don't have any bookmarks. Click the bookmark icon on projects or registrations to add them here."
},
From 1b7761523eff315d084b4e8474f7cb1e67cb785e Mon Sep 17 00:00:00 2001
From: nsemets
Date: Thu, 16 Oct 2025 10:59:34 +0300
Subject: [PATCH 2/2] fix(my-projects): updated styles
---
src/app/features/my-projects/my-projects.component.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/features/my-projects/my-projects.component.html b/src/app/features/my-projects/my-projects.component.html
index 725a1ac05..ac66040f3 100644
--- a/src/app/features/my-projects/my-projects.component.html
+++ b/src/app/features/my-projects/my-projects.component.html
@@ -28,7 +28,7 @@
}
-