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 cee666a6f..a993ab77f 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 @@ -1,11 +1,13 @@

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

-
- - {{ 'preprints.preprintContributorsWarning' | translate }} - -
+ @if (hasAdminAccess()) { +
+ + {{ 'preprints.preprintContributorsWarning' | translate }} + +
+ } {{ 'common.labels.contributors' | translate }} [isLoading]="isContributorsLoading()" [showLoadMore]="hasMoreContributors()" [isLoadingMore]="isLoadingMore()" + [hasAdminAccess]="hasAdminAccess()" (remove)="removeContributor($event)" (loadMore)="loadMoreContributors()" /> -
- @if (hasChanges) { -
- - -
- } - -
+ @if (hasAdminAccess()) { +
+ @if (hasChanges) { +
+ + +
+ } + +
+ }
diff --git a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts index 3dc5a0070..2126f6615 100644 --- a/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts @@ -1,11 +1,12 @@ import { Store } from '@ngxs/store'; -import { MockComponent, MockProvider } from 'ng-mocks'; +import { MockComponent, MockProvider, ngMocks } from 'ng-mocks'; import { of } from 'rxjs'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PreprintStepperSelectors } from '@osf/features/preprints/store/preprint-stepper'; import { ContributorsTableComponent } from '@osf/shared/components/contributors/contributors-table/contributors-table.component'; import { AddContributorType } from '@osf/shared/enums/contributors/add-contributor-type.enum'; import { ResourceType } from '@osf/shared/enums/resource-type.enum'; @@ -49,6 +50,7 @@ describe('PreprintsContributorsComponent', () => { { selector: ContributorsSelectors.isContributorsLoadingMore, value: false }, { selector: ContributorsSelectors.getContributorsPageSize, value: 10 }, { selector: ContributorsSelectors.getContributorsTotalCount, value: 1 }, + { selector: PreprintStepperSelectors.hasAdminAccess, value: true }, ]; function setup(overrides?: { @@ -109,6 +111,24 @@ describe('PreprintsContributorsComponent', () => { expect(component.contributors()).not.toBe(mockContributors); }); + it('should allow admin to manage contributors', () => { + setup(); + + expect(ngMocks.input(ngMocks.find(ContributorsTableComponent), 'hasAdminAccess')).toBe(true); + expect(fixture.nativeElement.querySelector('p-message')).toBeTruthy(); + expect(fixture.nativeElement.querySelectorAll('p-button').length).toBe(1); + }); + + it('should show contributors as read-only without admin access', () => { + setup({ selectorOverrides: [{ selector: PreprintStepperSelectors.hasAdminAccess, value: false }] }); + component.contributors.set([{ ...MOCK_CONTRIBUTOR, fullName: 'Updated Name' }]); + fixture.detectChanges(); + + expect(ngMocks.input(ngMocks.find(ContributorsTableComponent), 'hasAdminAccess')).toBe(false); + expect(fixture.nativeElement.querySelector('p-message')).toBeNull(); + expect(fixture.nativeElement.querySelectorAll('p-button').length).toBe(0); + }); + it('should compute hasChanges correctly', () => { setup(); expect(component.hasChanges).toBe(false); 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 e36795893..64fa98966 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 @@ -21,6 +21,7 @@ import { } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { PreprintStepperSelectors } from '@osf/features/preprints/store/preprint-stepper'; import { AddContributorDialogComponent } from '@osf/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component'; import { AddUnregisteredContributorDialogComponent } from '@osf/shared/components/contributors/add-unregistered-contributor-dialog/add-unregistered-contributor-dialog.component'; import { ContributorsTableComponent } from '@osf/shared/components/contributors/contributors-table/contributors-table.component'; @@ -65,6 +66,7 @@ export class PreprintsContributorsComponent implements OnInit { readonly hasMoreContributors = select(ContributorsSelectors.hasMoreContributors); readonly isLoadingMore = select(ContributorsSelectors.isContributorsLoadingMore); readonly pageSize = select(ContributorsSelectors.getContributorsPageSize); + readonly hasAdminAccess = select(PreprintStepperSelectors.hasAdminAccess); readonly actions = createDispatchMap({ getContributors: GetAllContributors, diff --git a/src/app/features/preprints/pages/preprint-details/preprint-details.component.spec.ts b/src/app/features/preprints/pages/preprint-details/preprint-details.component.spec.ts index b23e85952..797584cc3 100644 --- a/src/app/features/preprints/pages/preprint-details/preprint-details.component.spec.ts +++ b/src/app/features/preprints/pages/preprint-details/preprint-details.component.spec.ts @@ -49,7 +49,7 @@ import { PreprintTombstoneComponent } from '../../components/preprint-details/pr import { PreprintWarningBannerComponent } from '../../components/preprint-details/preprint-warning-banner/preprint-warning-banner.component'; import { ShareAndDownloadComponent } from '../../components/preprint-details/share-and-download/share-and-download.component'; import { StatusBannerComponent } from '../../components/preprint-details/status-banner/status-banner.component'; -import { ReviewsState } from '../../enums'; +import { ProviderReviewsWorkflow, ReviewsState } from '../../enums'; import { FetchPreprintDetails, FetchPreprintRequestActions, @@ -407,6 +407,68 @@ describe('PreprintDetailsComponent', () => { expect(component.editButtonVisible()).toBe(true); }); + it('should show edit button for previous version of preprint', () => { + setup({ + selectorOverrides: [ + { + selector: PreprintSelectors.getPreprint, + value: { ...mockPreprint, isLatestVersion: false, reviewsState: ReviewsState.Accepted }, + }, + ], + }); + + expect(component.editButtonVisible()).toBe(true); + }); + + it('should show edit button for previous version of postmoderation preprint', () => { + setup({ + selectorOverrides: [ + { + selector: PreprintProvidersSelectors.getPreprintProviderDetails('osf'), + value: { ...mockProvider, reviewsWorkflow: ProviderReviewsWorkflow.PostModeration }, + }, + { + selector: PreprintSelectors.getPreprint, + value: { ...mockPreprint, isLatestVersion: false, reviewsState: ReviewsState.Accepted }, + }, + ], + }); + + expect(component.editButtonVisible()).toBe(true); + }); + + it('should hide edit button for previous version when user does not have write access', () => { + setup({ + selectorOverrides: [ + { + selector: PreprintSelectors.getPreprint, + value: { ...mockPreprint, isLatestVersion: false, reviewsState: ReviewsState.Accepted }, + }, + { selector: PreprintSelectors.hasWriteAccess, value: false }, + ], + }); + + expect(component.editButtonVisible()).toBe(false); + }); + + it('should hide edit button for withdrawn previous version', () => { + setup({ + selectorOverrides: [ + { + selector: PreprintSelectors.getPreprint, + value: { + ...mockPreprint, + isLatestVersion: false, + reviewsState: ReviewsState.Withdrawn, + dateWithdrawn: '2024-01-01', + }, + }, + ], + }); + + expect(component.editButtonVisible()).toBe(false); + }); + it('should show edit button for pending premoderation preprint', () => { setup({ selectorOverrides: [ diff --git a/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts b/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts index 97cc4f9ed..a3083d392 100644 --- a/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts +++ b/src/app/features/preprints/pages/preprint-details/preprint-details.component.ts @@ -223,7 +223,7 @@ export class PreprintDetailsComponent implements OnInit, OnDestroy { } } - return false; + return !preprintIsRejected; }); editButtonLabel = computed(() => {