From 89d13844bcc22d6aef950f4c2f6facb4bd0b4f0f Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 23 Oct 2025 11:04:55 +0300 Subject: [PATCH 1/5] fix(contributors): updated contributors table with see more --- .../core/constants/ngxs-states.constant.ts | 3 +- .../collections/collections.routes.ts | 11 +-- .../add-to-collection.component.html | 1 + .../project-contributors-step.component.html | 2 + .../project-contributors-step.component.ts | 14 +++- .../contributors/contributors.component.html | 3 +- .../contributors/contributors.component.ts | 27 ++++--- .../contributors-dialog.component.html | 3 +- .../contributors-dialog.component.ts | 18 ++--- .../preprints-contributors.component.html | 3 +- .../preprints-contributors.component.ts | 18 ++--- .../features/preprints/preprints.routes.ts | 11 +-- src/app/features/project/project.routes.ts | 5 +- .../registries-contributors.component.html | 3 +- .../registries-contributors.component.ts | 27 ++++--- src/app/features/registry/registry.routes.ts | 12 +--- .../contributors-table.component.html | 26 ++++--- .../contributors-table.component.ts | 15 ++-- .../truncated-text.component.scss | 1 - .../mappers/collections/collections.mapper.ts | 14 ++-- .../contributors/contributors.actions.ts | 29 ++++++++ .../stores/contributors/contributors.model.ts | 23 ++++-- .../contributors/contributors.selectors.ts | 38 +++++++++- .../stores/contributors/contributors.state.ts | 72 ++++++++++++++++++- src/assets/i18n/en.json | 3 +- src/styles/overrides/table.scss | 5 +- 26 files changed, 282 insertions(+), 105 deletions(-) diff --git a/src/app/core/constants/ngxs-states.constant.ts b/src/app/core/constants/ngxs-states.constant.ts index 409a3d258..b41f1c6a5 100644 --- a/src/app/core/constants/ngxs-states.constant.ts +++ b/src/app/core/constants/ngxs-states.constant.ts @@ -6,7 +6,7 @@ import { FilesState } from '@osf/features/files/store'; import { MetadataState } from '@osf/features/metadata/store'; import { ProjectOverviewState } from '@osf/features/project/overview/store'; import { RegistrationsState } from '@osf/features/project/registrations/store'; -import { AddonsState, CurrentResourceState, WikiState } from '@osf/shared/stores'; +import { AddonsState, ContributorsState, CurrentResourceState, WikiState } from '@osf/shared/stores'; import { BannersState } from '@osf/shared/stores/banners'; import { GlobalSearchState } from '@shared/stores/global-search'; import { InstitutionsState } from '@shared/stores/institutions'; @@ -36,4 +36,5 @@ export const STATES = [ GlobalSearchState, BannersState, LinkedProjectsState, + ContributorsState, ]; diff --git a/src/app/features/collections/collections.routes.ts b/src/app/features/collections/collections.routes.ts index cb95bfe26..851ebacb3 100644 --- a/src/app/features/collections/collections.routes.ts +++ b/src/app/features/collections/collections.routes.ts @@ -6,14 +6,7 @@ import { authGuard } from '@osf/core/guards'; import { AddToCollectionState } from '@osf/features/collections/store/add-to-collection'; import { CollectionsModerationState } from '@osf/features/moderation/store/collections-moderation'; import { ConfirmLeavingGuard } from '@shared/guards'; -import { - BookmarksState, - CitationsState, - ContributorsState, - NodeLinksState, - ProjectsState, - SubjectsState, -} from '@shared/stores'; +import { BookmarksState, CitationsState, NodeLinksState, ProjectsState, SubjectsState } from '@shared/stores'; import { CollectionsState } from '@shared/stores/collections'; export const collectionsRoutes: Routes = [ @@ -47,7 +40,7 @@ export const collectionsRoutes: Routes = [ import('@osf/features/collections/components/add-to-collection/add-to-collection.component').then( (mod) => mod.AddToCollectionComponent ), - providers: [provideStates([ProjectsState, CollectionsState, AddToCollectionState, ContributorsState])], + providers: [provideStates([ProjectsState, CollectionsState, AddToCollectionState])], canActivate: [authGuard], canDeactivate: [ConfirmLeavingGuard], }, diff --git a/src/app/features/collections/components/add-to-collection/add-to-collection.component.html b/src/app/features/collections/components/add-to-collection/add-to-collection.component.html index 204620fa5..e60b9c227 100644 --- a/src/app/features/collections/components/add-to-collection/add-to-collection.component.html +++ b/src/app/features/collections/components/add-to-collection/add-to-collection.component.html @@ -32,6 +32,7 @@

{{ collectionProvider()? /> {{ 'collections.addToCollection.projectContributors' | translate }}

[(contributors)]="projectContributors" [tableParams]="tableParams()" [isLoading]="isContributorsLoading()" + [isLoadingMore]="isLoadingMore()" (remove)="handleRemoveContributor($event)" + (loadMore)="loadMoreContributors()" >
diff --git a/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts b/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts index f6518e2d4..54a19165d 100644 --- a/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts +++ b/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts @@ -40,6 +40,7 @@ import { BulkUpdateContributors, ContributorsSelectors, DeleteContributor, + LoadMoreContributors, ProjectsSelectors, } from '@osf/shared/stores'; @@ -61,20 +62,26 @@ export class ProjectContributorsStepComponent { readonly contributorsTotalCount = select(ContributorsSelectors.getContributorsTotalCount); readonly selectedProject = select(ProjectsSelectors.getSelectedProject); readonly currentUser = select(UserSelectors.getCurrentUser); + isLoadingMore = select(ContributorsSelectors.isContributorsLoadingMore); private initialContributors = select(ContributorsSelectors.getContributors); readonly projectContributors = signal([]); + pageSize = select(ContributorsSelectors.getContributorsPageSize); readonly tableParams = computed(() => ({ ...DEFAULT_TABLE_PARAMS, totalRecords: this.contributorsTotalCount(), - paginator: this.contributorsTotalCount() > DEFAULT_TABLE_PARAMS.rows, + paginator: false, + scrollable: true, + firstRowIndex: 0, + rows: this.pageSize(), })); stepperActiveValue = input.required(); targetStepValue = input.required(); isDisabled = input.required(); isProjectMetadataSaved = input(false); + projectId = input(); stepChange = output(); contributorsSaved = output(); @@ -84,6 +91,7 @@ export class ProjectContributorsStepComponent { bulkAddContributors: BulkAddContributors, bulkUpdateContributors: BulkUpdateContributors, deleteContributor: DeleteContributor, + loadMoreContributors: LoadMoreContributors, }); constructor() { @@ -150,6 +158,10 @@ export class ProjectContributorsStepComponent { this.stepChange.emit(this.targetStepValue()); } + loadMoreContributors(): void { + this.actions.loadMoreContributors(this.projectId(), ResourceType.Project); + } + private openAddContributorDialog() { const addedContributorIds = this.projectContributors().map((x) => x.userId); diff --git a/src/app/features/contributors/contributors.component.html b/src/app/features/contributors/contributors.component.html index dd3d74d45..3a5785bee 100644 --- a/src/app/features/contributors/contributors.component.html +++ b/src/app/features/contributors/contributors.component.html @@ -63,6 +63,7 @@

{{ 'navigation.contributors' | translate } class="w-full" [(contributors)]="contributors" [isLoading]="isContributorsLoading()" + [isLoadingMore]="isLoadingMore()" [tableParams]="tableParams()" [hasAdminAccess]="hasAdminAccess()" [currentUserId]="currentUser()?.id" @@ -70,7 +71,7 @@

{{ 'navigation.contributors' | translate } [showInfo]="true" [resourceType]="resourceType()" (remove)="removeContributor($event)" - (pageChanged)="pageChanged($event)" + (loadMore)="loadMoreContributors()" > @if (hasChanges) { diff --git a/src/app/features/contributors/contributors.component.ts b/src/app/features/contributors/contributors.component.ts index 25754e14a..93fd037e7 100644 --- a/src/app/features/contributors/contributors.component.ts +++ b/src/app/features/contributors/contributors.component.ts @@ -4,7 +4,7 @@ import { TranslatePipe } from '@ngx-translate/core'; import { Button } from 'primeng/button'; import { Select } from 'primeng/select'; -import { TableModule, TablePageEvent } from 'primeng/table'; +import { TableModule } from 'primeng/table'; import { debounceTime, distinctUntilChanged, filter, map, of, switchMap } from 'rxjs'; @@ -15,6 +15,7 @@ import { DestroyRef, effect, inject, + OnDestroy, OnInit, signal, } from '@angular/core'; @@ -60,7 +61,9 @@ import { GetRequestAccessContributors, GetResourceDetails, GetResourceWithChildren, + LoadMoreContributors, RejectRequestAccess, + ResetContributorsState, UpdateBibliographyFilter, UpdateContributorsSearchValue, UpdatePermissionFilter, @@ -87,7 +90,7 @@ import { ResourceInfoModel } from './models'; styleUrl: './contributors.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ContributorsComponent implements OnInit { +export class ContributorsComponent implements OnInit, OnDestroy { searchControl = new FormControl(''); readonly destroyRef = inject(DestroyRef); @@ -123,14 +126,15 @@ export class ContributorsComponent implements OnInit { readonly hasAdminAccess = select(CurrentResourceSelectors.hasResourceAdminAccess); readonly resourceAccessRequestEnabled = select(CurrentResourceSelectors.resourceAccessRequestEnabled); readonly currentUser = select(UserSelectors.getCurrentUser); - page = select(ContributorsSelectors.getContributorsPageNumber); pageSize = select(ContributorsSelectors.getContributorsPageSize); + isLoadingMore = select(ContributorsSelectors.isContributorsLoadingMore); readonly tableParams = computed(() => ({ ...DEFAULT_TABLE_PARAMS, totalRecords: this.contributorsTotalCount(), - paginator: this.contributorsTotalCount() > DEFAULT_TABLE_PARAMS.rows, - firstRowIndex: (this.page() - 1) * this.pageSize(), + paginator: false, + scrollable: true, + firstRowIndex: 0, rows: this.pageSize(), })); @@ -153,6 +157,7 @@ export class ContributorsComponent implements OnInit { getViewOnlyLinks: FetchViewOnlyLinks, getResourceDetails: GetResourceDetails, getContributors: GetAllContributors, + loadMoreContributors: LoadMoreContributors, updateSearchValue: UpdateContributorsSearchValue, updatePermissionFilter: UpdatePermissionFilter, updateBibliographyFilter: UpdateBibliographyFilter, @@ -166,6 +171,7 @@ export class ContributorsComponent implements OnInit { acceptRequestAccess: AcceptRequestAccess, rejectRequestAccess: RejectRequestAccess, getResourceWithChildren: GetResourceWithChildren, + resetContributorsState: ResetContributorsState, }); get hasChanges(): boolean { @@ -187,6 +193,10 @@ export class ContributorsComponent implements OnInit { this.setSearchSubscription(); } + ngOnDestroy(): void { + this.actions.resetContributorsState(); + } + private setSearchSubscription() { this.searchControl.valueChanges .pipe(debounceTime(500), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef)) @@ -383,11 +393,8 @@ export class ContributorsComponent implements OnInit { }); } - pageChanged(event: TablePageEvent) { - const page = Math.floor(event.first / event.rows) + 1; - const pageSize = event.rows; - - this.actions.getContributors(this.resourceId(), this.resourceType(), page, pageSize); + loadMoreContributors(): void { + this.actions.loadMoreContributors(this.resourceId(), this.resourceType()); } createViewLink() { diff --git a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.html b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.html index b6ee30cba..4ff339220 100644 --- a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.html +++ b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.html @@ -19,12 +19,13 @@ [(contributors)]="contributors" [tableParams]="tableParams()" [isLoading]="isLoading()" + [isLoadingMore]="isLoadingMore()" [showEmployment]="false" [showEducation]="false" [hasAdminAccess]="hasAdminAccess()" [currentUserId]="currentUser()?.id" (remove)="removeContributor($event)" - (pageChanged)="pageChanged($event)" + (loadMore)="loadMoreContributors()" > @if (hasChanges) { diff --git a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts index dd5693767..6d02a1e58 100644 --- a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts +++ b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts @@ -4,7 +4,6 @@ import { TranslatePipe } from '@ngx-translate/core'; import { Button } from 'primeng/button'; import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog'; -import { TablePageEvent } from 'primeng/table'; import { filter } from 'rxjs'; @@ -41,6 +40,7 @@ import { ContributorsSelectors, DeleteContributor, GetAllContributors, + LoadMoreContributors, UpdateBibliographyFilter, UpdateContributorsSearchValue, UpdatePermissionFilter, @@ -70,7 +70,7 @@ export class ContributorsDialogComponent implements OnInit { contributorsTotalCount = select(ContributorsSelectors.getContributorsTotalCount); hasAdminAccess = select(MetadataSelectors.hasAdminAccess); contributors = signal([]); - page = select(ContributorsSelectors.getContributorsPageNumber); + isLoadingMore = select(ContributorsSelectors.isContributorsLoadingMore); pageSize = select(ContributorsSelectors.getContributorsPageSize); currentUser = select(UserSelectors.getCurrentUser); @@ -78,8 +78,9 @@ export class ContributorsDialogComponent implements OnInit { readonly tableParams = computed(() => ({ ...DEFAULT_TABLE_PARAMS, totalRecords: this.contributorsTotalCount(), - paginator: this.contributorsTotalCount() > DEFAULT_TABLE_PARAMS.rows, - firstRowIndex: (this.page() - 1) * this.pageSize(), + paginator: false, + scrollable: true, + firstRowIndex: 0, rows: this.pageSize(), })); @@ -92,6 +93,7 @@ export class ContributorsDialogComponent implements OnInit { addContributor: AddContributor, bulkAddContributors: BulkAddContributors, bulkUpdateContributors: BulkUpdateContributors, + loadMoreContributors: LoadMoreContributors, }); private readonly resourceType: ResourceType; @@ -117,6 +119,7 @@ export class ContributorsDialogComponent implements OnInit { } ngOnInit(): void { + this.actions.getContributors(this.resourceId, this.resourceType); this.setSearchSubscription(); } @@ -206,11 +209,8 @@ export class ContributorsDialogComponent implements OnInit { }); } - pageChanged(event: TablePageEvent) { - const page = Math.floor(event.first / event.rows) + 1; - const pageSize = event.rows; - - this.actions.getContributors(this.resourceId, this.resourceType, page, pageSize); + loadMoreContributors(): void { + this.actions.loadMoreContributors(this.resourceId, this.resourceType); } cancel() { diff --git a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.html b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.html index 87e081260..c5dab158f 100644 --- a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.html +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.html @@ -12,8 +12,9 @@

{{ 'project.overview.metadata.contributors' | translate }}

[(contributors)]="contributors" [tableParams]="tableParams()" [isLoading]="isContributorsLoading()" + [isLoadingMore]="isLoadingMore()" (remove)="removeContributor($event)" - (pageChanged)="pageChanged($event)" + (loadMore)="loadMoreContributors()" />
@if (hasChanges) { diff --git a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts index b2c08a55f..24e11678c 100644 --- a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts @@ -5,7 +5,7 @@ import { TranslatePipe } from '@ngx-translate/core'; import { Button } from 'primeng/button'; import { Card } from 'primeng/card'; import { Message } from 'primeng/message'; -import { TableModule, TablePageEvent } from 'primeng/table'; +import { TableModule } from 'primeng/table'; import { filter } from 'rxjs'; @@ -41,6 +41,7 @@ import { ContributorsSelectors, DeleteContributor, GetAllContributors, + LoadMoreContributors, } from '@osf/shared/stores'; @Component({ @@ -63,14 +64,15 @@ export class PreprintsContributorsComponent implements OnInit { contributors = signal([]); contributorsTotalCount = select(ContributorsSelectors.getContributorsTotalCount); isContributorsLoading = select(ContributorsSelectors.isContributorsLoading); - page = select(ContributorsSelectors.getContributorsPageNumber); + isLoadingMore = select(ContributorsSelectors.isContributorsLoadingMore); pageSize = select(ContributorsSelectors.getContributorsPageSize); readonly tableParams = computed(() => ({ ...DEFAULT_TABLE_PARAMS, totalRecords: this.contributorsTotalCount(), - paginator: this.contributorsTotalCount() > DEFAULT_TABLE_PARAMS.rows, - firstRowIndex: (this.page() - 1) * this.pageSize(), + paginator: false, + scrollable: true, + firstRowIndex: 0, rows: this.pageSize(), })); @@ -80,6 +82,7 @@ export class PreprintsContributorsComponent implements OnInit { bulkUpdateContributors: BulkUpdateContributors, bulkAddContributors: BulkAddContributors, addContributor: AddContributor, + loadMoreContributors: LoadMoreContributors, }); get hasChanges(): boolean { @@ -182,10 +185,7 @@ export class PreprintsContributorsComponent implements OnInit { }); } - pageChanged(event: TablePageEvent) { - const page = Math.floor(event.first / event.rows) + 1; - const pageSize = event.rows; - - this.actions.getContributors(this.preprintId(), ResourceType.Preprint, page, pageSize); + loadMoreContributors(): void { + this.actions.loadMoreContributors(this.preprintId(), ResourceType.Preprint); } } diff --git a/src/app/features/preprints/preprints.routes.ts b/src/app/features/preprints/preprints.routes.ts index 93a9f8654..2f3ba9325 100644 --- a/src/app/features/preprints/preprints.routes.ts +++ b/src/app/features/preprints/preprints.routes.ts @@ -9,7 +9,7 @@ import { PreprintState } from '@osf/features/preprints/store/preprint'; import { PreprintProvidersState } from '@osf/features/preprints/store/preprint-providers'; import { PreprintStepperState } from '@osf/features/preprints/store/preprint-stepper'; import { ConfirmLeavingGuard } from '@shared/guards'; -import { CitationsState, ContributorsState, ProjectsState, SubjectsState } from '@shared/stores'; +import { CitationsState, ProjectsState, SubjectsState } from '@shared/stores'; import { PreprintModerationState } from '../moderation/store/preprint-moderation'; @@ -18,14 +18,7 @@ export const preprintsRoutes: Routes = [ path: '', component: PreprintsComponent, providers: [ - provideStates([ - PreprintProvidersState, - PreprintStepperState, - ContributorsState, - SubjectsState, - PreprintState, - CitationsState, - ]), + provideStates([PreprintProvidersState, PreprintStepperState, SubjectsState, PreprintState, CitationsState]), ], children: [ { diff --git a/src/app/features/project/project.routes.ts b/src/app/features/project/project.routes.ts index 5d7d3bae8..55951dc01 100644 --- a/src/app/features/project/project.routes.ts +++ b/src/app/features/project/project.routes.ts @@ -8,7 +8,6 @@ import { LicensesService } from '@osf/shared/services'; import { CitationsState, CollectionsState, - ContributorsState, DuplicatesState, NodeLinksState, SubjectsState, @@ -53,7 +52,7 @@ export const projectRoutes: Routes = [ { path: 'metadata', loadChildren: () => import('@osf/features/metadata/metadata.routes').then((mod) => mod.metadataRoutes), - providers: [provideStates([SubjectsState, ContributorsState])], + providers: [provideStates([SubjectsState])], data: { resourceType: ResourceType.Project }, canActivate: [viewOnlyGuard], }, @@ -87,7 +86,7 @@ export const projectRoutes: Routes = [ canActivate: [viewOnlyGuard], loadComponent: () => import('../contributors/contributors.component').then((mod) => mod.ContributorsComponent), data: { resourceType: ResourceType.Project }, - providers: [provideStates([ContributorsState, ViewOnlyLinkState])], + providers: [provideStates([ViewOnlyLinkState])], }, { path: 'analytics', diff --git a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.html b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.html index 7726dae69..70164d25d 100644 --- a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.html +++ b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.html @@ -6,8 +6,9 @@

{{ 'project.overview.metadata.contributors' | translate }}

[(contributors)]="contributors" [tableParams]="tableParams()" [isLoading]="isContributorsLoading()" + [isLoadingMore]="isLoadingMore()" (remove)="removeContributor($event)" - (pageChanged)="pageChanged($event)" + (loadMore)="loadMoreContributors()" />
diff --git a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts index bf07f0974..8b720bd1e 100644 --- a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts +++ b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts @@ -4,7 +4,7 @@ import { TranslatePipe } from '@ngx-translate/core'; import { Button } from 'primeng/button'; import { Card } from 'primeng/card'; -import { TableModule, TablePageEvent } from 'primeng/table'; +import { TableModule } from 'primeng/table'; import { filter, map, of } from 'rxjs'; @@ -16,6 +16,7 @@ import { effect, inject, input, + OnDestroy, OnInit, signal, } from '@angular/core'; @@ -40,6 +41,8 @@ import { ContributorsSelectors, DeleteContributor, GetAllContributors, + LoadMoreContributors, + ResetContributorsState, } from '@osf/shared/stores'; @Component({ @@ -49,7 +52,7 @@ import { styleUrl: './registries-contributors.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class RegistriesContributorsComponent implements OnInit { +export class RegistriesContributorsComponent implements OnInit, OnDestroy { control = input.required(); readonly destroyRef = inject(DestroyRef); @@ -65,14 +68,15 @@ export class RegistriesContributorsComponent implements OnInit { isContributorsLoading = select(ContributorsSelectors.isContributorsLoading); contributorsTotalCount = select(ContributorsSelectors.getContributorsTotalCount); - page = select(ContributorsSelectors.getContributorsPageNumber); + isLoadingMore = select(ContributorsSelectors.isContributorsLoadingMore); pageSize = select(ContributorsSelectors.getContributorsPageSize); readonly tableParams = computed(() => ({ ...DEFAULT_TABLE_PARAMS, totalRecords: this.contributorsTotalCount(), - paginator: this.contributorsTotalCount() > DEFAULT_TABLE_PARAMS.rows, - firstRowIndex: (this.page() - 1) * this.pageSize(), + paginator: false, + scrollable: true, + firstRowIndex: 0, rows: this.pageSize(), })); @@ -82,6 +86,8 @@ export class RegistriesContributorsComponent implements OnInit { bulkUpdateContributors: BulkUpdateContributors, bulkAddContributors: BulkAddContributors, addContributor: AddContributor, + loadMoreContributors: LoadMoreContributors, + resetContributorsState: ResetContributorsState, }); get hasChanges(): boolean { @@ -98,6 +104,10 @@ export class RegistriesContributorsComponent implements OnInit { this.actions.getContributors(this.draftId(), ResourceType.DraftRegistration); } + ngOnDestroy(): void { + this.actions.resetContributorsState(); + } + onFocusOut() { if (this.control()) { this.control().markAsTouched(); @@ -192,10 +202,7 @@ export class RegistriesContributorsComponent implements OnInit { }); } - pageChanged(event: TablePageEvent) { - const page = Math.floor(event.first / event.rows) + 1; - const pageSize = event.rows; - - this.actions.getContributors(this.draftId(), ResourceType.DraftRegistration, page, pageSize); + loadMoreContributors(): void { + this.actions.loadMoreContributors(this.draftId(), ResourceType.DraftRegistration); } } diff --git a/src/app/features/registry/registry.routes.ts b/src/app/features/registry/registry.routes.ts index f26006bbe..e4161724b 100644 --- a/src/app/features/registry/registry.routes.ts +++ b/src/app/features/registry/registry.routes.ts @@ -5,13 +5,7 @@ import { Routes } from '@angular/router'; import { viewOnlyGuard } from '@osf/core/guards'; import { ResourceType } from '@osf/shared/enums'; import { LicensesService } from '@osf/shared/services'; -import { - CitationsState, - ContributorsState, - DuplicatesState, - SubjectsState, - ViewOnlyLinkState, -} from '@osf/shared/stores'; +import { CitationsState, DuplicatesState, SubjectsState, ViewOnlyLinkState } from '@osf/shared/stores'; import { ActivityLogsState } from '@shared/stores/activity-logs'; import { AnalyticsState } from '../analytics/store'; @@ -52,7 +46,7 @@ export const registryRoutes: Routes = [ { path: 'metadata', loadChildren: () => import('@osf/features/metadata/metadata.routes').then((mod) => mod.metadataRoutes), - providers: [provideStates([SubjectsState, ContributorsState])], + providers: [provideStates([SubjectsState])], data: { resourceType: ResourceType.Registration }, canActivate: [viewOnlyGuard], }, @@ -68,7 +62,7 @@ export const registryRoutes: Routes = [ canActivate: [viewOnlyGuard], loadComponent: () => import('../contributors/contributors.component').then((mod) => mod.ContributorsComponent), data: { resourceType: ResourceType.Registration }, - providers: [provideStates([ContributorsState, ViewOnlyLinkState])], + providers: [provideStates([ViewOnlyLinkState])], }, { path: 'analytics', diff --git a/src/app/shared/components/contributors/contributors-table/contributors-table.component.html b/src/app/shared/components/contributors/contributors-table/contributors-table.component.html index 99e579a57..9d8f37d3f 100644 --- a/src/app/shared/components/contributors/contributors-table/contributors-table.component.html +++ b/src/app/shared/components/contributors/contributors-table/contributors-table.component.html @@ -1,17 +1,9 @@ @@ -182,6 +174,22 @@ } + + @if (showLoadMore() && index === contributors().length - 1) { + + +
+ +
+ + + }
diff --git a/src/app/shared/components/contributors/contributors-table/contributors-table.component.ts b/src/app/shared/components/contributors/contributors-table/contributors-table.component.ts index 467b1b31a..d9776cbbb 100644 --- a/src/app/shared/components/contributors/contributors-table/contributors-table.component.ts +++ b/src/app/shared/components/contributors/contributors-table/contributors-table.component.ts @@ -3,7 +3,7 @@ import { TranslatePipe } from '@ngx-translate/core'; import { Button } from 'primeng/button'; import { Checkbox } from 'primeng/checkbox'; import { Skeleton } from 'primeng/skeleton'; -import { TableModule, TablePageEvent } from 'primeng/table'; +import { TableModule } from 'primeng/table'; import { Tooltip } from 'primeng/tooltip'; import { ChangeDetectionStrategy, Component, computed, inject, input, model, output } from '@angular/core'; @@ -41,6 +41,7 @@ import { InfoIconComponent } from '../../info-icon/info-icon.component'; export class ContributorsTableComponent { contributors = model([]); isLoading = input(false); + isLoadingMore = input(false); tableParams = input.required(); showCurator = input(false); showEducation = input(true); @@ -52,7 +53,7 @@ export class ContributorsTableComponent { hasAdminAccess = input(true); remove = output(); - pageChanged = output(); + loadMore = output(); customDialogService = inject(CustomDialogService); @@ -65,6 +66,12 @@ export class ContributorsTableComponent { deactivatedContributors = computed(() => this.contributors().some((contributor) => contributor.deactivated)); + showLoadMore = computed(() => { + const currentLoadedItems = this.contributors().length; + const totalRecords = this.tableParams().totalRecords; + return currentLoadedItems > 0 && currentLoadedItems < totalRecords; + }); + removeContributor(contributor: ContributorModel) { this.remove.emit(contributor); } @@ -91,7 +98,7 @@ export class ContributorsTableComponent { this.contributors.set(reorderedContributors); } - onPageChange(event: TablePageEvent): void { - this.pageChanged.emit(event); + loadMoreItems() { + this.loadMore.emit(); } } diff --git a/src/app/shared/components/truncated-text/truncated-text.component.scss b/src/app/shared/components/truncated-text/truncated-text.component.scss index bb473e7e9..8c983db9c 100644 --- a/src/app/shared/components/truncated-text/truncated-text.component.scss +++ b/src/app/shared/components/truncated-text/truncated-text.component.scss @@ -4,7 +4,6 @@ text-overflow: ellipsis; display: -webkit-box; line-clamp: var(--line-clamp); - line-height: 1.7; -webkit-line-clamp: var(--line-clamp); -webkit-box-orient: vertical; white-space: pre-line; diff --git a/src/app/shared/mappers/collections/collections.mapper.ts b/src/app/shared/mappers/collections/collections.mapper.ts index 7a741e2d0..22969da39 100644 --- a/src/app/shared/mappers/collections/collections.mapper.ts +++ b/src/app/shared/mappers/collections/collections.mapper.ts @@ -37,12 +37,14 @@ export class CollectionsMapper { facebookAppId: response.attributes.facebook_app_id, allowSubmissions: response.attributes.allow_submissions, allowCommenting: response.attributes.allow_commenting, - assets: { - style: response.attributes.assets.style, - squareColorTransparent: response.attributes.assets.square_color_transparent, - squareColorNoTransparent: response.attributes.assets.square_color_no_transparent, - favicon: response.attributes.assets.favicon, - }, + assets: response.attributes.assets + ? { + style: response.attributes.assets.style, + squareColorTransparent: response.attributes.assets.square_color_transparent, + squareColorNoTransparent: response.attributes.assets.square_color_no_transparent, + favicon: response.attributes.assets.favicon, + } + : {}, shareSource: response.attributes.share_source, sharePublishType: response.attributes.share_publish_type, permissions: response.attributes.permissions, diff --git a/src/app/shared/stores/contributors/contributors.actions.ts b/src/app/shared/stores/contributors/contributors.actions.ts index 4eaaead98..ee1a85912 100644 --- a/src/app/shared/stores/contributors/contributors.actions.ts +++ b/src/app/shared/stores/contributors/contributors.actions.ts @@ -119,3 +119,32 @@ export class RejectRequestAccess { public resourceType: ResourceType | undefined ) {} } + +export class GetBibliographicContributors { + static readonly type = '[Contributors] Get Bibliographic Contributors'; + + constructor( + public resourceId: string | undefined | null, + public resourceType: ResourceType | undefined, + public page = 1, + public pageSize = DEFAULT_TABLE_PARAMS.rows + ) {} +} + +export class LoadMoreBibliographicContributors { + static readonly type = '[Contributors] Load More Bibliographic Contributors'; + + constructor( + public resourceId: string | undefined | null, + public resourceType: ResourceType | undefined + ) {} +} + +export class LoadMoreContributors { + static readonly type = '[Contributors] Load More Contributors'; + + constructor( + public resourceId: string | undefined | null, + public resourceType: ResourceType | undefined + ) {} +} diff --git a/src/app/shared/stores/contributors/contributors.model.ts b/src/app/shared/stores/contributors/contributors.model.ts index 5f7c92b61..89d34a7fd 100644 --- a/src/app/shared/stores/contributors/contributors.model.ts +++ b/src/app/shared/stores/contributors/contributors.model.ts @@ -2,16 +2,21 @@ import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants'; import { ContributorAddModel, ContributorModel, RequestAccessModel } from '@osf/shared/models'; import { AsyncStateModel, AsyncStateWithTotalCount } from '@osf/shared/models/store'; -export interface ContributorsListModel extends AsyncStateWithTotalCount { +export interface ContributorsList extends AsyncStateWithTotalCount { + page: number; + pageSize: number; +} + +export interface ContributorsListWithFiltersModel extends ContributorsList { searchValue: string | null; permissionFilter: string | null; bibliographyFilter: boolean | null; - page: number; - pageSize: number; + isLoadingMore: boolean; } export interface ContributorsStateModel { - contributorsList: ContributorsListModel; + contributorsList: ContributorsListWithFiltersModel; + bibliographicContributorsList: ContributorsList; requestAccessList: AsyncStateModel; users: AsyncStateWithTotalCount; } @@ -27,6 +32,16 @@ export const CONTRIBUTORS_STATE_DEFAULTS: ContributorsStateModel = { totalCount: 0, page: 1, pageSize: DEFAULT_TABLE_PARAMS.rows, + isLoadingMore: false, + }, + bibliographicContributorsList: { + data: [], + isLoading: false, + isSubmitting: false, + error: null, + totalCount: 0, + page: 0, + pageSize: DEFAULT_TABLE_PARAMS.rows, }, requestAccessList: { data: [], diff --git a/src/app/shared/stores/contributors/contributors.selectors.ts b/src/app/shared/stores/contributors/contributors.selectors.ts index f3816a2de..ff3844d74 100644 --- a/src/app/shared/stores/contributors/contributors.selectors.ts +++ b/src/app/shared/stores/contributors/contributors.selectors.ts @@ -37,14 +37,41 @@ export class ContributorsSelectors { return state.contributorsList.data.filter((contributor) => contributor.isBibliographic); } + @Selector([ContributorsState]) + static getBibliographicContributorsList(state: ContributorsStateModel) { + if (!state?.bibliographicContributorsList?.data) { + return []; + } + + return state.bibliographicContributorsList.data; + } + + @Selector([ContributorsState]) + static isBibliographicContributorsLoading(state: ContributorsStateModel) { + return state?.bibliographicContributorsList?.isLoading || false; + } + + @Selector([ContributorsState]) + static getBibliographicContributorsTotalCount(state: ContributorsStateModel) { + return state?.bibliographicContributorsList?.totalCount || 0; + } + + @Selector([ContributorsState]) + static hasMoreBibliographicContributors(state: ContributorsStateModel) { + return ( + state?.bibliographicContributorsList?.data?.length < state?.bibliographicContributorsList?.totalCount && + !state?.bibliographicContributorsList?.isLoading + ); + } + @Selector([ContributorsState]) static isContributorsLoading(state: ContributorsStateModel) { return state?.contributorsList?.isLoading || false; } @Selector([ContributorsState]) - static getContributorsPageNumber(state: ContributorsStateModel) { - return state.contributorsList.page; + static isContributorsLoadingMore(state: ContributorsStateModel) { + return state?.contributorsList?.isLoadingMore || false; } @Selector([ContributorsState]) @@ -57,6 +84,13 @@ export class ContributorsSelectors { return state.contributorsList.totalCount; } + @Selector([ContributorsState]) + static hasMoreContributors(state: ContributorsStateModel) { + return ( + state?.contributorsList?.data?.length < state?.contributorsList?.totalCount && !state?.contributorsList?.isLoading + ); + } + @Selector([ContributorsState]) static getUsers(state: ContributorsStateModel) { return state?.users?.data || []; diff --git a/src/app/shared/stores/contributors/contributors.state.ts b/src/app/shared/stores/contributors/contributors.state.ts index be0259ff5..e1f92b627 100644 --- a/src/app/shared/stores/contributors/contributors.state.ts +++ b/src/app/shared/stores/contributors/contributors.state.ts @@ -15,7 +15,10 @@ import { ClearUsers, DeleteContributor, GetAllContributors, + GetBibliographicContributors, GetRequestAccessContributors, + LoadMoreBibliographicContributors, + LoadMoreContributors, RejectRequestAccess, ResetContributorsState, SearchUsers, @@ -48,19 +51,23 @@ export class ContributorsState { ctx.patchState({ contributorsList: { ...state.contributorsList, - data: [], - isLoading: true, + data: page === 1 ? [] : state.contributorsList.data, + isLoading: page === 1, + isLoadingMore: page > 1, error: null, }, }); return this.contributorsService.getAllContributors(action.resourceType, action.resourceId, page, pageSize).pipe( tap((res) => { + const data = page === 1 ? res.data : [...state.contributorsList.data, ...res.data]; + ctx.patchState({ contributorsList: { ...state.contributorsList, - data: res.data, + data, isLoading: false, + isLoadingMore: false, totalCount: res.totalCount, page, pageSize, @@ -285,6 +292,65 @@ export class ContributorsState { ctx.patchState({ users: { data: [], isLoading: false, error: null, totalCount: 0 } }); } + @Action(GetBibliographicContributors) + getBibliographicContributors(ctx: StateContext, action: GetBibliographicContributors) { + const state = ctx.getState(); + + if (!action.resourceId || !action.resourceType) { + return; + } + + ctx.patchState({ + bibliographicContributorsList: { + ...state.bibliographicContributorsList, + data: action.page === 1 ? [] : state.bibliographicContributorsList.data, + isLoading: true, + error: null, + }, + }); + + return this.contributorsService + .getBibliographicContributors(action.resourceType, action.resourceId, action.page, action.pageSize) + .pipe( + tap((res) => { + const data = action.page === 1 ? res.data : [...state.bibliographicContributorsList.data, ...res.data]; + + ctx.patchState({ + bibliographicContributorsList: { + data, + isLoading: false, + error: null, + page: action.page, + pageSize: 10, + totalCount: res.totalCount, + }, + }); + }), + catchError((error) => handleSectionError(ctx, 'bibliographicContributorsList', error)) + ); + } + + @Action(LoadMoreBibliographicContributors) + loadMoreBibliographicContributors( + ctx: StateContext, + action: LoadMoreBibliographicContributors + ) { + const state = ctx.getState(); + const nextPage = state.bibliographicContributorsList.page + 1; + + return ctx.dispatch(new GetBibliographicContributors(action.resourceId, action.resourceType, nextPage, 10)); + } + + @Action(LoadMoreContributors) + loadMoreContributors(ctx: StateContext, action: LoadMoreContributors) { + const state = ctx.getState(); + const nextPage = state.contributorsList.page + 1; + + return ctx.dispatch( + new GetAllContributors(action.resourceId, action.resourceType, nextPage, state.contributorsList.pageSize) + ); + } + @Action(ResetContributorsState) resetState(ctx: StateContext) { ctx.setState({ ...CONTRIBUTORS_STATE_DEFAULTS }); diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 58c0b767d..e0aff280d 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -57,7 +57,8 @@ "removeAll": "Remove All", "accept": "Accept", "reject": "Reject", - "loadMore": "Load more" + "loadMore": "Load more", + "seeMore": "See more" }, "accessibility": { "help": "Help", diff --git a/src/styles/overrides/table.scss b/src/styles/overrides/table.scss index a27d956b4..416cee613 100644 --- a/src/styles/overrides/table.scss +++ b/src/styles/overrides/table.scss @@ -85,10 +85,13 @@ p-table { td, th { - background-color: transparent; border-bottom: 1px solid var(--grey-2); } + td { + background-color: transparent; + } + tr { &:hover { background: transparent; From 21dacd616635768b6d84acc1e9a5a2b9f9b5a338 Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 23 Oct 2025 11:31:17 +0300 Subject: [PATCH 2/5] fix(contributors): added see more for contributors list --- .../metadata-contributors.component.html | 11 ++++-- .../metadata-contributors.component.ts | 6 ++- .../contributors-dialog.component.ts | 25 ++++++++----- .../features/metadata/metadata.component.html | 3 ++ .../features/metadata/metadata.component.ts | 27 ++++++++------ .../general-information.component.html | 11 +++--- .../general-information.component.ts | 18 ++++++--- .../preprint-tombstone.component.html | 11 +++--- .../preprint-tombstone.component.ts | 18 ++++++--- .../review-step/review-step.component.html | 7 +++- .../review-step/review-step.component.ts | 22 ++++++++--- .../overview/project-overview.component.html | 4 ++ .../overview/project-overview.component.ts | 20 +++++++++- .../services/project-overview.service.ts | 9 +---- .../components/review/review.component.html | 7 +++- .../components/review/review.component.ts | 18 ++++++++- .../registry-overview.component.html | 4 ++ .../registry-overview.component.ts | 19 +++++++++- .../contributors-list.component.html | 37 ++++++++++++++----- .../contributors-list.component.scss | 3 ++ .../contributors-list.component.ts | 11 +++++- .../resource-metadata.component.html | 5 ++- .../resource-metadata.component.ts | 6 ++- .../mappers/resource-overview.mappers.ts | 7 ++-- 24 files changed, 226 insertions(+), 83 deletions(-) diff --git a/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.html b/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.html index e7956426c..3ec6df984 100644 --- a/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.html +++ b/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.html @@ -12,9 +12,14 @@

{{ 'project.overview.metadata.contributors' | translate }}

}
- @if (contributors()) { -
- + @if (contributors().length) { +
+
} diff --git a/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.ts b/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.ts index 461edea00..360c4b225 100644 --- a/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.ts +++ b/src/app/features/metadata/components/metadata-contributors/metadata-contributors.component.ts @@ -15,7 +15,11 @@ import { ContributorModel } from '@osf/shared/models'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class MetadataContributorsComponent { - openEditContributorDialog = output(); contributors = input([]); + isLoading = input(false); + hasMoreContributors = input(false); readonly = input(false); + + openEditContributorDialog = output(); + loadMoreContributors = output(); } diff --git a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts index 6d02a1e58..0d14be48d 100644 --- a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts +++ b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts @@ -72,6 +72,7 @@ export class ContributorsDialogComponent implements OnInit { contributors = signal([]); isLoadingMore = select(ContributorsSelectors.isContributorsLoadingMore); pageSize = select(ContributorsSelectors.getContributorsPageSize); + changesMade = signal(false); currentUser = select(UserSelectors.getCurrentUser); @@ -150,9 +151,10 @@ export class ContributorsDialogComponent implements OnInit { this.actions .bulkAddContributors(this.resourceId, this.resourceType, res.data) .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(() => - this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage') - ); + .subscribe(() => { + this.changesMade.set(true); + this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage'); + }); } } }); @@ -175,7 +177,10 @@ export class ContributorsDialogComponent implements OnInit { const params = { name: res.data[0].fullName }; this.actions.addContributor(this.resourceId, this.resourceType, res.data[0]).subscribe({ - next: () => this.toastService.showSuccess('project.contributors.toastMessages.addSuccessMessage', params), + next: () => { + this.changesMade.set(true); + this.toastService.showSuccess('project.contributors.toastMessages.addSuccessMessage', params); + }, }); } }); @@ -195,12 +200,13 @@ export class ContributorsDialogComponent implements OnInit { .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { + this.changesMade.set(true); this.toastService.showSuccess('project.contributors.removeDialog.successMessage', { name: contributor.fullName, }); if (isDeletingSelf) { - this.dialogRef.close(); + this.dialogRef.close(this.changesMade()); this.router.navigate(['/']); } }, @@ -218,7 +224,7 @@ export class ContributorsDialogComponent implements OnInit { } onClose(): void { - this.dialogRef.close(); + this.dialogRef.close(this.changesMade()); } onSave(): void { @@ -227,8 +233,9 @@ export class ContributorsDialogComponent implements OnInit { this.actions .bulkUpdateContributors(this.resourceId, this.resourceType, updatedContributors) .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(() => - this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage') - ); + .subscribe(() => { + this.changesMade.set(true); + this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage'); + }); } } diff --git a/src/app/features/metadata/metadata.component.html b/src/app/features/metadata/metadata.component.html index a5adc3975..fe576760d 100644 --- a/src/app/features/metadata/metadata.component.html +++ b/src/app/features/metadata/metadata.component.html @@ -38,7 +38,10 @@ this.isMetadataLoading() || - this.isContributorsLoading() || this.areInstitutionsLoading() || this.isSubmitting() || this.areResourceInstitutionsSubmitting() @@ -320,23 +322,24 @@ export class MetadataComponent implements OnInit { this.actions.updateMetadata(this.resourceId, this.resourceType(), { tags }); } + handleLoadMoreContributors(): void { + this.actions.loadMoreBibliographicContributors(this.resourceId, this.resourceType()); + } + openEditContributorDialog(): void { this.customDialogService .open(ContributorsDialogComponent, { header: 'project.metadata.contributors.editContributors', - width: '600px', + width: '800px', data: { resourceId: this.resourceId, resourceType: this.resourceType(), }, }) - .onClose.subscribe((result) => { - if (result) { - this.actions.getResourceMetadata(this.resourceId, this.resourceType()); - this.toastService.showSuccess('project.metadata.contributors.updateSucceed'); + .onClose.subscribe((changesMade) => { + if (changesMade) { + this.actions.getContributors(this.resourceId, this.resourceType()); } - - this.actions.updateContributorsSearchValue(null); }); } diff --git a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html index 1864e4d31..079003eb2 100644 --- a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html +++ b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html @@ -7,11 +7,12 @@

{{ 'preprints.preprintStepper.review.sections.metadata.authors' | translate }}

- - - @if (areContributorsLoading()) { - - } +
diff --git a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts index c3cbfac6b..a710da82b 100644 --- a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts +++ b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts @@ -22,8 +22,9 @@ import { ResourceType } from '@osf/shared/enums'; import { ContributorsSelectors, FetchResourceInstitutions, - GetAllContributors, + GetBibliographicContributors, InstitutionsSelectors, + LoadMoreBibliographicContributors, ResetContributorsState, } from '@osf/shared/stores'; @@ -53,10 +54,11 @@ export class GeneralInformationComponent implements OnDestroy { readonly PreregLinkInfo = PreregLinkInfo; private actions = createDispatchMap({ - getContributors: GetAllContributors, + getBibliographicContributors: GetBibliographicContributors, resetContributorsState: ResetContributorsState, fetchPreprintById: FetchPreprintById, fetchResourceInstitutions: FetchResourceInstitutions, + loadMoreBibliographicContributors: LoadMoreBibliographicContributors, }); preprintProvider = input.required(); @@ -67,9 +69,9 @@ export class GeneralInformationComponent implements OnDestroy { affiliatedInstitutions = select(InstitutionsSelectors.getResourceInstitutions); - contributors = select(ContributorsSelectors.getContributors); - areContributorsLoading = select(ContributorsSelectors.isContributorsLoading); - bibliographicContributors = computed(() => this.contributors().filter((contributor) => contributor.isBibliographic)); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + areContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); + hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); skeletonData = Array.from({ length: 5 }, () => null); @@ -80,7 +82,7 @@ export class GeneralInformationComponent implements OnDestroy { const preprint = this.preprint(); if (!preprint) return; - this.actions.getContributors(this.preprint()!.id, ResourceType.Preprint); + this.actions.getBibliographicContributors(this.preprint()!.id, ResourceType.Preprint); this.actions.fetchResourceInstitutions(this.preprint()!.id, ResourceType.Preprint); }); } @@ -88,4 +90,8 @@ export class GeneralInformationComponent implements OnDestroy { ngOnDestroy(): void { this.actions.resetContributorsState(); } + + handleLoadMoreContributors(): void { + this.actions.loadMoreBibliographicContributors(this.preprint()?.id, ResourceType.Preprint); + } } diff --git a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.html b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.html index 901890563..633711405 100644 --- a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.html +++ b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.html @@ -13,11 +13,12 @@

{{ 'preprints.details.reasonForWithdrawal' | translate }}

{{ 'preprints.preprintStepper.review.sections.metadata.authors' | translate }}

- - - @if (areContributorsLoading()) { - - } +
diff --git a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts index 347a8a2ad..b08c9c46c 100644 --- a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts +++ b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts @@ -20,7 +20,8 @@ import { InterpolatePipe } from '@osf/shared/pipes'; import { ContributorsSelectors, FetchSelectedSubjects, - GetAllContributors, + GetBibliographicContributors, + LoadMoreBibliographicContributors, ResetContributorsState, SubjectsSelectors, } from '@osf/shared/stores'; @@ -53,10 +54,11 @@ export class PreprintTombstoneComponent implements OnDestroy { readonly PreregLinkInfo = PreregLinkInfo; private actions = createDispatchMap({ - getContributors: GetAllContributors, + getBibliographicContributors: GetBibliographicContributors, resetContributorsState: ResetContributorsState, fetchPreprintById: FetchPreprintById, fetchSubjects: FetchSelectedSubjects, + loadMoreBibliographicContributors: LoadMoreBibliographicContributors, }); private router = inject(Router); @@ -67,9 +69,9 @@ export class PreprintTombstoneComponent implements OnDestroy { preprint = select(PreprintSelectors.getPreprint); isPreprintLoading = select(PreprintSelectors.isPreprintLoading); - contributors = select(ContributorsSelectors.getContributors); - areContributorsLoading = select(ContributorsSelectors.isContributorsLoading); - bibliographicContributors = computed(() => this.contributors().filter((contributor) => contributor.isBibliographic)); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + areContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); + hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); subjects = select(SubjectsSelectors.getSelectedSubjects); areSelectedSubjectsLoading = select(SubjectsSelectors.areSelectedSubjectsLoading); @@ -88,7 +90,7 @@ export class PreprintTombstoneComponent implements OnDestroy { const preprint = this.preprint(); if (!preprint) return; - this.actions.getContributors(this.preprint()!.id, ResourceType.Preprint); + this.actions.getBibliographicContributors(this.preprint()?.id, ResourceType.Preprint); this.actions.fetchSubjects(this.preprint()!.id, ResourceType.Preprint); }); } @@ -100,4 +102,8 @@ export class PreprintTombstoneComponent implements OnDestroy { tagClicked(tag: string) { this.router.navigate(['/search'], { queryParams: { search: tag } }); } + + loadMoreContributors(): void { + this.actions.loadMoreBibliographicContributors(this.preprint()?.id, ResourceType.Preprint); + } } diff --git a/src/app/features/preprints/components/stepper/review-step/review-step.component.html b/src/app/features/preprints/components/stepper/review-step/review-step.component.html index c4eb7d713..e0e092c86 100644 --- a/src/app/features/preprints/components/stepper/review-step/review-step.component.html +++ b/src/app/features/preprints/components/stepper/review-step/review-step.component.html @@ -62,7 +62,12 @@

{{ 'preprints.preprintStepper.review.sections.metadata.title' | translate }}

{{ 'common.labels.contributors' | translate }}

- +
@if (affiliatedInstitutions().length) { diff --git a/src/app/features/preprints/components/stepper/review-step/review-step.component.ts b/src/app/features/preprints/components/stepper/review-step/review-step.component.ts index 132fa9dde..363f6e90d 100644 --- a/src/app/features/preprints/components/stepper/review-step/review-step.component.ts +++ b/src/app/features/preprints/components/stepper/review-step/review-step.component.ts @@ -31,7 +31,13 @@ import { import { ResourceType } from '@shared/enums'; import { InterpolatePipe } from '@shared/pipes'; import { ToastService } from '@shared/services'; -import { ContributorsSelectors, FetchSelectedSubjects, GetAllContributors, SubjectsSelectors } from '@shared/stores'; +import { + ContributorsSelectors, + FetchSelectedSubjects, + GetBibliographicContributors, + LoadMoreBibliographicContributors, + SubjectsSelectors, +} from '@shared/stores'; import { FetchResourceInstitutions, InstitutionsSelectors } from '@shared/stores/institutions'; @Component({ @@ -60,7 +66,7 @@ export class ReviewStepComponent implements OnInit { private router = inject(Router); private toastService = inject(ToastService); private actions = createDispatchMap({ - getContributors: GetAllContributors, + getBibliographicContributors: GetBibliographicContributors, fetchSubjects: FetchSelectedSubjects, fetchLicenses: FetchLicenses, fetchPreprintProject: FetchPreprintProject, @@ -68,6 +74,7 @@ export class ReviewStepComponent implements OnInit { fetchResourceInstitutions: FetchResourceInstitutions, updatePrimaryFileRelationship: UpdatePrimaryFileRelationship, updatePreprint: UpdatePreprint, + loadMoreBibliographicContributors: LoadMoreBibliographicContributors, }); provider = input.required(); @@ -76,8 +83,9 @@ export class ReviewStepComponent implements OnInit { preprintFile = select(PreprintStepperSelectors.getPreprintFile); isPreprintSubmitting = select(PreprintStepperSelectors.isPreprintSubmitting); - contributors = select(ContributorsSelectors.getContributors); - bibliographicContributors = computed(() => this.contributors().filter((contributor) => contributor.isBibliographic)); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + areContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); + hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); subjects = select(SubjectsSelectors.getSelectedSubjects); affiliatedInstitutions = select(InstitutionsSelectors.getResourceInstitutions); license = select(PreprintStepperSelectors.getPreprintLicense); @@ -88,7 +96,7 @@ export class ReviewStepComponent implements OnInit { readonly PreregLinkInfo = PreregLinkInfo; ngOnInit(): void { - this.actions.getContributors(this.preprint()!.id, ResourceType.Preprint); + this.actions.getBibliographicContributors(this.preprint()?.id, ResourceType.Preprint); this.actions.fetchSubjects(this.preprint()!.id, ResourceType.Preprint); this.actions.fetchLicenses(); this.actions.fetchPreprintProject(); @@ -123,4 +131,8 @@ export class ReviewStepComponent implements OnInit { cancelSubmission() { this.router.navigateByUrl('/preprints'); } + + loadMoreContributors(): void { + this.actions.loadMoreBibliographicContributors(this.preprint()?.id, ResourceType.Preprint); + } } diff --git a/src/app/features/project/overview/project-overview.component.html b/src/app/features/project/overview/project-overview.component.html index f9d5a7850..f65b70d76 100644 --- a/src/app/features/project/overview/project-overview.component.html +++ b/src/app/features/project/overview/project-overview.component.html @@ -89,6 +89,10 @@ [isCollectionsRoute]="isCollectionsRoute()" [canEdit]="hasAdminAccess()" [showEditButton]="hasWriteAccess()" + [bibliographicContributors]="bibliographicContributors()" + [isBibliographicContributorsLoading]="isBibliographicContributorsLoading()" + [hasMoreBibliographicContributors]="hasMoreBibliographicContributors()" + (loadMoreContributors)="handleLoadMoreContributors()" />

diff --git a/src/app/features/project/overview/project-overview.component.ts b/src/app/features/project/overview/project-overview.component.ts index 8c87fc8e0..33d007bf8 100644 --- a/src/app/features/project/overview/project-overview.component.ts +++ b/src/app/features/project/overview/project-overview.component.ts @@ -39,9 +39,11 @@ import { ClearConfiguredAddons, ClearWiki, CollectionsSelectors, + ContributorsSelectors, CurrentResourceSelectors, FetchSelectedSubjects, GetAddonsResourceReference, + GetBibliographicContributors, GetBookmarksCollectionId, GetCollectionProvider, GetConfiguredCitationAddons, @@ -49,6 +51,8 @@ import { GetHomeWiki, GetLinkedResources, GetResourceWithChildren, + LoadMoreBibliographicContributors, + ResetContributorsState, SubjectsSelectors, } from '@osf/shared/stores'; import { GetActivityLogs } from '@osf/shared/stores/activity-logs'; @@ -139,6 +143,9 @@ export class ProjectOverviewComponent implements OnInit { isWikiEnabled = select(ProjectOverviewSelectors.isWikiEnabled); parentProject = select(ProjectOverviewSelectors.getParentProject); isParentProjectLoading = select(ProjectOverviewSelectors.getParentProjectLoading); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + isBibliographicContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); + hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); addonsResourceReference = select(AddonsSelectors.getAddonsResourceReference); configuredCitationAddons = select(AddonsSelectors.getConfiguredCitationAddons); operationInvocation = select(AddonsSelectors.getOperationInvocation); @@ -164,6 +171,9 @@ export class ProjectOverviewComponent implements OnInit { getParentProject: GetParentProject, getAddonsResourceReference: GetAddonsResourceReference, getConfiguredCitationAddons: GetConfiguredCitationAddons, + getBibliographicContributors: GetBibliographicContributors, + loadMoreBibliographicContributors: LoadMoreBibliographicContributors, + resetContributorsState: ResetContributorsState, }); readonly activityPageSize = 5; @@ -193,8 +203,9 @@ export class ProjectOverviewComponent implements OnInit { resourceOverview = computed(() => { const project = this.currentProject(); const subjects = this.subjects(); + const bibliographicContributors = this.bibliographicContributors(); if (project) { - return MapProjectOverview(project, subjects, this.isAnonymous()); + return MapProjectOverview(project, subjects, this.isAnonymous(), bibliographicContributors); } return null; }); @@ -282,6 +293,10 @@ export class ProjectOverviewComponent implements OnInit { this.actions.setProjectCustomCitation(citation); } + handleLoadMoreContributors(): void { + this.actions.loadMoreBibliographicContributors(this.currentProject()?.id, ResourceType.Project); + } + ngOnInit(): void { const projectId = this.route.snapshot.params['id'] || this.route.parent?.snapshot.params['id']; @@ -291,6 +306,7 @@ export class ProjectOverviewComponent implements OnInit { this.actions.getComponents(projectId); this.actions.getLinkedProjects(projectId); this.actions.getActivityLogs(projectId, this.activityDefaultPage, this.activityPageSize); + this.actions.getBibliographicContributors(projectId, ResourceType.Project); } this.dataciteService @@ -385,6 +401,7 @@ export class ProjectOverviewComponent implements OnInit { this.actions.getComponents(projectId); this.actions.getLinkedProjects(projectId); this.actions.getActivityLogs(projectId, this.activityDefaultPage, this.activityPageSize); + this.actions.getBibliographicContributors(projectId, ResourceType.Project); }), takeUntilDestroyed(this.destroyRef) ) @@ -398,6 +415,7 @@ export class ProjectOverviewComponent implements OnInit { this.actions.clearCollections(); this.actions.clearCollectionModeration(); this.actions.clearConfiguredAddons(); + this.actions.resetContributorsState(); }); } diff --git a/src/app/features/project/overview/services/project-overview.service.ts b/src/app/features/project/overview/services/project-overview.service.ts index 4261b22a8..eb8bf543a 100644 --- a/src/app/features/project/overview/services/project-overview.service.ts +++ b/src/app/features/project/overview/services/project-overview.service.ts @@ -34,14 +34,7 @@ export class ProjectOverviewService { getProjectById(projectId: string): Observable { const params: Record = { - 'embed[]': [ - 'bibliographic_contributors', - 'affiliated_institutions', - 'identifiers', - 'license', - 'storage', - 'preprints', - ], + 'embed[]': ['affiliated_institutions', 'identifiers', 'license', 'storage', 'preprints'], 'fields[institutions]': 'assets,description,name', 'fields[preprints]': 'title,date_created', 'fields[users]': 'family_name,full_name,given_name,middle_name', diff --git a/src/app/features/registries/components/review/review.component.html b/src/app/features/registries/components/review/review.component.html index 691afff6c..0392daa69 100644 --- a/src/app/features/registries/components/review/review.component.html +++ b/src/app/features/registries/components/review/review.component.html @@ -27,7 +27,12 @@

{{ 'common.labels.description' | translate }}

{{ 'common.labels.contributors' | translate }}

- +
diff --git a/src/app/features/registries/components/review/review.component.ts b/src/app/features/registries/components/review/review.component.ts index cc8b2e29a..b0ff45a0d 100644 --- a/src/app/features/registries/components/review/review.component.ts +++ b/src/app/features/registries/components/review/review.component.ts @@ -10,7 +10,7 @@ import { Tag } from 'primeng/tag'; import { map, of } from 'rxjs'; -import { ChangeDetectionStrategy, Component, computed, effect, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, computed, effect, inject, OnDestroy } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { ActivatedRoute, Router } from '@angular/router'; @@ -24,6 +24,8 @@ import { ContributorsSelectors, FetchSelectedSubjects, GetAllContributors, + LoadMoreContributors, + ResetContributorsState, SubjectsSelectors, } from '@osf/shared/stores'; @@ -58,7 +60,7 @@ import { SelectComponentsDialogComponent } from '../select-components-dialog/sel styleUrl: './review.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ReviewComponent { +export class ReviewComponent implements OnDestroy { private readonly router = inject(Router); private readonly route = inject(ActivatedRoute); private readonly customConfirmationService = inject(CustomConfirmationService); @@ -73,6 +75,8 @@ export class ReviewComponent { readonly stepsData = select(RegistriesSelectors.getStepsData); readonly INPUT_VALIDATION_MESSAGES = INPUT_VALIDATION_MESSAGES; readonly contributors = select(ContributorsSelectors.getContributors); + readonly areContributorsLoading = select(ContributorsSelectors.isContributorsLoading); + readonly hasMoreContributors = select(ContributorsSelectors.hasMoreContributors); readonly subjects = select(SubjectsSelectors.getSelectedSubjects); readonly components = select(RegistriesSelectors.getRegistrationComponents); readonly license = select(RegistriesSelectors.getRegistrationLicense); @@ -88,6 +92,8 @@ export class ReviewComponent { getProjectsComponents: FetchProjectChildren, fetchLicenses: FetchLicenses, updateStepState: UpdateStepState, + loadMoreContributors: LoadMoreContributors, + resetContributorsState: ResetContributorsState, }); private readonly draftId = toSignal(this.route.params.pipe(map((params) => params['id'])) ?? of(undefined)); @@ -134,6 +140,10 @@ export class ReviewComponent { }); } + ngOnDestroy(): void { + this.actions.resetContributorsState(); + } + goBack(): void { const previousStep = this.pages().length; this.router.navigate(['../', previousStep], { relativeTo: this.route }); @@ -206,4 +216,8 @@ export class ReviewComponent { } }); } + + loadMoreContributors(): void { + this.actions.loadMoreContributors(this.draftId(), ResourceType.DraftRegistration); + } } diff --git a/src/app/features/registry/pages/registry-overview/registry-overview.component.html b/src/app/features/registry/pages/registry-overview/registry-overview.component.html index 387f1f2a6..2f90fd324 100644 --- a/src/app/features/registry/pages/registry-overview/registry-overview.component.html +++ b/src/app/features/registry/pages/registry-overview/registry-overview.component.html @@ -136,6 +136,10 @@

{{ section.title }}

(customCitationUpdated)="onCustomCitationUpdated($event)" [canEdit]="hasWriteAccess()" [showEditButton]="hasWriteAccess()" + [bibliographicContributors]="bibliographicContributors()" + [isBibliographicContributorsLoading]="isBibliographicContributorsLoading()" + [hasMoreBibliographicContributors]="hasMoreBibliographicContributors()" + (loadMoreContributors)="handleLoadMoreContributors()" />

diff --git a/src/app/features/registry/pages/registry-overview/registry-overview.component.ts b/src/app/features/registry/pages/registry-overview/registry-overview.component.ts index af1b77fb6..fafecac24 100644 --- a/src/app/features/registry/pages/registry-overview/registry-overview.component.ts +++ b/src/app/features/registry/pages/registry-overview/registry-overview.component.ts @@ -35,7 +35,14 @@ import { hasViewOnlyParam, toCamelCase } from '@osf/shared/helpers'; import { MapRegistryOverview } from '@osf/shared/mappers'; import { SchemaResponse, ToolbarResource } from '@osf/shared/models'; import { CustomDialogService, ToastService } from '@osf/shared/services'; -import { FetchSelectedSubjects, GetBookmarksCollectionId, SubjectsSelectors } from '@osf/shared/stores'; +import { + ContributorsSelectors, + FetchSelectedSubjects, + GetBibliographicContributors, + GetBookmarksCollectionId, + LoadMoreBibliographicContributors, + SubjectsSelectors, +} from '@osf/shared/stores'; import { ArchivingMessageComponent, RegistryRevisionsComponent, RegistryStatusesComponent } from '../../components'; import { RegistryMakeDecisionComponent } from '../../components/registry-make-decision/registry-make-decision.component'; @@ -90,6 +97,9 @@ export class RegistryOverviewComponent { readonly areReviewActionsLoading = select(RegistryOverviewSelectors.areReviewActionsLoading); readonly currentRevision = select(RegistriesSelectors.getSchemaResponse); readonly isSchemaResponseLoading = select(RegistriesSelectors.getSchemaResponseLoading); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + isBibliographicContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); + hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); readonly hasWriteAccess = select(RegistryOverviewSelectors.hasWriteAccess); readonly hasAdminAccess = select(RegistryOverviewSelectors.hasAdminAccess); @@ -180,6 +190,8 @@ export class RegistryOverviewComponent { getRegistryReviewActions: GetRegistryReviewActions, getSchemaResponse: FetchAllSchemaResponses, createSchemaResponse: CreateSchemaResponse, + getBibliographicContributors: GetBibliographicContributors, + loadMoreBibliographicContributors: LoadMoreBibliographicContributors, }); revisionId: string | null = null; @@ -213,6 +225,7 @@ export class RegistryOverviewComponent { effect(() => { if (this.registryId()) { this.actions.getRegistryById(this.registryId()); + this.actions.getBibliographicContributors(this.registryId(), ResourceType.Registration); } }); @@ -272,6 +285,10 @@ export class RegistryOverviewComponent { .subscribe(); } + handleLoadMoreContributors(): void { + this.actions.loadMoreBibliographicContributors(this.registry()?.id, ResourceType.Registration); + } + private navigateToJustificationPage(): void { const revisionId = this.revisionId || this.revisionInProgress?.id; this.router.navigate([`/registries/revisions/${revisionId}/justification`]); diff --git a/src/app/shared/components/contributors-list/contributors-list.component.html b/src/app/shared/components/contributors-list/contributors-list.component.html index 7c379d360..814ad1dac 100644 --- a/src/app/shared/components/contributors-list/contributors-list.component.html +++ b/src/app/shared/components/contributors-list/contributors-list.component.html @@ -1,17 +1,34 @@ -
+
@if (anonymous()) {

{{ 'project.overview.metadata.anonymousContributors' | translate }}

} @else { - @for (contributor of contributors(); track contributor.id) { -
- @if (readonly() || contributor.isUnregisteredContributor || !contributor.id || contributor.deactivated) { - {{ contributor.fullName }}{{ $last ? '' : ',' }} - } @else { - - {{ contributor.fullName }}{{ $last ? '' : ',' }} - - } + @if (isLoading()) { +
+
+ } @else { + @for (contributor of contributors(); track contributor.id) { +
+ @if (readonly() || contributor.isUnregisteredContributor || !contributor.id || contributor.deactivated) { + {{ contributor.fullName }}{{ $last ? '' : ',' }} + } @else { + + {{ contributor.fullName }}{{ $last ? '' : ',' }} + + } +
+ } } }
+ +@if (hasLoadMore()) { +
+ +
+} diff --git a/src/app/shared/components/contributors-list/contributors-list.component.scss b/src/app/shared/components/contributors-list/contributors-list.component.scss index e69de29bb..b9bc65ea4 100644 --- a/src/app/shared/components/contributors-list/contributors-list.component.scss +++ b/src/app/shared/components/contributors-list/contributors-list.component.scss @@ -0,0 +1,3 @@ +:host { + width: 100%; +} diff --git a/src/app/shared/components/contributors-list/contributors-list.component.ts b/src/app/shared/components/contributors-list/contributors-list.component.ts index 89cc6ab67..b84335abc 100644 --- a/src/app/shared/components/contributors-list/contributors-list.component.ts +++ b/src/app/shared/components/contributors-list/contributors-list.component.ts @@ -1,19 +1,26 @@ import { TranslatePipe } from '@ngx-translate/core'; -import { ChangeDetectionStrategy, Component, input } from '@angular/core'; +import { Button } from 'primeng/button'; +import { Skeleton } from 'primeng/skeleton'; + +import { ChangeDetectionStrategy, Component, input, output } from '@angular/core'; import { RouterLink } from '@angular/router'; import { ContributorModel } from '@shared/models'; @Component({ selector: 'osf-contributors-list', - imports: [RouterLink, TranslatePipe], + imports: [RouterLink, TranslatePipe, Skeleton, Button], templateUrl: './contributors-list.component.html', styleUrl: './contributors-list.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class ContributorsListComponent { contributors = input.required[]>(); + isLoading = input(false); + hasLoadMore = input(false); readonly = input(false); anonymous = input(false); + + loadMoreContributors = output(); } diff --git a/src/app/shared/components/resource-metadata/resource-metadata.component.html b/src/app/shared/components/resource-metadata/resource-metadata.component.html index cd4398182..060edb646 100644 --- a/src/app/shared/components/resource-metadata/resource-metadata.component.html +++ b/src/app/shared/components/resource-metadata/resource-metadata.component.html @@ -19,8 +19,11 @@

{{ 'common.labels.contributors' | translate }}

diff --git a/src/app/shared/components/resource-metadata/resource-metadata.component.ts b/src/app/shared/components/resource-metadata/resource-metadata.component.ts index f1ef25b3a..b83423090 100644 --- a/src/app/shared/components/resource-metadata/resource-metadata.component.ts +++ b/src/app/shared/components/resource-metadata/resource-metadata.component.ts @@ -10,7 +10,7 @@ import { Router, RouterLink } from '@angular/router'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { OverviewCollectionsComponent } from '@osf/features/project/overview/components/overview-collections/overview-collections.component'; import { CurrentResourceType } from '@osf/shared/enums'; -import { ResourceOverview } from '@shared/models'; +import { ContributorModel, ResourceOverview } from '@shared/models'; import { AffiliatedInstitutionsViewComponent } from '../affiliated-institutions-view/affiliated-institutions-view.component'; import { ContributorsListComponent } from '../contributors-list/contributors-list.component'; @@ -44,6 +44,10 @@ export class ResourceMetadataComponent { isCollectionsRoute = input(false); canEdit = input.required(); showEditButton = input(); + bibliographicContributors = input([]); + isBibliographicContributorsLoading = input(false); + hasMoreBibliographicContributors = input(false); + loadMoreContributors = output(); readonly resourceTypes = CurrentResourceType; readonly dateFormat = 'MMM d, y, h:mm a'; diff --git a/src/app/shared/mappers/resource-overview.mappers.ts b/src/app/shared/mappers/resource-overview.mappers.ts index 419e515fa..cb4a69622 100644 --- a/src/app/shared/mappers/resource-overview.mappers.ts +++ b/src/app/shared/mappers/resource-overview.mappers.ts @@ -1,12 +1,13 @@ import { ProjectOverview } from '@osf/features/project/overview/models'; import { RegistryOverview } from '@osf/features/registry/models'; -import { Institution, ResourceOverview, SubjectModel } from '../models'; +import { ContributorModel, Institution, ResourceOverview, SubjectModel } from '../models'; export function MapProjectOverview( project: ProjectOverview, subjects: SubjectModel[], - isAnonymous = false + isAnonymous = false, + bibliographicContributors: ContributorModel[] = [] ): ResourceOverview { return { id: project.id, @@ -35,7 +36,7 @@ export function MapProjectOverview( currentUserIsContributorOrGroupMember: project.currentUserIsContributorOrGroupMember, wikiEnabled: project.wikiEnabled, subjects: subjects, - contributors: project.contributors?.filter(Boolean) || [], + contributors: bibliographicContributors?.filter(Boolean) || [], customCitation: project.customCitation || null, region: project.region || undefined, affiliatedInstitutions: project.affiliatedInstitutions?.filter(Boolean) || undefined, From 5a5ef020e6936970f3e6496d91984ec77c90b805 Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 23 Oct 2025 11:51:48 +0300 Subject: [PATCH 3/5] fix(preprints): updated preprints styles --- .../additional-info/additional-info.component.html | 6 +++--- .../general-information/general-information.component.html | 4 ++-- .../preprint-file-section.component.scss | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/features/preprints/components/preprint-details/additional-info/additional-info.component.html b/src/app/features/preprints/components/preprint-details/additional-info/additional-info.component.html index c5c929c7e..cca778583 100644 --- a/src/app/features/preprints/components/preprint-details/additional-info/additional-info.component.html +++ b/src/app/features/preprints/components/preprint-details/additional-info/additional-info.component.html @@ -53,7 +53,7 @@

{{ 'preprints.preprintStepper.review.sections.metadata.subjects' | translate } @if (areSelectedSubjectsLoading()) { - + }

@@ -83,8 +83,8 @@

{{ 'preprints.preprintStepper.review.sections.metadata.tags' | translate }}<
@for (i of skeletonData; track $index) {
- - + +
}
diff --git a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html index 079003eb2..a20d43ff2 100644 --- a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html +++ b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html @@ -119,8 +119,8 @@

{{ 'preprints.preprintStepper.review.sections.authorAssertions.conflictOfInt
@for (i of skeletonData; track $index) {
- - + +
}
diff --git a/src/app/features/preprints/components/preprint-details/preprint-file-section/preprint-file-section.component.scss b/src/app/features/preprints/components/preprint-details/preprint-file-section/preprint-file-section.component.scss index c205f2091..7aa21b9e3 100644 --- a/src/app/features/preprints/components/preprint-details/preprint-file-section/preprint-file-section.component.scss +++ b/src/app/features/preprints/components/preprint-details/preprint-file-section/preprint-file-section.component.scss @@ -4,7 +4,7 @@ } .file-section-height { - min-height: 400px; + min-height: 600px; } .card { From 13d8aa532f96fe79b69e63346c930a8c1b531eeb Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 23 Oct 2025 12:54:34 +0300 Subject: [PATCH 4/5] fix(contributors): updated selected contributors in add dialog --- .../project-contributors-step.component.ts | 3 --- .../contributors/contributors.component.ts | 2 -- .../contributors-dialog.component.ts | 3 --- .../preprint-submission-item.component.html | 2 +- .../preprints-contributors.component.ts | 3 --- .../registries-contributors.component.ts | 3 --- .../add-contributor-dialog.component.html | 7 +++++- .../add-contributor-dialog.component.ts | 23 ++++++++++++++++++- .../contributors/contributor-add.model.ts | 2 ++ .../stores/contributors/contributors.state.ts | 22 +++++++++++------- 10 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts b/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts index 54a19165d..99581d068 100644 --- a/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts +++ b/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.ts @@ -163,13 +163,10 @@ export class ProjectContributorsStepComponent { } private openAddContributorDialog() { - const addedContributorIds = this.projectContributors().map((x) => x.userId); - this.customDialogService .open(AddContributorDialogComponent, { header: 'project.contributors.addDialog.addRegisteredContributor', width: '448px', - data: addedContributorIds, }) .onClose.pipe( filter((res: ContributorDialogAddModel) => !!res), diff --git a/src/app/features/contributors/contributors.component.ts b/src/app/features/contributors/contributors.component.ts index 93fd037e7..68b48e494 100644 --- a/src/app/features/contributors/contributors.component.ts +++ b/src/app/features/contributors/contributors.component.ts @@ -255,7 +255,6 @@ export class ContributorsComponent implements OnInit, OnDestroy { } openAddContributorDialog() { - const addedContributorIds = this.initialContributors().map((x) => x.userId); const rootParentId = this.resourceDetails().rootParentId ?? this.resourceId(); this.loaderService.show(); @@ -273,7 +272,6 @@ export class ContributorsComponent implements OnInit, OnDestroy { header: 'project.contributors.addDialog.addRegisteredContributor', width: '448px', data: { - addedContributorIds, components, resourceName: this.resourceDetails().title, }, diff --git a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts index 0d14be48d..d3f9fd331 100644 --- a/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts +++ b/src/app/features/metadata/dialogs/contributors-dialog/contributors-dialog.component.ts @@ -131,13 +131,10 @@ export class ContributorsDialogComponent implements OnInit { } openAddContributorDialog(): void { - const addedContributorIds = this.initialContributors().map((x) => x.userId); - this.customDialogService .open(AddContributorDialogComponent, { header: 'project.contributors.addDialog.addRegisteredContributor', width: '448px', - data: addedContributorIds, }) .onClose.pipe( filter((res: ContributorDialogAddModel) => !!res), diff --git a/src/app/features/moderation/components/preprint-submission-item/preprint-submission-item.component.html b/src/app/features/moderation/components/preprint-submission-item/preprint-submission-item.component.html index ae7decd48..8de29f158 100644 --- a/src/app/features/moderation/components/preprint-submission-item/preprint-submission-item.component.html +++ b/src/app/features/moderation/components/preprint-submission-item/preprint-submission-item.component.html @@ -39,7 +39,7 @@ -
+

{{ 'common.labels.contributors' | translate }}:

@if (submission().contributorsLoading) { diff --git a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts index 24e11678c..0331b822f 100644 --- a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts @@ -115,13 +115,10 @@ export class PreprintsContributorsComponent implements OnInit { } openAddContributorDialog() { - const addedContributorIds = this.initialContributors().map((x) => x.userId); - this.customDialogService .open(AddContributorDialogComponent, { header: 'project.contributors.addDialog.addRegisteredContributor', width: '448px', - data: addedContributorIds, }) .onClose.pipe( filter((res: ContributorDialogAddModel) => !!res), diff --git a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts index 8b720bd1e..b7fdc2449 100644 --- a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts +++ b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.ts @@ -132,13 +132,10 @@ export class RegistriesContributorsComponent implements OnInit, OnDestroy { } openAddContributorDialog() { - const addedContributorIds = this.initialContributors().map((x) => x.userId); - this.customDialogService .open(AddContributorDialogComponent, { header: 'project.contributors.addDialog.addRegisteredContributor', width: '448px', - data: addedContributorIds, }) .onClose.pipe( filter((res: ContributorDialogAddModel) => !!res), diff --git a/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.html b/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.html index 933bf2479..fec415038 100644 --- a/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.html +++ b/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.html @@ -11,7 +11,12 @@ } @else { @for (item of users(); track $index) { } diff --git a/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.ts b/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.ts index f560f5ca8..f1ec803e2 100644 --- a/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.ts +++ b/src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.ts @@ -14,6 +14,7 @@ import { Component, computed, DestroyRef, + effect, inject, OnDestroy, OnInit, @@ -82,6 +83,10 @@ export class AddContributorDialogComponent implements OnInit, OnDestroy { readonly hasComponents = computed(() => this.components().length > 0); readonly buttonLabel = computed(() => (this.isComponentsState() ? 'common.buttons.done' : 'common.buttons.next')); + constructor() { + this.setupEffects(); + } + ngOnInit(): void { this.initializeDialogData(); this.setSearchSubscription(); @@ -145,8 +150,10 @@ export class AddContributorDialogComponent implements OnInit, OnDestroy { .filter((c) => c.checked && !c.isCurrent) .map((c) => c.id); + const filteredUsers = this.selectedUsers().filter((user) => !user.disabled); + this.dialogRef.close({ - data: this.selectedUsers(), + data: filteredUsers, type: AddContributorType.Registered, childNodeIds: childNodeIds.length > 0 ? childNodeIds : undefined, } as ContributorDialogAddModel); @@ -174,4 +181,18 @@ export class AddContributorDialogComponent implements OnInit, OnDestroy { this.currentPage.set(1); this.first.set(0); } + + private setupEffects(): void { + effect(() => { + const usersList = this.users(); + + if (usersList.length > 0) { + const checkedUsers = usersList.filter((user) => user.checked); + + if (checkedUsers.length > 0) { + this.selectedUsers.set(checkedUsers); + } + } + }); + } } diff --git a/src/app/shared/models/contributors/contributor-add.model.ts b/src/app/shared/models/contributors/contributor-add.model.ts index 31bc3bf35..9e6a6f6c6 100644 --- a/src/app/shared/models/contributors/contributor-add.model.ts +++ b/src/app/shared/models/contributors/contributor-add.model.ts @@ -5,4 +5,6 @@ export interface ContributorAddModel { fullName?: string; email?: string; index?: number; + checked?: boolean; + disabled?: boolean; } diff --git a/src/app/shared/stores/contributors/contributors.state.ts b/src/app/shared/stores/contributors/contributors.state.ts index e1f92b627..bc4f04e1c 100644 --- a/src/app/shared/stores/contributors/contributors.state.ts +++ b/src/app/shared/stores/contributors/contributors.state.ts @@ -266,17 +266,21 @@ export class ContributorsState { users: { ...state.users, isLoading: true, error: null }, }); - const addedContributorsIds = state.contributorsList.data.map((contributor) => contributor.userId); - if (!action.searchValue) { return of([]); } return this.contributorsService.searchUsers(action.searchValue, action.page).pipe( tap((users) => { + const addedContributorsIds = state.contributorsList.data.map((contributor) => contributor.userId); + ctx.patchState({ users: { - data: users.data.filter((user) => !addedContributorsIds.includes(user.id!)), + data: users.data.map((user) => ({ + ...user, + checked: addedContributorsIds.includes(user.id!), + disabled: addedContributorsIds.includes(user.id!), + })), isLoading: false, error: '', totalCount: users.totalCount, @@ -321,7 +325,7 @@ export class ContributorsState { isLoading: false, error: null, page: action.page, - pageSize: 10, + pageSize: res.pageSize, totalCount: res.totalCount, }, }); @@ -337,18 +341,20 @@ export class ContributorsState { ) { const state = ctx.getState(); const nextPage = state.bibliographicContributorsList.page + 1; + const nextPageSize = state.bibliographicContributorsList.pageSize; - return ctx.dispatch(new GetBibliographicContributors(action.resourceId, action.resourceType, nextPage, 10)); + return ctx.dispatch( + new GetBibliographicContributors(action.resourceId, action.resourceType, nextPage, nextPageSize) + ); } @Action(LoadMoreContributors) loadMoreContributors(ctx: StateContext, action: LoadMoreContributors) { const state = ctx.getState(); const nextPage = state.contributorsList.page + 1; + const nextPageSize = state.contributorsList.pageSize; - return ctx.dispatch( - new GetAllContributors(action.resourceId, action.resourceType, nextPage, state.contributorsList.pageSize) - ); + return ctx.dispatch(new GetAllContributors(action.resourceId, action.resourceType, nextPage, nextPageSize)); } @Action(ResetContributorsState) From bf823591a319149999e4712054cac3d74b4310ae Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 23 Oct 2025 16:50:59 +0300 Subject: [PATCH 5/5] fix(tests): updated unit tests --- jest.config.js | 8 +++---- .../features/metadata/metadata.component.ts | 2 +- .../general-information.component.spec.ts | 24 +++++++------------ .../general-information.component.ts | 2 +- .../preprint-tombstone.component.spec.ts | 18 +++++--------- .../preprint-tombstone.component.ts | 2 +- .../review-step/review-step.component.spec.ts | 14 +++-------- .../review-step/review-step.component.ts | 2 +- .../overview/project-overview.component.ts | 2 +- .../registries-contributors.component.spec.ts | 9 +++---- .../registry-overview.component.ts | 2 +- .../shared/mappers/view-only-links.mapper.ts | 4 ++-- .../contributors/contributors.selectors.ts | 9 ------- 13 files changed, 32 insertions(+), 66 deletions(-) diff --git a/jest.config.js b/jest.config.js index ecdfa34e0..f6ee835f3 100644 --- a/jest.config.js +++ b/jest.config.js @@ -50,10 +50,10 @@ module.exports = { extensionsToTreatAsEsm: ['.ts'], coverageThreshold: { global: { - branches: 24.1, - functions: 28.73, - lines: 56.52, - statements: 56.82, + branches: 29.01, + functions: 32.75, + lines: 60.28, + statements: 60.77, }, }, watchPathIgnorePatterns: [ diff --git a/src/app/features/metadata/metadata.component.ts b/src/app/features/metadata/metadata.component.ts index 2ff53aa56..c1ef63a77 100644 --- a/src/app/features/metadata/metadata.component.ts +++ b/src/app/features/metadata/metadata.component.ts @@ -125,7 +125,7 @@ export class MetadataComponent implements OnInit { metadata = select(MetadataSelectors.getResourceMetadata); isMetadataLoading = select(MetadataSelectors.getLoading); customItemMetadata = select(MetadataSelectors.getCustomItemMetadata); - bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributors); isContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); hasMoreContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); cedarRecords = select(MetadataSelectors.getCedarRecords); diff --git a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.spec.ts b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.spec.ts index e1e4de9c4..c5e129de1 100644 --- a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.spec.ts +++ b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.spec.ts @@ -47,9 +47,7 @@ describe('GeneralInformationComponent', () => { ), ], providers: [ - MockProvider(ENVIRONMENT, { - webUrl: mockWebUrl, - }), + MockProvider(ENVIRONMENT, { webUrl: mockWebUrl }), provideMockStore({ signals: [ { @@ -61,11 +59,15 @@ describe('GeneralInformationComponent', () => { value: false, }, { - selector: ContributorsSelectors.getContributors, + selector: ContributorsSelectors.getBibliographicContributors, value: mockContributors, }, { - selector: ContributorsSelectors.isContributorsLoading, + selector: ContributorsSelectors.isBibliographicContributorsLoading, + value: false, + }, + { + selector: ContributorsSelectors.hasMoreBibliographicContributors, value: false, }, { @@ -83,26 +85,16 @@ describe('GeneralInformationComponent', () => { fixture.componentRef.setInput('preprintProvider', mockPreprintProvider); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - it('should return preprint from store', () => { const preprint = component.preprint(); expect(preprint).toBe(mockPreprint); }); it('should return contributors from store', () => { - const contributors = component.contributors(); + const contributors = component.bibliographicContributors(); expect(contributors).toBe(mockContributors); }); - it('should filter bibliographic contributors', () => { - const bibliographicContributors = component.bibliographicContributors(); - expect(bibliographicContributors).toHaveLength(1); - expect(bibliographicContributors.every((contributor) => contributor.isBibliographic)).toBe(true); - }); - it('should return affiliated institutions from store', () => { const institutions = component.affiliatedInstitutions(); expect(institutions).toBe(mockInstitutions); diff --git a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts index a710da82b..b2af64189 100644 --- a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts +++ b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts @@ -69,7 +69,7 @@ export class GeneralInformationComponent implements OnDestroy { affiliatedInstitutions = select(InstitutionsSelectors.getResourceInstitutions); - bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributors); areContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); diff --git a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.spec.ts b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.spec.ts index ecd1053a5..be2c331e4 100644 --- a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.spec.ts +++ b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.spec.ts @@ -50,11 +50,15 @@ describe('PreprintTombstoneComponent', () => { value: false, }, { - selector: ContributorsSelectors.getContributors, + selector: ContributorsSelectors.getBibliographicContributors, value: mockContributors, }, { - selector: ContributorsSelectors.isContributorsLoading, + selector: ContributorsSelectors.isBibliographicContributorsLoading, + value: false, + }, + { + selector: ContributorsSelectors.hasMoreBibliographicContributors, value: false, }, { @@ -76,16 +80,6 @@ describe('PreprintTombstoneComponent', () => { fixture.componentRef.setInput('preprintProvider', mockProvider); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should compute bibliographic contributors', () => { - const bibliographicContributors = component.bibliographicContributors(); - expect(bibliographicContributors).toHaveLength(1); - expect(bibliographicContributors[0].isBibliographic).toBe(true); - }); - it('should compute license from preprint', () => { const license = component.license(); expect(license).toBe(mockPreprint.embeddedLicense); diff --git a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts index b08c9c46c..bb410923c 100644 --- a/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts +++ b/src/app/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component.ts @@ -69,7 +69,7 @@ export class PreprintTombstoneComponent implements OnDestroy { preprint = select(PreprintSelectors.getPreprint); isPreprintLoading = select(PreprintSelectors.isPreprintLoading); - bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributors); areContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); subjects = select(SubjectsSelectors.getSelectedSubjects); diff --git a/src/app/features/preprints/components/stepper/review-step/review-step.component.spec.ts b/src/app/features/preprints/components/stepper/review-step/review-step.component.spec.ts index 16530d553..335b27a9f 100644 --- a/src/app/features/preprints/components/stepper/review-step/review-step.component.spec.ts +++ b/src/app/features/preprints/components/stepper/review-step/review-step.component.spec.ts @@ -52,7 +52,9 @@ describe('ReviewStepComponent', () => { { selector: PreprintStepperSelectors.isPreprintSubmitting, value: false }, { selector: PreprintStepperSelectors.getPreprintLicense, value: mockLicense }, { selector: PreprintStepperSelectors.getPreprintProject, value: mockPreprintProject }, - { selector: ContributorsSelectors.getContributors, value: mockContributors }, + { selector: ContributorsSelectors.getBibliographicContributors, value: mockContributors }, + { selector: ContributorsSelectors.isBibliographicContributorsLoading, value: false }, + { selector: ContributorsSelectors.hasMoreBibliographicContributors, value: false }, { selector: SubjectsSelectors.getSelectedSubjects, value: mockSubjects }, { selector: InstitutionsSelectors.getResourceInstitutions, value: mockInstitutions }, ], @@ -68,20 +70,10 @@ describe('ReviewStepComponent', () => { fixture.componentRef.setInput('provider', mockProvider); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - it('should have required provider input', () => { expect(component.provider()).toEqual(mockProvider); }); - it('should filter bibliographic contributors', () => { - const bibliographicContributors = component.bibliographicContributors(); - expect(bibliographicContributors).toHaveLength(1); - expect(bibliographicContributors.every((c) => c.isBibliographic)).toBe(true); - }); - it('should create license options record', () => { const licenseOptionsRecord = component.licenseOptionsRecord(); expect(licenseOptionsRecord).toEqual({ copyrightHolders: 'John Doe', year: '2023' }); diff --git a/src/app/features/preprints/components/stepper/review-step/review-step.component.ts b/src/app/features/preprints/components/stepper/review-step/review-step.component.ts index 363f6e90d..7c277d1d5 100644 --- a/src/app/features/preprints/components/stepper/review-step/review-step.component.ts +++ b/src/app/features/preprints/components/stepper/review-step/review-step.component.ts @@ -83,7 +83,7 @@ export class ReviewStepComponent implements OnInit { preprintFile = select(PreprintStepperSelectors.getPreprintFile); isPreprintSubmitting = select(PreprintStepperSelectors.isPreprintSubmitting); - bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributors); areContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); subjects = select(SubjectsSelectors.getSelectedSubjects); diff --git a/src/app/features/project/overview/project-overview.component.ts b/src/app/features/project/overview/project-overview.component.ts index 33d007bf8..f53edbfc8 100644 --- a/src/app/features/project/overview/project-overview.component.ts +++ b/src/app/features/project/overview/project-overview.component.ts @@ -143,7 +143,7 @@ export class ProjectOverviewComponent implements OnInit { isWikiEnabled = select(ProjectOverviewSelectors.isWikiEnabled); parentProject = select(ProjectOverviewSelectors.getParentProject); isParentProjectLoading = select(ProjectOverviewSelectors.getParentProjectLoading); - bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributors); isBibliographicContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); addonsResourceReference = select(AddonsSelectors.getAddonsResourceReference); diff --git a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.spec.ts b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.spec.ts index 35d007b66..bbef5fbd3 100644 --- a/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.spec.ts +++ b/src/app/features/registries/components/registries-metadata-step/registries-contributors/registries-contributors.component.spec.ts @@ -9,8 +9,8 @@ import { ActivatedRoute } from '@angular/router'; import { UserSelectors } from '@core/store/user'; import { ResourceType } from '@osf/shared/enums'; import { CustomConfirmationService, CustomDialogService, ToastService } from '@osf/shared/services'; -import { ContributorsSelectors } from '@osf/shared/stores'; -import { ContributorsTableComponent } from '@shared/components/contributors'; +import { ContributorsSelectors } from '@osf/shared/stores/contributors/contributors.selectors'; +import { ContributorsTableComponent } from '@shared/components/contributors/contributors-table/contributors-table.component'; import { RegistriesContributorsComponent } from './registries-contributors.component'; @@ -77,15 +77,12 @@ describe('RegistriesContributorsComponent', () => { deleteContributor: jest.fn().mockReturnValue(of({})), bulkUpdateContributors: jest.fn().mockReturnValue(of({})), bulkAddContributors: jest.fn().mockReturnValue(of({})), + resetContributorsState: jest.fn().mockRejectedValue(of({})), } as any; Object.defineProperty(component, 'actions', { value: mockActions }); fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - it('should request contributors on init', () => { const actions = (component as any).actions; expect(actions.getContributors).toHaveBeenCalledWith('draft-1', ResourceType.DraftRegistration); diff --git a/src/app/features/registry/pages/registry-overview/registry-overview.component.ts b/src/app/features/registry/pages/registry-overview/registry-overview.component.ts index fafecac24..7df422947 100644 --- a/src/app/features/registry/pages/registry-overview/registry-overview.component.ts +++ b/src/app/features/registry/pages/registry-overview/registry-overview.component.ts @@ -97,7 +97,7 @@ export class RegistryOverviewComponent { readonly areReviewActionsLoading = select(RegistryOverviewSelectors.areReviewActionsLoading); readonly currentRevision = select(RegistriesSelectors.getSchemaResponse); readonly isSchemaResponseLoading = select(RegistriesSelectors.getSchemaResponseLoading); - bibliographicContributors = select(ContributorsSelectors.getBibliographicContributorsList); + bibliographicContributors = select(ContributorsSelectors.getBibliographicContributors); isBibliographicContributorsLoading = select(ContributorsSelectors.isBibliographicContributorsLoading); hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors); diff --git a/src/app/shared/mappers/view-only-links.mapper.ts b/src/app/shared/mappers/view-only-links.mapper.ts index a168611b2..3d56a1c4d 100644 --- a/src/app/shared/mappers/view-only-links.mapper.ts +++ b/src/app/shared/mappers/view-only-links.mapper.ts @@ -24,7 +24,7 @@ export class ViewOnlyLinksMapper { id: creator?.id || '', fullName: creator?.fullName || '', }, - nodes: item.embeds.nodes.data.map( + nodes: item.embeds?.nodes?.data?.map( (node) => ({ id: node.id, @@ -59,7 +59,7 @@ export class ViewOnlyLinksMapper { id: creator?.id || '', fullName: creator?.fullName || '', }, - nodes: item.embeds.nodes.data.map( + nodes: item.embeds?.nodes?.data?.map( (node) => ({ id: node.id, diff --git a/src/app/shared/stores/contributors/contributors.selectors.ts b/src/app/shared/stores/contributors/contributors.selectors.ts index ff3844d74..57f026482 100644 --- a/src/app/shared/stores/contributors/contributors.selectors.ts +++ b/src/app/shared/stores/contributors/contributors.selectors.ts @@ -30,15 +30,6 @@ export class ContributorsSelectors { @Selector([ContributorsState]) static getBibliographicContributors(state: ContributorsStateModel) { - if (!state?.contributorsList?.data) { - return []; - } - - return state.contributorsList.data.filter((contributor) => contributor.isBibliographic); - } - - @Selector([ContributorsState]) - static getBibliographicContributorsList(state: ContributorsStateModel) { if (!state?.bibliographicContributorsList?.data) { return []; }