From 100e56c97d60ecdf012672c20cdaa001558554b7 Mon Sep 17 00:00:00 2001 From: nsemets Date: Tue, 23 Sep 2025 10:51:33 +0300 Subject: [PATCH 1/5] fix(contributors): added reorder contributors --- .../project-contributors-step.component.html | 2 +- .../project-contributors-step.component.ts | 31 +++++----- .../contributors-dialog.component.html | 2 +- .../contributors-dialog.component.ts | 17 +++-- .../contributors/contributors.component.html | 2 +- .../contributors/contributors.component.ts | 24 +++---- .../select-preprint-service.component.html | 6 +- .../contributors/contributors.component.html | 2 +- .../contributors/contributors.component.ts | 28 ++++----- .../registries-contributors.component.html | 2 +- .../registries-contributors.component.ts | 17 +++-- .../contributors-list.component.html | 13 +++- .../contributors-list.component.spec.ts | 1 + .../contributors-list.component.ts | 22 ++++++- .../contributors/contributors.mapper.ts | 3 + .../contributors/contributor-add.model.ts | 1 + .../contributor-response.model.ts | 1 + .../models/contributors/contributor.model.ts | 1 + .../shared/services/contributors.service.ts | 30 ++++++--- .../contributors/contributors.actions.ts | 6 +- .../stores/contributors/contributors.state.ts | 62 ++++++++----------- 21 files changed, 156 insertions(+), 117 deletions(-) diff --git a/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.html b/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.html index f0715c95f..3e594518d 100644 --- a/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.html +++ b/src/app/features/collections/components/add-to-collection/project-contributors-step/project-contributors-step.component.html @@ -39,7 +39,7 @@

{{ 'collections.addToCollection.projectContributors' | translate }}

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 dfa1bad79..a9b3c1c7a 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 @@ -25,10 +25,10 @@ import { ContributorDialogAddModel, ContributorModel } from '@osf/shared/models' import { CustomConfirmationService, ToastService } from '@osf/shared/services'; import { AddContributor, + BulkUpdateContributors, ContributorsSelectors, DeleteContributor, ProjectsSelectors, - UpdateContributor, } from '@osf/shared/stores'; @Component({ @@ -46,11 +46,11 @@ export class ProjectContributorsStepComponent { private readonly toastService = inject(ToastService); private readonly customConfirmationService = inject(CustomConfirmationService); - readonly projectContributors = select(ContributorsSelectors.getContributors); readonly isContributorsLoading = select(ContributorsSelectors.isContributorsLoading); readonly selectedProject = select(ProjectsSelectors.getSelectedProject); - private initialContributors = signal([]); + private initialContributors = select(ContributorsSelectors.getContributors); + readonly projectContributors = signal([]); stepperActiveValue = input.required(); targetStepValue = input.required(); @@ -62,7 +62,7 @@ export class ProjectContributorsStepComponent { actions = createDispatchMap({ addContributor: AddContributor, - updateContributor: UpdateContributor, + bulkUpdateContributors: BulkUpdateContributors, deleteContributor: DeleteContributor, }); @@ -103,17 +103,16 @@ export class ProjectContributorsStepComponent { const updatedContributors = findChangedItems(this.initialContributors(), this.projectContributors(), 'id'); if (!updatedContributors.length) { - this.initialContributors.set(JSON.parse(JSON.stringify(this.projectContributors()))); + this.projectContributors.set(JSON.parse(JSON.stringify(this.initialContributors()))); this.contributorsSaved.emit(); } else { - const updateRequests = updatedContributors.map((payload) => - this.actions.updateContributor(this.selectedProject()?.id, ResourceType.Project, payload) - ); - forkJoin(updateRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage'); - this.initialContributors.set(JSON.parse(JSON.stringify(this.projectContributors()))); - this.contributorsSaved.emit(); - }); + this.actions + .bulkUpdateContributors(this.selectedProject()?.id, ResourceType.Project, updatedContributors) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage'); + this.contributorsSaved.emit(); + }); } } else { this.contributorsSaved.emit(); @@ -186,10 +185,10 @@ export class ProjectContributorsStepComponent { private setupEffects(): void { effect(() => { const isMetadataSaved = this.isProjectMetadataSaved(); - const contributors = this.projectContributors(); + const contributors = this.initialContributors(); - if (isMetadataSaved && contributors.length && !this.initialContributors().length) { - this.initialContributors.set(JSON.parse(JSON.stringify(contributors))); + if (isMetadataSaved && contributors.length && !this.projectContributors().length) { + this.projectContributors.set(JSON.parse(JSON.stringify(contributors))); } }); } 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 3953d23fa..8ee523b93 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 @@ -18,7 +18,7 @@

{{ 'project.contributors.addContributor' | translate }}

- this.actions.updateContributor(this.resourceId, this.resourceType, payload) - ); - - forkJoin(updateRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage'); - }); + this.actions + .bulkUpdateContributors(this.resourceId, this.resourceType, updatedContributors) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage') + ); } } diff --git a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.html b/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.html index 5db80a58c..06c78577c 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.html +++ b/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.html @@ -9,7 +9,7 @@

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

{ - return contributor.userId === currentUserId && contributor.permission === ContributorPermission.Admin; - }); + return initialContributors.some( + (contributor: ContributorModel) => + contributor.userId === currentUserId && contributor.permission === ContributorPermission.Admin + ); }); actions = createDispatchMap({ getContributors: GetAllContributors, deleteContributor: DeleteContributor, - updateContributor: UpdateContributor, + bulkUpdateContributors: BulkUpdateContributors, addContributor: AddContributor, }); @@ -102,13 +103,12 @@ export class ContributorsComponent implements OnInit { save() { const updatedContributors = findChangedItems(this.initialContributors(), this.contributors(), 'id'); - const updateRequests = updatedContributors.map((payload) => - this.actions.updateContributor(this.preprintId(), ResourceType.Preprint, payload) - ); - - forkJoin(updateRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage'); - }); + this.actions + .bulkUpdateContributors(this.preprintId(), ResourceType.Preprint, updatedContributors) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage') + ); } openAddContributorDialog() { diff --git a/src/app/features/preprints/pages/select-preprint-service/select-preprint-service.component.html b/src/app/features/preprints/pages/select-preprint-service/select-preprint-service.component.html index 50aa02379..3bc727057 100644 --- a/src/app/features/preprints/pages/select-preprint-service/select-preprint-service.component.html +++ b/src/app/features/preprints/pages/select-preprint-service/select-preprint-service.component.html @@ -6,10 +6,12 @@

{{ 'preprints.selectService.sectionTitle' | translate }}

{{ 'preprints.selectService.description' | translate }} - + + {{ 'preprints.selectService.learnMore' | translate }}

+
@if (areProvidersLoading()) { @for (_ of skeletonArray; track $index) { @@ -51,12 +53,14 @@

{{ provider.name }}

/>
+
} } +
{{ 'navigation.contributors' | translate } - this.actions.updateContributor(this.resourceId(), this.resourceType(), payload) - ); - - forkJoin(updateRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage'); - }); + this.actions + .bulkUpdateContributors(this.resourceId(), this.resourceType(), updatedContributors) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage') + ); } openAddContributorDialog() { @@ -271,12 +270,11 @@ export class ContributorsComponent implements OnInit { this.actions .deleteContributor(this.resourceId(), this.resourceType(), contributor.userId) .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe({ - next: () => - this.toastService.showSuccess('project.contributors.removeDialog.successMessage', { - name: contributor.fullName, - }), - }); + .subscribe(() => + this.toastService.showSuccess('project.contributors.removeDialog.successMessage', { + name: contributor.fullName, + }) + ); }, }); } 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 0e1864b7c..468e0840e 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 @@ -3,7 +3,7 @@

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

- this.actions.updateContributor(this.draftId(), ResourceType.DraftRegistration, payload) - ); - - forkJoin(updateRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage'); - }); + this.actions + .bulkUpdateContributors(this.draftId(), ResourceType.DraftRegistration, updatedContributors) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleUpdateSuccessMessage') + ); } openAddContributorDialog() { diff --git a/src/app/shared/components/contributors/contributors-list/contributors-list.component.html b/src/app/shared/components/contributors/contributors-list/contributors-list.component.html index 8b542f9c8..e69311aea 100644 --- a/src/app/shared/components/contributors/contributors-list/contributors-list.component.html +++ b/src/app/shared/components/contributors/contributors-list/contributors-list.component.html @@ -9,10 +9,13 @@ [lazy]="true" [lazyLoadOnInit]="true" [customSort]="true" + [reorderableColumns]="true" + (onRowReorder)="onRowReorder()" class="view-only-table" > + {{ 'project.contributors.table.headers.name' | translate }}
@@ -93,9 +96,15 @@

{{ 'project.contributors.curatorInfo.heading' | translate }}

- + @if (contributor.id) { - + + +
+ +
+ +

{{ contributor.fullName }} diff --git a/src/app/shared/components/contributors/contributors-list/contributors-list.component.spec.ts b/src/app/shared/components/contributors/contributors-list/contributors-list.component.spec.ts index 9c0705668..fdee198cb 100644 --- a/src/app/shared/components/contributors/contributors-list/contributors-list.component.spec.ts +++ b/src/app/shared/components/contributors/contributors-list/contributors-list.component.spec.ts @@ -132,6 +132,7 @@ describe('ContributorsListComponent', () => { fullName: 'Minimal User', givenName: 'Minimal User', familyName: 'Minimal User', + index: 0, permission: ContributorPermission.Read, education: [], employment: [], diff --git a/src/app/shared/components/contributors/contributors-list/contributors-list.component.ts b/src/app/shared/components/contributors/contributors-list/contributors-list.component.ts index 72e7f96c3..f51315cff 100644 --- a/src/app/shared/components/contributors/contributors-list/contributors-list.component.ts +++ b/src/app/shared/components/contributors/contributors-list/contributors-list.component.ts @@ -7,7 +7,7 @@ import { Skeleton } from 'primeng/skeleton'; import { TableModule } from 'primeng/table'; import { Tooltip } from 'primeng/tooltip'; -import { ChangeDetectionStrategy, Component, computed, inject, input, output, signal } from '@angular/core'; +import { ChangeDetectionStrategy, Component, computed, inject, input, model, output, signal } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { ModeratorPermission } from '@osf/features/moderation/enums'; @@ -17,18 +17,29 @@ import { ContributorPermission } from '@shared/enums'; import { EducationHistoryDialogComponent } from '../../education-history-dialog/education-history-dialog.component'; import { EmploymentHistoryDialogComponent } from '../../employment-history-dialog/employment-history-dialog.component'; +import { IconComponent } from '../../icon/icon.component'; import { SelectComponent } from '../../select/select.component'; @Component({ selector: 'osf-contributors-list', - imports: [TranslatePipe, FormsModule, TableModule, Tooltip, Checkbox, Skeleton, Button, SelectComponent], + imports: [ + TranslatePipe, + FormsModule, + TableModule, + Tooltip, + Checkbox, + Skeleton, + Button, + SelectComponent, + IconComponent, + ], templateUrl: './contributors-list.component.html', styleUrl: './contributors-list.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], }) export class ContributorsListComponent { - contributors = input([]); + contributors = model([]); isLoading = input(false); showCurator = input(false); showEducation = input(true); @@ -93,4 +104,9 @@ export class ContributorsListComponent { closable: true, }); } + + onRowReorder() { + const reorderedContributors = this.contributors().map((item, i) => ({ ...item, index: i })); + this.contributors.set(reorderedContributors); + } } diff --git a/src/app/shared/mappers/contributors/contributors.mapper.ts b/src/app/shared/mappers/contributors/contributors.mapper.ts index 505c81865..49d7af4af 100644 --- a/src/app/shared/mappers/contributors/contributors.mapper.ts +++ b/src/app/shared/mappers/contributors/contributors.mapper.ts @@ -18,6 +18,7 @@ export class ContributorsMapper { isBibliographic: contributor.attributes.bibliographic, isUnregisteredContributor: !!contributor.attributes.unregistered_contributor, isCurator: contributor.attributes.is_curator, + index: contributor.attributes.index, permission: contributor.attributes.permission, fullName: contributor.embeds?.users?.data?.attributes?.full_name || '', givenName: contributor.embeds?.users?.data?.attributes?.given_name || '', @@ -53,6 +54,7 @@ export class ContributorsMapper { isCurator: response.attributes.is_curator, isUnregisteredContributor: !!response.attributes.unregistered_contributor, permission: response.attributes.permission, + index: response.attributes.index, fullName: response.embeds.users.data.attributes.full_name, givenName: response.embeds.users.data.attributes.given_name, familyName: response.embeds.users.data.attributes.family_name, @@ -71,6 +73,7 @@ export class ContributorsMapper { attributes: { bibliographic: model.isBibliographic, permission: model.permission, + index: model.index, id: model.id, }, relationships: { diff --git a/src/app/shared/models/contributors/contributor-add.model.ts b/src/app/shared/models/contributors/contributor-add.model.ts index e7988c070..31bc3bf35 100644 --- a/src/app/shared/models/contributors/contributor-add.model.ts +++ b/src/app/shared/models/contributors/contributor-add.model.ts @@ -4,4 +4,5 @@ export interface ContributorAddModel { permission: string; fullName?: string; email?: string; + index?: number; } diff --git a/src/app/shared/models/contributors/contributor-response.model.ts b/src/app/shared/models/contributors/contributor-response.model.ts index 1c77d8d86..d779d726f 100644 --- a/src/app/shared/models/contributors/contributor-response.model.ts +++ b/src/app/shared/models/contributors/contributor-response.model.ts @@ -28,6 +28,7 @@ export interface ContributorAddRequestModel { id?: string; full_name?: string; email?: string; + index?: number; }; relationships: { users?: { diff --git a/src/app/shared/models/contributors/contributor.model.ts b/src/app/shared/models/contributors/contributor.model.ts index 13357be30..0cb0648e6 100644 --- a/src/app/shared/models/contributors/contributor.model.ts +++ b/src/app/shared/models/contributors/contributor.model.ts @@ -9,6 +9,7 @@ export interface ContributorModel { isUnregisteredContributor: boolean; isCurator: boolean; permission: ContributorPermission; + index: number; fullName: string; givenName: string; familyName: string; diff --git a/src/app/shared/services/contributors.service.ts b/src/app/shared/services/contributors.service.ts index 9562d89d3..ee4552e3c 100644 --- a/src/app/shared/services/contributors.service.ts +++ b/src/app/shared/services/contributors.service.ts @@ -1,4 +1,4 @@ -import { map, Observable } from 'rxjs'; +import { forkJoin, map, Observable, of } from 'rxjs'; import { inject, Injectable } from '@angular/core'; @@ -77,6 +77,28 @@ export class ContributorsService { .pipe(map((contributor) => ContributorsMapper.fromContributorResponse(contributor.data))); } + deleteContributor(resourceType: ResourceType, resourceId: string, userId: string): Observable { + const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/${userId}/`; + + return this.jsonApiService.delete(baseUrl); + } + + bulkUpdateContributors( + resourceType: ResourceType, + resourceId: string, + contributors: ContributorModel[] + ): Observable { + if (contributors.length === 0) { + return of([]); + } + + const updateRequests = contributors.map((contributor) => + this.updateContributor(resourceType, resourceId, contributor) + ); + + return forkJoin(updateRequests); + } + updateContributor( resourceType: ResourceType, resourceId: string, @@ -90,10 +112,4 @@ export class ContributorsService { .patch(baseUrl, contributorData) .pipe(map((contributor) => ContributorsMapper.fromContributorResponse(contributor))); } - - deleteContributor(resourceType: ResourceType, resourceId: string, userId: string): Observable { - const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/${userId}/`; - - return this.jsonApiService.delete(baseUrl); - } } diff --git a/src/app/shared/stores/contributors/contributors.actions.ts b/src/app/shared/stores/contributors/contributors.actions.ts index d93e9c89b..8741945d8 100644 --- a/src/app/shared/stores/contributors/contributors.actions.ts +++ b/src/app/shared/stores/contributors/contributors.actions.ts @@ -38,13 +38,13 @@ export class AddContributor { ) {} } -export class UpdateContributor { - static readonly type = '[Contributors] Update Contributor'; +export class BulkUpdateContributors { + static readonly type = '[Contributors] Bulk Update Contributors'; constructor( public resourceId: string | undefined | null, public resourceType: ResourceType | undefined, - public contributor: ContributorModel + public contributors: ContributorModel[] ) {} } diff --git a/src/app/shared/stores/contributors/contributors.state.ts b/src/app/shared/stores/contributors/contributors.state.ts index bfd7558d2..81b0f5906 100644 --- a/src/app/shared/stores/contributors/contributors.state.ts +++ b/src/app/shared/stores/contributors/contributors.state.ts @@ -9,13 +9,13 @@ import { ContributorsService } from '@osf/shared/services'; import { AddContributor, + BulkUpdateContributors, ClearUsers, DeleteContributor, GetAllContributors, ResetContributorsState, SearchUsers, UpdateBibliographyFilter, - UpdateContributor, UpdateContributorsSearchValue, UpdatePermissionFilter, } from './contributors.actions'; @@ -33,14 +33,14 @@ export class ContributorsState { getAllContributors(ctx: StateContext, action: GetAllContributors) { const state = ctx.getState(); - ctx.patchState({ - contributorsList: { ...state.contributorsList, data: [], isLoading: true, error: null }, - }); - if (!action.resourceId || !action.resourceType) { return; } + ctx.patchState({ + contributorsList: { ...state.contributorsList, data: [], isLoading: true, error: null }, + }); + return this.contributorsService.getAllContributors(action.resourceType, action.resourceId).pipe( tap((contributors) => { ctx.patchState({ @@ -59,14 +59,14 @@ export class ContributorsState { addContributor(ctx: StateContext, action: AddContributor) { const state = ctx.getState(); - ctx.patchState({ - contributorsList: { ...state.contributorsList, isLoading: true, error: null }, - }); - if (!action.resourceId || !action.resourceType) { return; } + ctx.patchState({ + contributorsList: { ...state.contributorsList, isLoading: true, error: null }, + }); + return this.contributorsService.addContributor(action.resourceType, action.resourceId, action.contributor).pipe( tap((contributor) => { const currentState = ctx.getState(); @@ -83,48 +83,40 @@ export class ContributorsState { ); } - @Action(UpdateContributor) - updateContributor(ctx: StateContext, action: UpdateContributor) { + @Action(BulkUpdateContributors) + bulkUpdateContributors(ctx: StateContext, action: BulkUpdateContributors) { const state = ctx.getState(); - ctx.patchState({ - contributorsList: { ...state.contributorsList, isLoading: true, error: null }, - }); - - if (!action.resourceId || !action.resourceType) { + if (!action.resourceId || !action.resourceType || !action.contributors.length) { return; } - return this.contributorsService.updateContributor(action.resourceType, action.resourceId, action.contributor).pipe( - tap((updatedContributor) => { - const currentState = ctx.getState(); + ctx.patchState({ + contributorsList: { ...state.contributorsList, isLoading: true, error: null }, + }); - ctx.patchState({ - contributorsList: { - ...currentState.contributorsList, - data: currentState.contributorsList.data.map((contributor) => - contributor.id === updatedContributor.id ? updatedContributor : contributor - ), - isLoading: false, - }, - }); - }), - catchError((error) => handleSectionError(ctx, 'contributorsList', error)) - ); + return this.contributorsService + .bulkUpdateContributors(action.resourceType, action.resourceId, action.contributors) + .pipe( + tap(() => { + ctx.dispatch(new GetAllContributors(action.resourceId, action.resourceType)); + }), + catchError((error) => handleSectionError(ctx, 'contributorsList', error)) + ); } @Action(DeleteContributor) deleteContributor(ctx: StateContext, action: DeleteContributor) { const state = ctx.getState(); - ctx.patchState({ - contributorsList: { ...state.contributorsList, isLoading: true, error: null }, - }); - if (!action.resourceId || !action.resourceType) { return; } + ctx.patchState({ + contributorsList: { ...state.contributorsList, isLoading: true, error: null }, + }); + return this.contributorsService .deleteContributor(action.resourceType, action.resourceId, action.contributorId) .pipe( From 66f8032f2f89f3da2061c0e408ebc113fab304ea Mon Sep 17 00:00:00 2001 From: nsemets Date: Tue, 23 Sep 2025 11:09:01 +0300 Subject: [PATCH 2/5] fix(contributors): updated add contributors --- .../project-contributors-step.component.ts | 18 +++--- .../contributors-dialog.component.ts | 17 +++--- .../contributors/contributors.component.ts | 17 +++--- .../contributors/contributors.component.ts | 17 +++--- .../registries-contributors.component.ts | 17 +++--- .../shared/services/contributors.service.ts | 56 ++++++++++++------- .../contributors/contributors.actions.ts | 10 ++++ .../stores/contributors/contributors.state.ts | 23 ++++++++ 8 files changed, 113 insertions(+), 62 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 a9b3c1c7a..937c24c9f 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 @@ -7,7 +7,6 @@ import { DialogService } from 'primeng/dynamicdialog'; import { Step, StepItem, StepPanel } from 'primeng/stepper'; import { Tooltip } from 'primeng/tooltip'; -import { forkJoin } from 'rxjs'; import { filter } from 'rxjs/operators'; import { ChangeDetectionStrategy, Component, DestroyRef, effect, inject, input, output, signal } from '@angular/core'; @@ -25,6 +24,7 @@ import { ContributorDialogAddModel, ContributorModel } from '@osf/shared/models' import { CustomConfirmationService, ToastService } from '@osf/shared/services'; import { AddContributor, + BulkAddContributors, BulkUpdateContributors, ContributorsSelectors, DeleteContributor, @@ -62,6 +62,7 @@ export class ProjectContributorsStepComponent { actions = createDispatchMap({ addContributor: AddContributor, + bulkAddContributors: BulkAddContributors, bulkUpdateContributors: BulkUpdateContributors, deleteContributor: DeleteContributor, }); @@ -144,13 +145,12 @@ export class ProjectContributorsStepComponent { if (res.type === AddContributorType.Unregistered) { this.openAddUnregisteredContributorDialog(); } else { - const addRequests = res.data.map((payload) => - this.actions.addContributor(this.selectedProject()?.id, ResourceType.Project, payload) - ); - - forkJoin(addRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage'); - }); + this.actions + .bulkAddContributors(this.selectedProject()?.id, ResourceType.Project, res.data) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage') + ); } }); } @@ -187,7 +187,7 @@ export class ProjectContributorsStepComponent { const isMetadataSaved = this.isProjectMetadataSaved(); const contributors = this.initialContributors(); - if (isMetadataSaved && contributors.length && !this.projectContributors().length) { + if (isMetadataSaved && contributors.length) { this.projectContributors.set(JSON.parse(JSON.stringify(contributors))); } }); 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 b87efda60..d6bcdd6a6 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 @@ -5,7 +5,7 @@ import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { Button } from 'primeng/button'; import { DialogService, DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog'; -import { filter, forkJoin } from 'rxjs'; +import { filter } from 'rxjs'; import { ChangeDetectionStrategy, @@ -33,6 +33,7 @@ import { ContributorDialogAddModel, ContributorModel } from '@osf/shared/models' import { CustomConfirmationService, ToastService } from '@osf/shared/services'; import { AddContributor, + BulkAddContributors, BulkUpdateContributors, ContributorsSelectors, DeleteContributor, @@ -71,6 +72,7 @@ export class ContributorsDialogComponent implements OnInit { updateBibliographyFilter: UpdateBibliographyFilter, deleteContributor: DeleteContributor, addContributor: AddContributor, + bulkAddContributors: BulkAddContributors, bulkUpdateContributors: BulkUpdateContributors, }); @@ -139,13 +141,12 @@ export class ContributorsDialogComponent implements OnInit { this.openAddUnregisteredContributorDialog(); } else { if (res?.type === AddContributorType.Registered) { - const addRequests = res.data.map((payload) => - this.actions.addContributor(this.resourceId, this.resourceType, payload) - ); - - forkJoin(addRequests).subscribe(() => - this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage') - ); + this.actions + .bulkAddContributors(this.resourceId, this.resourceType, res.data) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage') + ); } } }); diff --git a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.ts b/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.ts index 54fff6e1a..60820e695 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.ts +++ b/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.ts @@ -8,7 +8,7 @@ import { DialogService } from 'primeng/dynamicdialog'; import { Message } from 'primeng/message'; import { TableModule } from 'primeng/table'; -import { filter, forkJoin } from 'rxjs'; +import { filter } from 'rxjs'; import { ChangeDetectionStrategy, @@ -36,6 +36,7 @@ import { ContributorDialogAddModel, ContributorModel } from '@osf/shared/models' import { CustomConfirmationService, ToastService } from '@osf/shared/services'; import { AddContributor, + BulkAddContributors, BulkUpdateContributors, ContributorsSelectors, DeleteContributor, @@ -79,6 +80,7 @@ export class ContributorsComponent implements OnInit { getContributors: GetAllContributors, deleteContributor: DeleteContributor, bulkUpdateContributors: BulkUpdateContributors, + bulkAddContributors: BulkAddContributors, addContributor: AddContributor, }); @@ -132,13 +134,12 @@ export class ContributorsComponent implements OnInit { if (res.type === AddContributorType.Unregistered) { this.openAddUnregisteredContributorDialog(); } else { - const addRequests = res.data.map((payload) => - this.actions.addContributor(this.preprintId(), ResourceType.Preprint, payload) - ); - - forkJoin(addRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage'); - }); + this.actions + .bulkAddContributors(this.preprintId(), ResourceType.Preprint, res.data) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage') + ); } }); } diff --git a/src/app/features/project/contributors/contributors.component.ts b/src/app/features/project/contributors/contributors.component.ts index 7e24d2c88..2811ac916 100644 --- a/src/app/features/project/contributors/contributors.component.ts +++ b/src/app/features/project/contributors/contributors.component.ts @@ -7,7 +7,7 @@ import { DialogService } from 'primeng/dynamicdialog'; import { Select } from 'primeng/select'; import { TableModule } from 'primeng/table'; -import { debounceTime, distinctUntilChanged, filter, forkJoin, map, of, switchMap } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, map, of, switchMap } from 'rxjs'; import { ChangeDetectionStrategy, @@ -43,6 +43,7 @@ import { import { CustomConfirmationService, ToastService } from '@osf/shared/services'; import { AddContributor, + BulkAddContributors, BulkUpdateContributors, ContributorsSelectors, CreateViewOnlyLink, @@ -134,6 +135,7 @@ export class ContributorsComponent implements OnInit { updateBibliographyFilter: UpdateBibliographyFilter, deleteContributor: DeleteContributor, bulkUpdateContributors: BulkUpdateContributors, + bulkAddContributors: BulkAddContributors, addContributor: AddContributor, createViewOnlyLink: CreateViewOnlyLink, deleteViewOnlyLink: DeleteViewOnlyLink, @@ -222,13 +224,12 @@ export class ContributorsComponent implements OnInit { if (res.type === AddContributorType.Unregistered) { this.openAddUnregisteredContributorDialog(); } else { - const addRequests = res.data.map((payload) => - this.actions.addContributor(this.resourceId(), this.resourceType(), payload) - ); - - forkJoin(addRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage'); - }); + this.actions + .bulkAddContributors(this.resourceId(), this.resourceType(), res.data) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage') + ); } }); } 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 0ee6628ad..8b39a9e13 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 @@ -7,7 +7,7 @@ import { Card } from 'primeng/card'; import { DialogService } from 'primeng/dynamicdialog'; import { TableModule } from 'primeng/table'; -import { filter, forkJoin, map, of } from 'rxjs'; +import { filter, map, of } from 'rxjs'; import { ChangeDetectionStrategy, @@ -36,6 +36,7 @@ import { ContributorDialogAddModel, ContributorModel } from '@osf/shared/models' import { CustomConfirmationService, ToastService } from '@osf/shared/services'; import { AddContributor, + BulkAddContributors, BulkUpdateContributors, ContributorsSelectors, DeleteContributor, @@ -83,6 +84,7 @@ export class RegistriesContributorsComponent implements OnInit { getContributors: GetAllContributors, deleteContributor: DeleteContributor, bulkUpdateContributors: BulkUpdateContributors, + bulkAddContributors: BulkAddContributors, addContributor: AddContributor, }); @@ -145,13 +147,12 @@ export class RegistriesContributorsComponent implements OnInit { if (res.type === AddContributorType.Unregistered) { this.openAddUnregisteredContributorDialog(); } else { - const addRequests = res.data.map((payload) => - this.actions.addContributor(this.draftId(), ResourceType.DraftRegistration, payload) - ); - - forkJoin(addRequests).subscribe(() => { - this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage'); - }); + this.actions + .bulkAddContributors(this.draftId(), ResourceType.DraftRegistration, res.data) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => + this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage') + ); } }); } diff --git a/src/app/shared/services/contributors.service.ts b/src/app/shared/services/contributors.service.ts index ee4552e3c..92dad7bba 100644 --- a/src/app/shared/services/contributors.service.ts +++ b/src/app/shared/services/contributors.service.ts @@ -62,27 +62,6 @@ export class ContributorsService { .pipe(map((response) => ContributorsMapper.fromUsersWithPaginationGetResponse(response))); } - addContributor( - resourceType: ResourceType, - resourceId: string, - data: ContributorAddModel - ): Observable { - const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/`; - const type = data.id ? AddContributorType.Registered : AddContributorType.Unregistered; - - const contributorData = { data: ContributorsMapper.toContributorAddRequest(data, type) }; - - return this.jsonApiService - .post>(baseUrl, contributorData) - .pipe(map((contributor) => ContributorsMapper.fromContributorResponse(contributor.data))); - } - - deleteContributor(resourceType: ResourceType, resourceId: string, userId: string): Observable { - const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/${userId}/`; - - return this.jsonApiService.delete(baseUrl); - } - bulkUpdateContributors( resourceType: ResourceType, resourceId: string, @@ -112,4 +91,39 @@ export class ContributorsService { .patch(baseUrl, contributorData) .pipe(map((contributor) => ContributorsMapper.fromContributorResponse(contributor))); } + + bulkAddContributors( + resourceType: ResourceType, + resourceId: string, + contributors: ContributorAddModel[] + ): Observable { + if (contributors.length === 0) { + return of([]); + } + + const addRequests = contributors.map((contributor) => this.addContributor(resourceType, resourceId, contributor)); + + return forkJoin(addRequests); + } + + addContributor( + resourceType: ResourceType, + resourceId: string, + data: ContributorAddModel + ): Observable { + const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/`; + const type = data.id ? AddContributorType.Registered : AddContributorType.Unregistered; + + const contributorData = { data: ContributorsMapper.toContributorAddRequest(data, type) }; + + return this.jsonApiService + .post>(baseUrl, contributorData) + .pipe(map((contributor) => ContributorsMapper.fromContributorResponse(contributor.data))); + } + + deleteContributor(resourceType: ResourceType, resourceId: string, userId: string): Observable { + const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/${userId}/`; + + return this.jsonApiService.delete(baseUrl); + } } diff --git a/src/app/shared/stores/contributors/contributors.actions.ts b/src/app/shared/stores/contributors/contributors.actions.ts index 8741945d8..8633da276 100644 --- a/src/app/shared/stores/contributors/contributors.actions.ts +++ b/src/app/shared/stores/contributors/contributors.actions.ts @@ -48,6 +48,16 @@ export class BulkUpdateContributors { ) {} } +export class BulkAddContributors { + static readonly type = '[Contributors] Bulk Add Contributors'; + + constructor( + public resourceId: string | undefined | null, + public resourceType: ResourceType | undefined, + public contributors: ContributorAddModel[] + ) {} +} + export class DeleteContributor { static readonly type = '[Contributors] Delete Contributor'; diff --git a/src/app/shared/stores/contributors/contributors.state.ts b/src/app/shared/stores/contributors/contributors.state.ts index 81b0f5906..fbef29ec8 100644 --- a/src/app/shared/stores/contributors/contributors.state.ts +++ b/src/app/shared/stores/contributors/contributors.state.ts @@ -9,6 +9,7 @@ import { ContributorsService } from '@osf/shared/services'; import { AddContributor, + BulkAddContributors, BulkUpdateContributors, ClearUsers, DeleteContributor, @@ -105,6 +106,28 @@ export class ContributorsState { ); } + @Action(BulkAddContributors) + bulkAddContributors(ctx: StateContext, action: BulkAddContributors) { + const state = ctx.getState(); + + if (!action.resourceId || !action.resourceType || !action.contributors.length) { + return; + } + + ctx.patchState({ + contributorsList: { ...state.contributorsList, isLoading: true, error: null }, + }); + + return this.contributorsService + .bulkAddContributors(action.resourceType, action.resourceId, action.contributors) + .pipe( + tap(() => { + ctx.dispatch(new GetAllContributors(action.resourceId, action.resourceType)); + }), + catchError((error) => handleSectionError(ctx, 'contributorsList', error)) + ); + } + @Action(DeleteContributor) deleteContributor(ctx: StateContext, action: DeleteContributor) { const state = ctx.getState(); From 0b7a2e0509b322684626a6ececf927bd8daebe3b Mon Sep 17 00:00:00 2001 From: nsemets Date: Tue, 23 Sep 2025 11:15:17 +0300 Subject: [PATCH 3/5] fix(naming): updated naming of components --- .../features/preprints/components/index.ts | 2 +- ...nts-affiliated-institutions.component.html | 0 ...nts-affiliated-institutions.component.scss | 0 ...-affiliated-institutions.component.spec.ts | 0 ...rints-affiliated-institutions.component.ts | 8 ++++---- .../preprints-contributors.component.html} | 0 .../preprints-contributors.component.scss} | 0 .../preprints-contributors.component.spec.ts} | 16 +++++++-------- .../preprints-contributors.component.ts} | 8 ++++---- .../preprints-metadata-step.component.html} | 2 +- .../preprints-metadata-step.component.scss} | 0 ...preprints-metadata-step.component.spec.ts} | 16 +++++++-------- .../preprints-metadata-step.component.ts} | 20 +++++++++---------- .../preprints-subjects.component.html | 0 .../preprints-subjects.component.scss | 0 .../preprints-subjects.component.spec.ts | 4 ++-- .../preprints-subjects.component.ts | 2 +- .../submit-preprint-stepper.component.html | 2 +- .../submit-preprint-stepper.component.ts | 4 ++-- .../update-preprint-stepper.component.html | 2 +- .../update-preprint-stepper.component.ts | 4 ++-- 21 files changed, 45 insertions(+), 45 deletions(-) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html (100%) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-affiliated-institutions/preprints-affiliated-institutions.component.scss (100%) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts (100%) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts (91%) rename src/app/features/preprints/components/stepper/{metadata-step/contributors/contributors.component.html => preprints-metadata-step/preprints-contributors/preprints-contributors.component.html} (100%) rename src/app/features/preprints/components/stepper/{metadata-step/contributors/contributors.component.scss => preprints-metadata-step/preprints-contributors/preprints-contributors.component.scss} (100%) rename src/app/features/preprints/components/stepper/{metadata-step/contributors/contributors.component.spec.ts => preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts} (64%) rename src/app/features/preprints/components/stepper/{metadata-step/contributors/contributors.component.ts => preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts} (96%) rename src/app/features/preprints/components/stepper/{metadata-step/metadata-step.component.html => preprints-metadata-step/preprints-metadata-step.component.html} (98%) rename src/app/features/preprints/components/stepper/{metadata-step/metadata-step.component.scss => preprints-metadata-step/preprints-metadata-step.component.scss} (100%) rename src/app/features/preprints/components/stepper/{metadata-step/metadata-step.component.spec.ts => preprints-metadata-step/preprints-metadata-step.component.spec.ts} (69%) rename src/app/features/preprints/components/stepper/{metadata-step/metadata-step.component.ts => preprints-metadata-step/preprints-metadata-step.component.ts} (88%) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-subjects/preprints-subjects.component.html (100%) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-subjects/preprints-subjects.component.scss (100%) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-subjects/preprints-subjects.component.spec.ts (92%) rename src/app/features/preprints/components/stepper/{metadata-step => preprints-metadata-step}/preprints-subjects/preprints-subjects.component.ts (97%) diff --git a/src/app/features/preprints/components/index.ts b/src/app/features/preprints/components/index.ts index f8f1fb1dc..3c13eac87 100644 --- a/src/app/features/preprints/components/index.ts +++ b/src/app/features/preprints/components/index.ts @@ -11,11 +11,11 @@ export { PreprintProviderHeroComponent } from './preprint-provider-hero/preprint export { PreprintServicesComponent } from './preprint-services/preprint-services.component'; export { PreprintsHelpDialogComponent } from './preprints-help-dialog/preprints-help-dialog.component'; export { AuthorAssertionsStepComponent } from './stepper/author-assertion-step/author-assertions-step.component'; +export { PreprintsMetadataStepComponent } from './stepper/preprints-metadata-step/preprints-metadata-step.component'; export { SupplementsStepComponent } from './stepper/supplements-step/supplements-step.component'; export { MakeDecisionComponent } from '@osf/features/preprints/components/preprint-details/make-decision/make-decision.component'; export { PreprintTombstoneComponent } from '@osf/features/preprints/components/preprint-details/preprint-tombstone/preprint-tombstone.component'; export { WithdrawDialogComponent } from '@osf/features/preprints/components/preprint-details/withdraw-dialog/withdraw-dialog.component'; export { FileStepComponent } from '@osf/features/preprints/components/stepper/file-step/file-step.component'; -export { MetadataStepComponent } from '@osf/features/preprints/components/stepper/metadata-step/metadata-step.component'; export { ReviewStepComponent } from '@osf/features/preprints/components/stepper/review-step/review-step.component'; export { TitleAndAbstractStepComponent } from '@osf/features/preprints/components/stepper/title-and-abstract-step/title-and-abstract-step.component'; diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.scss b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.scss similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.scss rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.scss diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts similarity index 91% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts index 5941b7ca4..1d456a86b 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts @@ -7,15 +7,15 @@ import { Card } from 'primeng/card'; import { ChangeDetectionStrategy, Component, effect, input, OnInit, signal } from '@angular/core'; import { PreprintProviderDetails } from '@osf/features/preprints/models'; -import { AffiliatedInstitutionSelectComponent } from '@shared/components'; -import { ResourceType } from '@shared/enums'; -import { Institution } from '@shared/models'; +import { AffiliatedInstitutionSelectComponent } from '@osf/shared/components'; +import { ResourceType } from '@osf/shared/enums'; +import { Institution } from '@osf/shared/models'; import { FetchResourceInstitutions, FetchUserInstitutions, InstitutionsSelectors, UpdateResourceInstitutions, -} from '@shared/stores/institutions'; +} from '@osf/shared/stores/institutions'; @Component({ selector: 'osf-preprints-affiliated-institutions', diff --git a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.html b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.html similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.html rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.html diff --git a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.scss b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.scss similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.scss rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.scss diff --git a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.spec.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts similarity index 64% rename from src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.spec.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts index 4bd1cf675..9ee0e43db 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.spec.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.spec.ts @@ -8,20 +8,20 @@ import { DialogService } from 'primeng/dynamicdialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideNoopAnimations } from '@angular/platform-browser/animations'; -import { MOCK_STORE, TranslateServiceMock } from '@shared/mocks'; -import { CustomConfirmationService, ToastService } from '@shared/services'; +import { MOCK_STORE, TranslateServiceMock } from '@osf/shared/mocks'; +import { CustomConfirmationService, ToastService } from '@osf/shared/services'; -import { ContributorsComponent } from './contributors.component'; +import { PreprintsContributorsComponent } from './preprints-contributors.component'; -describe('ContributorsComponent', () => { - let component: ContributorsComponent; - let fixture: ComponentFixture; +describe('PreprintsContributorsComponent', () => { + let component: PreprintsContributorsComponent; + let fixture: ComponentFixture; beforeEach(async () => { (MOCK_STORE.selectSignal as jest.Mock).mockImplementation(() => () => []); await TestBed.configureTestingModule({ - imports: [ContributorsComponent, MockPipe(TranslatePipe)], + imports: [PreprintsContributorsComponent, MockPipe(TranslatePipe)], providers: [ MockProvider(Store, MOCK_STORE), MockProvider(DialogService), @@ -32,7 +32,7 @@ describe('ContributorsComponent', () => { ], }).compileComponents(); - fixture = TestBed.createComponent(ContributorsComponent); + fixture = TestBed.createComponent(PreprintsContributorsComponent); component = fixture.componentInstance; fixture.componentRef.setInput('preprintId', '1'); diff --git a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts similarity index 96% rename from src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts index 60820e695..8be442036 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/contributors/contributors.component.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-contributors/preprints-contributors.component.ts @@ -44,14 +44,14 @@ import { } from '@osf/shared/stores'; @Component({ - selector: 'osf-preprint-contributors', + selector: 'osf-preprints-contributors', imports: [FormsModule, TableModule, ContributorsListComponent, TranslatePipe, Card, Button, Message], - templateUrl: './contributors.component.html', - styleUrl: './contributors.component.scss', + templateUrl: './preprints-contributors.component.html', + styleUrl: './preprints-contributors.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], }) -export class ContributorsComponent implements OnInit { +export class PreprintsContributorsComponent implements OnInit { preprintId = input(''); readonly destroyRef = inject(DestroyRef); diff --git a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.html b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.html similarity index 98% rename from src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.html rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.html index 7bbba2f5b..dec11eca6 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.html +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.html @@ -1,7 +1,7 @@

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

- +
diff --git a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.scss b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.scss similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.scss rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.scss diff --git a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.spec.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.spec.ts similarity index 69% rename from src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.spec.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.spec.ts index 381e51df7..ea1be6b36 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.spec.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.spec.ts @@ -7,14 +7,14 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { PreprintStepperSelectors } from '@osf/features/preprints/store/preprint-stepper'; -import { MOCK_STORE, TranslateServiceMock } from '@shared/mocks'; -import { CustomConfirmationService, ToastService } from '@shared/services'; +import { MOCK_STORE, TranslateServiceMock } from '@osf/shared/mocks'; +import { CustomConfirmationService, ToastService } from '@osf/shared/services'; -import { MetadataStepComponent } from './metadata-step.component'; +import { PreprintsMetadataStepComponent } from './preprints-metadata-step.component'; -describe('MetadataStepComponent', () => { - let component: MetadataStepComponent; - let fixture: ComponentFixture; +describe('PreprintsMetadataStepComponent', () => { + let component: PreprintsMetadataStepComponent; + let fixture: ComponentFixture; beforeEach(async () => { (MOCK_STORE.selectSignal as jest.Mock).mockImplementation((selector) => { @@ -31,7 +31,7 @@ describe('MetadataStepComponent', () => { }); await TestBed.configureTestingModule({ - imports: [MetadataStepComponent, MockPipe(TranslatePipe)], + imports: [PreprintsMetadataStepComponent, MockPipe(TranslatePipe)], providers: [ MockProvider(Store, MOCK_STORE), MockProvider(ToastService), @@ -41,7 +41,7 @@ describe('MetadataStepComponent', () => { ], }).compileComponents(); - fixture = TestBed.createComponent(MetadataStepComponent); + fixture = TestBed.createComponent(PreprintsMetadataStepComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.ts similarity index 88% rename from src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.ts index f2a60abe4..786b4aaa0 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-metadata-step.component.ts @@ -21,20 +21,20 @@ import { SaveLicense, UpdatePreprint, } from '@osf/features/preprints/store/preprint-stepper'; +import { IconComponent, LicenseComponent, TagsInputComponent, TextInputComponent } from '@osf/shared/components'; +import { INPUT_VALIDATION_MESSAGES } from '@osf/shared/constants'; import { CustomValidators, findChangedFields } from '@osf/shared/helpers'; -import { IconComponent, LicenseComponent, TagsInputComponent, TextInputComponent } from '@shared/components'; -import { INPUT_VALIDATION_MESSAGES } from '@shared/constants'; -import { LicenseModel, LicenseOptions } from '@shared/models'; -import { CustomConfirmationService, ToastService } from '@shared/services'; +import { LicenseModel, LicenseOptions } from '@osf/shared/models'; +import { CustomConfirmationService, ToastService } from '@osf/shared/services'; -import { ContributorsComponent } from './contributors/contributors.component'; import { PreprintsAffiliatedInstitutionsComponent } from './preprints-affiliated-institutions/preprints-affiliated-institutions.component'; +import { PreprintsContributorsComponent } from './preprints-contributors/preprints-contributors.component'; import { PreprintsSubjectsComponent } from './preprints-subjects/preprints-subjects.component'; @Component({ - selector: 'osf-preprint-metadata', + selector: 'osf-preprints-metadata', imports: [ - ContributorsComponent, + PreprintsContributorsComponent, Button, Card, ReactiveFormsModule, @@ -50,11 +50,11 @@ import { PreprintsSubjectsComponent } from './preprints-subjects/preprints-subje PreprintsSubjectsComponent, PreprintsAffiliatedInstitutionsComponent, ], - templateUrl: './metadata-step.component.html', - styleUrl: './metadata-step.component.scss', + templateUrl: './preprints-metadata-step.component.html', + styleUrl: './preprints-metadata-step.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MetadataStepComponent implements OnInit { +export class PreprintsMetadataStepComponent implements OnInit { private customConfirmationService = inject(CustomConfirmationService); private toastService = inject(ToastService); private actions = createDispatchMap({ diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.html b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.html similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.html rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.html diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.scss b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.scss similarity index 100% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.scss rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.scss diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.spec.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.spec.ts similarity index 92% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.spec.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.spec.ts index 330e6fda9..c8865104d 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.spec.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.spec.ts @@ -7,8 +7,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormControl } from '@angular/forms'; import { PreprintStepperSelectors } from '@osf/features/preprints/store/preprint-stepper'; -import { MOCK_STORE, TranslateServiceMock } from '@shared/mocks'; -import { SubjectsSelectors } from '@shared/stores'; +import { MOCK_STORE, TranslateServiceMock } from '@osf/shared/mocks'; +import { SubjectsSelectors } from '@osf/shared/stores'; import { PreprintsSubjectsComponent } from './preprints-subjects.component'; diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.ts b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.ts similarity index 97% rename from src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.ts rename to src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.ts index a88ca063c..b7d18cdbe 100644 --- a/src/app/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component.ts +++ b/src/app/features/preprints/components/stepper/preprints-metadata-step/preprints-subjects/preprints-subjects.component.ts @@ -10,6 +10,7 @@ import { FormControl } from '@angular/forms'; import { PreprintStepperSelectors } from '@osf/features/preprints/store/preprint-stepper'; import { SubjectsComponent } from '@osf/shared/components'; +import { INPUT_VALIDATION_MESSAGES } from '@osf/shared/constants'; import { ResourceType } from '@osf/shared/enums'; import { SubjectModel } from '@osf/shared/models'; import { @@ -19,7 +20,6 @@ import { SubjectsSelectors, UpdateResourceSubjects, } from '@osf/shared/stores'; -import { INPUT_VALIDATION_MESSAGES } from '@shared/constants'; @Component({ selector: 'osf-preprints-subjects', diff --git a/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html b/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html index ebdf7165f..fd53f63ae 100644 --- a/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html +++ b/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html @@ -43,7 +43,7 @@

/> } @case (SubmitStepsEnum.Metadata) { - /> } @case (PreprintSteps.Metadata) { - Date: Mon, 29 Sep 2025 14:38:35 +0300 Subject: [PATCH 4/5] fix(imports): added missing import --- .../contributors-table.component.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) 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 c90056ce0..68f11ad00 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 @@ -18,9 +18,21 @@ import { ContributorPermission } from '@osf/shared/enums'; import { ContributorModel, SelectOption, TableParameters } from '@osf/shared/models'; import { CustomDialogService } from '@osf/shared/services'; +import { IconComponent } from '../../icon/icon.component'; + @Component({ selector: 'osf-contributors-table', - imports: [TranslatePipe, FormsModule, TableModule, Tooltip, Checkbox, Skeleton, Button, SelectComponent], + imports: [ + TranslatePipe, + FormsModule, + TableModule, + Tooltip, + Checkbox, + Skeleton, + Button, + SelectComponent, + IconComponent, + ], templateUrl: './contributors-table.component.html', styleUrl: './contributors-table.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, From 6e5cdc92e5d0b02a8c685304401e36317d3ec5f2 Mon Sep 17 00:00:00 2001 From: nsemets Date: Tue, 30 Sep 2025 16:58:49 +0300 Subject: [PATCH 5/5] fix(education): fixed condition --- .../components/education/education.component.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/features/settings/profile-settings/components/education/education.component.ts b/src/app/features/settings/profile-settings/components/education/education.component.ts index 4ffe3bae2..af16a56d2 100644 --- a/src/app/features/settings/profile-settings/components/education/education.component.ts +++ b/src/app/features/settings/profile-settings/components/education/education.component.ts @@ -123,6 +123,10 @@ export class EducationComponent { ); } + if (formPositions.length !== education.length) { + return true; + } + return this.educations.value.some((formEducation, index) => { const initialEdu = this.educationItems()[index]; if (!initialEdu) return true;