diff --git a/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.html b/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.html
index 36592e717..f8501c0a9 100644
--- a/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.html
+++ b/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.html
@@ -1,170 +1,48 @@
-
-
-
- {{ 'moderation.preprintSettings.warning' | translate }}
- support@osf.io
- {{ 'moderation.preprintSettings.warningForAssistance' | translate }}
-
-
-
-
+
+}
diff --git a/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.ts b/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.ts
index 026be61a0..05022ef15 100644
--- a/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.ts
+++ b/src/app/features/moderation/components/preprint-moderation-settings/preprint-moderation-settings.component.ts
@@ -1,38 +1,79 @@
+import { createDispatchMap, select, Store } from '@ngxs/store';
+
import { TranslatePipe } from '@ngx-translate/core';
import { Card } from 'primeng/card';
import { Message } from 'primeng/message';
import { RadioButton } from 'primeng/radiobutton';
-import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';
+import { map, of } from 'rxjs';
+
+import { ChangeDetectionStrategy, Component, computed, effect, inject, OnInit } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
+import { ActivatedRoute } from '@angular/router';
+
+import { LoadingSpinnerComponent } from '@osf/shared/components';
+import { DEFAULT_SUPPORT_EMAIL } from '@osf/shared/constants';
import { PREPRINT_SETTINGS_SECTIONS } from '../../constants';
-import { CommentVisibilityType, ModerationType, ModeratorsCommentsType, SettingsSectionControl } from '../../enums';
+import { SettingsSectionControl } from '../../enums';
+import { GetPreprintProvider, PreprintModerationSelectors } from '../../store/preprint-moderation';
@Component({
selector: 'osf-preprint-moderation-settings',
- imports: [TranslatePipe, ReactiveFormsModule, Card, RadioButton, Message],
+ imports: [TranslatePipe, ReactiveFormsModule, Card, RadioButton, Message, LoadingSpinnerComponent],
templateUrl: './preprint-moderation-settings.component.html',
styleUrl: './preprint-moderation-settings.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PreprintModerationSettingsComponent implements OnInit {
- private fb = inject(FormBuilder);
+ private readonly route = inject(ActivatedRoute);
+ private readonly store = inject(Store);
+ private readonly fb = inject(FormBuilder);
+
+ private readonly actions = createDispatchMap({ getPreprintProvider: GetPreprintProvider });
+ readonly providerId = toSignal(this.route.parent?.params.pipe(map((params) => params['id'])) ?? of(undefined));
+
settingsForm!: FormGroup;
sections = PREPRINT_SETTINGS_SECTIONS;
+ supportEmail = DEFAULT_SUPPORT_EMAIL;
+
+ isLoading = select(PreprintModerationSelectors.arePreprintProviderLoading);
+
+ settings = computed(() =>
+ this.store.selectSignal(PreprintModerationSelectors.getPreprintProvider)()(this.providerId())
+ );
+
+ constructor() {
+ effect(() => {
+ if (this.settings()) {
+ this.updateForm();
+ }
+ });
+ }
+
ngOnInit(): void {
+ this.actions.getPreprintProvider(this.providerId());
this.initForm();
}
private initForm(): void {
this.settingsForm = this.fb.group({
- [SettingsSectionControl.ModerationType]: [ModerationType.Pre],
- [SettingsSectionControl.CommentVisibility]: [CommentVisibilityType.Moderators],
- [SettingsSectionControl.ModeratorComments]: [ModeratorsCommentsType.Anonymized],
+ [SettingsSectionControl.ModerationType]: this.settings()?.reviewsWorkflow,
+ [SettingsSectionControl.CommentVisibility]: this.settings()?.reviewsCommentsPrivate,
+ [SettingsSectionControl.ModeratorComments]: this.settings()?.reviewsCommentsAnonymous,
});
this.settingsForm.disable();
}
+
+ private updateForm() {
+ this.settingsForm.patchValue({
+ [SettingsSectionControl.ModerationType]: this.settings()?.reviewsWorkflow,
+ [SettingsSectionControl.CommentVisibility]: this.settings()?.reviewsCommentsPrivate,
+ [SettingsSectionControl.ModeratorComments]: this.settings()?.reviewsCommentsAnonymous,
+ });
+ }
}
diff --git a/src/app/features/moderation/constants/preprint-settings-sections.const.ts b/src/app/features/moderation/constants/preprint-settings-sections.const.ts
index daab5ed10..e2ad7e844 100644
--- a/src/app/features/moderation/constants/preprint-settings-sections.const.ts
+++ b/src/app/features/moderation/constants/preprint-settings-sections.const.ts
@@ -1,4 +1,4 @@
-import { CommentVisibilityType, ModerationType, ModeratorsCommentsType, SettingsSectionControl } from '../enums';
+import { ModerationType, SettingsSectionControl } from '../enums';
export const PREPRINT_SETTINGS_SECTIONS = [
{
@@ -23,12 +23,12 @@ export const PREPRINT_SETTINGS_SECTIONS = [
description: 'moderation.preprintSettings.commentVisibility.description',
options: [
{
- value: CommentVisibilityType.Moderators,
+ value: true,
label: 'moderation.preprintSettings.commentVisibility.moderators',
description: 'moderation.preprintSettings.commentVisibility.moderatorsDescription',
},
{
- value: CommentVisibilityType.ModeratorsAndContributors,
+ value: false,
label: 'moderation.preprintSettings.commentVisibility.moderatorsAndContributors',
description: 'moderation.preprintSettings.commentVisibility.moderatorsAndContributorsDescription',
},
@@ -40,12 +40,12 @@ export const PREPRINT_SETTINGS_SECTIONS = [
description: 'moderation.preprintSettings.moderatorComments.description',
options: [
{
- value: ModeratorsCommentsType.Anonymized,
+ value: true,
label: 'moderation.preprintSettings.moderatorComments.anonymized',
description: 'moderation.preprintSettings.moderatorComments.anonymizedDescription',
},
{
- value: ModeratorsCommentsType.Named,
+ value: false,
label: 'moderation.preprintSettings.moderatorComments.named',
description: 'moderation.preprintSettings.moderatorComments.namedDescription',
},
diff --git a/src/app/features/moderation/enums/comment-visibility-type.enum.ts b/src/app/features/moderation/enums/comment-visibility-type.enum.ts
deleted file mode 100644
index c9f237740..000000000
--- a/src/app/features/moderation/enums/comment-visibility-type.enum.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export enum CommentVisibilityType {
- Moderators = 'moderators',
- ModeratorsAndContributors = 'moderatorsAndContributors',
-}
diff --git a/src/app/features/moderation/enums/index.ts b/src/app/features/moderation/enums/index.ts
index 64fa3ce62..3890b7661 100644
--- a/src/app/features/moderation/enums/index.ts
+++ b/src/app/features/moderation/enums/index.ts
@@ -1,9 +1,7 @@
export * from './add-moderator-type.enum';
export * from './collection-moderation-tab.enum';
-export * from './comment-visibility-type.enum';
export * from './moderation-type.enum';
export * from './moderator-permission.enum';
-export * from './moderators-comments-type.enum';
export * from './preprint-moderation-tab.enum';
export * from './registry-moderation-tab.enum';
export * from './settings-section-control.enum';
diff --git a/src/app/features/moderation/enums/moderation-type.enum.ts b/src/app/features/moderation/enums/moderation-type.enum.ts
index f3cbabe87..b5b9c5a65 100644
--- a/src/app/features/moderation/enums/moderation-type.enum.ts
+++ b/src/app/features/moderation/enums/moderation-type.enum.ts
@@ -1,4 +1,4 @@
export enum ModerationType {
- Pre = 'pre',
- Post = 'post',
+ Pre = 'pre-moderation',
+ Post = 'post-moderation',
}
diff --git a/src/app/features/moderation/enums/moderators-comments-type.enum.ts b/src/app/features/moderation/enums/moderators-comments-type.enum.ts
deleted file mode 100644
index 3b19d6c97..000000000
--- a/src/app/features/moderation/enums/moderators-comments-type.enum.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export enum ModeratorsCommentsType {
- Anonymized = 'anonymized',
- Named = 'named',
-}
diff --git a/src/app/features/moderation/mappers/index.ts b/src/app/features/moderation/mappers/index.ts
index 5705bce50..90bd110d9 100644
--- a/src/app/features/moderation/mappers/index.ts
+++ b/src/app/features/moderation/mappers/index.ts
@@ -1,2 +1,2 @@
export * from './moderation.mapper';
-export * from './preprint-review-action.mapper';
+export * from './preprint-moderation.mapper';
diff --git a/src/app/features/moderation/mappers/preprint-review-action.mapper.ts b/src/app/features/moderation/mappers/preprint-moderation.mapper.ts
similarity index 62%
rename from src/app/features/moderation/mappers/preprint-review-action.mapper.ts
rename to src/app/features/moderation/mappers/preprint-moderation.mapper.ts
index 4e3d326f0..385581505 100644
--- a/src/app/features/moderation/mappers/preprint-review-action.mapper.ts
+++ b/src/app/features/moderation/mappers/preprint-moderation.mapper.ts
@@ -1,10 +1,10 @@
import { JsonApiResponseWithPaging } from '@osf/core/models';
import { PaginatedData } from '@osf/shared/models';
-import { PreprintRelatedCountJsonApi, ReviewActionJsonApi } from '../models';
+import { PreprintProviderModerationInfo, PreprintRelatedCountJsonApi, ReviewActionJsonApi } from '../models';
import { PreprintReviewActionModel } from '../models/preprint-review-action.model';
-export class PreprintReviewActionMapper {
+export class PreprintModerationMapper {
static fromResponse(response: ReviewActionJsonApi): PreprintReviewActionModel {
return {
id: response.id,
@@ -35,7 +35,15 @@ export class PreprintReviewActionMapper {
};
}
- static fromRelatedCounts(response: PreprintRelatedCountJsonApi) {
- return response.relationships.preprints.links.related.meta.pending;
+ static fromPreprintRelatedCounts(response: PreprintRelatedCountJsonApi): PreprintProviderModerationInfo {
+ return {
+ id: response.id,
+ name: response.attributes.name,
+ reviewsCommentsAnonymous: response.attributes.reviews_comments_anonymous,
+ reviewsCommentsPrivate: response.attributes.reviews_comments_private,
+ reviewsWorkflow: response.attributes.reviews_workflow,
+ submissionCount: response.relationships.preprints.links.related.meta.pending ?? 0,
+ supportEmail: response.attributes.email_support,
+ };
}
}
diff --git a/src/app/features/moderation/models/index.ts b/src/app/features/moderation/models/index.ts
index 0bc26a8b4..38e717b41 100644
--- a/src/app/features/moderation/models/index.ts
+++ b/src/app/features/moderation/models/index.ts
@@ -3,6 +3,7 @@ export * from './moderator.model';
export * from './moderator-add.model';
export * from './moderator-dialog-add.model';
export * from './moderator-json-api.model';
+export * from './preprint-provider-moderation-info.model';
export * from './preprint-related-count-json-api.model';
export * from './preprint-review-action.model';
export * from './preprint-review-action-json-api.model';
diff --git a/src/app/features/moderation/models/preprint-provider-moderation-info.model.ts b/src/app/features/moderation/models/preprint-provider-moderation-info.model.ts
new file mode 100644
index 000000000..62ea85ef4
--- /dev/null
+++ b/src/app/features/moderation/models/preprint-provider-moderation-info.model.ts
@@ -0,0 +1,9 @@
+export interface PreprintProviderModerationInfo {
+ id: string;
+ name: string;
+ submissionCount?: number;
+ reviewsCommentsAnonymous: boolean;
+ reviewsCommentsPrivate: boolean;
+ reviewsWorkflow: boolean;
+ supportEmail?: string;
+}
diff --git a/src/app/features/moderation/models/preprint-related-count-json-api.model.ts b/src/app/features/moderation/models/preprint-related-count-json-api.model.ts
index 4cbaed274..e288a496b 100644
--- a/src/app/features/moderation/models/preprint-related-count-json-api.model.ts
+++ b/src/app/features/moderation/models/preprint-related-count-json-api.model.ts
@@ -1,4 +1,12 @@
export interface PreprintRelatedCountJsonApi {
+ id: string;
+ attributes: {
+ name: string;
+ reviews_comments_anonymous: boolean;
+ reviews_comments_private: boolean;
+ reviews_workflow: boolean;
+ email_support?: string;
+ };
relationships: {
preprints: {
links: {
diff --git a/src/app/features/moderation/preprint-moderation.routes.ts b/src/app/features/moderation/preprint-moderation.routes.ts
index 1a2e6cef2..ef2a0053f 100644
--- a/src/app/features/moderation/preprint-moderation.routes.ts
+++ b/src/app/features/moderation/preprint-moderation.routes.ts
@@ -5,6 +5,7 @@ import { Routes } from '@angular/router';
import { ResourceType } from '@osf/shared/enums';
import { ModeratorsState } from './store/moderation';
+import { PreprintModerationState } from './store/preprint-moderation';
import { PreprintModerationTab } from './enums';
export const preprintModerationRoutes: Routes = [
@@ -14,6 +15,7 @@ export const preprintModerationRoutes: Routes = [
import('@osf/features/moderation/pages/preprint-moderation/preprint-moderation.component').then(
(m) => m.PreprintModerationComponent
),
+ providers: [provideStates([PreprintModerationState])],
children: [
{
path: '',
diff --git a/src/app/features/moderation/services/preprint-moderation.service.ts b/src/app/features/moderation/services/preprint-moderation.service.ts
index 6e316943b..e5d905dfc 100644
--- a/src/app/features/moderation/services/preprint-moderation.service.ts
+++ b/src/app/features/moderation/services/preprint-moderation.service.ts
@@ -4,12 +4,15 @@ import { inject, Injectable } from '@angular/core';
import { JsonApiResponse, JsonApiResponseWithPaging } from '@osf/core/models';
import { JsonApiService } from '@osf/core/services';
-import { PreprintProvidersMapper } from '@osf/features/preprints/mappers';
-import { PreprintProviderDetailsJsonApi, PreprintProviderShortInfo } from '@osf/features/preprints/models';
import { PaginatedData } from '@osf/shared/models';
-import { PreprintReviewActionMapper } from '../mappers';
-import { PreprintRelatedCountJsonApi, PreprintReviewActionModel, ReviewActionJsonApi } from '../models';
+import { PreprintModerationMapper } from '../mappers';
+import {
+ PreprintProviderModerationInfo,
+ PreprintRelatedCountJsonApi,
+ PreprintReviewActionModel,
+ ReviewActionJsonApi,
+} from '../models';
import { environment } from 'src/environments/environment';
@@ -19,20 +22,20 @@ import { environment } from 'src/environments/environment';
export class PreprintModerationService {
private readonly jsonApiService = inject(JsonApiService);
- getPreprintProvidersToModerate(): Observable {
+ getPreprintProviders(): Observable {
const baseUrl = `${environment.apiUrl}/preprint_providers/?filter[permissions]=view_actions,set_up_moderation`;
return this.jsonApiService
- .get>(baseUrl)
- .pipe(map((response) => PreprintProvidersMapper.toPreprintProviderShortInfoFromGetResponse(response.data)));
+ .get>(baseUrl)
+ .pipe(map((response) => response.data.map((x) => PreprintModerationMapper.fromPreprintRelatedCounts(x))));
}
- getPreprintProvider(id: string): Observable {
+ getPreprintProvider(id: string): Observable {
const baseUrl = `${environment.apiUrl}/providers/preprints/${id}/?related_counts=true`;
return this.jsonApiService
.get>(baseUrl)
- .pipe(map((response) => PreprintReviewActionMapper.fromRelatedCounts(response.data)));
+ .pipe(map((response) => PreprintModerationMapper.fromPreprintRelatedCounts(response.data)));
}
getPreprintReviews(page = 1): Observable> {
@@ -40,6 +43,6 @@ export class PreprintModerationService {
return this.jsonApiService
.get>(baseUrl)
- .pipe(map((response) => PreprintReviewActionMapper.fromResponseWithPagination(response)));
+ .pipe(map((response) => PreprintModerationMapper.fromResponseWithPagination(response)));
}
}
diff --git a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.actions.ts b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.actions.ts
index 5033c0f46..8a7bc49af 100644
--- a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.actions.ts
+++ b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.actions.ts
@@ -9,3 +9,9 @@ export class GetPreprintReviewActions {
constructor(public page = 1) {}
}
+
+export class GetPreprintProvider {
+ static readonly type = `${ACTION_SCOPE} Get Preprint Provider`;
+
+ constructor(public providerId: string) {}
+}
diff --git a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.model.ts b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.model.ts
index 549e9a270..6ea91f8f8 100644
--- a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.model.ts
+++ b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.model.ts
@@ -1,10 +1,9 @@
-import { PreprintProviderShortInfo } from '@osf/features/preprints/models';
import { AsyncStateModel, AsyncStateWithTotalCount } from '@osf/shared/models';
-import { PreprintReviewActionModel } from '../../models';
+import { PreprintProviderModerationInfo, PreprintReviewActionModel } from '../../models';
export interface PreprintModerationStateModel {
- preprintProviders: AsyncStateModel;
+ preprintProviders: AsyncStateModel;
reviewActions: AsyncStateWithTotalCount;
}
diff --git a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.selectors.ts b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.selectors.ts
index 617925e8b..c59c38559 100644
--- a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.selectors.ts
+++ b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.selectors.ts
@@ -14,6 +14,11 @@ export class PreprintModerationSelectors {
return state.preprintProviders.isLoading;
}
+ @Selector([PreprintModerationState])
+ static getPreprintProvider(state: PreprintModerationStateModel) {
+ return (id: string) => state.preprintProviders.data.find((item) => item.id === id);
+ }
+
@Selector([PreprintModerationState])
static getPreprintReviews(state: PreprintModerationStateModel) {
return state.reviewActions.data;
diff --git a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.state.ts b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.state.ts
index e05df61e4..950c79d02 100644
--- a/src/app/features/moderation/store/preprint-moderation/preprint-moderation.state.ts
+++ b/src/app/features/moderation/store/preprint-moderation/preprint-moderation.state.ts
@@ -1,5 +1,5 @@
import { Action, State, StateContext } from '@ngxs/store';
-import { patch } from '@ngxs/store/operators';
+import { insertItem, patch, updateItem } from '@ngxs/store/operators';
import { catchError, forkJoin, map, switchMap, tap } from 'rxjs';
@@ -9,7 +9,7 @@ import { handleSectionError } from '@osf/core/handlers';
import { PreprintModerationService } from '../../services';
-import { GetPreprintProviders, GetPreprintReviewActions } from './preprint-moderation.actions';
+import { GetPreprintProvider, GetPreprintProviders, GetPreprintReviewActions } from './preprint-moderation.actions';
import { PREPRINT_MODERATION_STATE_DEFAULTS, PreprintModerationStateModel } from './preprint-moderation.model';
@State({
@@ -24,14 +24,14 @@ export class PreprintModerationState {
getPreprintProviders(ctx: StateContext) {
ctx.setState(patch({ preprintProviders: patch({ isLoading: true }) }));
- return this.preprintModerationService.getPreprintProvidersToModerate().pipe(
+ return this.preprintModerationService.getPreprintProviders().pipe(
switchMap((items) =>
forkJoin(
items.map((item) =>
this.preprintModerationService.getPreprintProvider(item.id).pipe(
- map((totalCount) => ({
+ map((res) => ({
...item,
- submissionCount: totalCount,
+ submissionCount: res.submissionCount,
}))
)
)
@@ -70,4 +70,25 @@ export class PreprintModerationState {
catchError((error) => handleSectionError(ctx, 'reviewActions', error))
);
}
+
+ @Action(GetPreprintProvider)
+ getPreprintProvider(ctx: StateContext, { providerId }: GetPreprintProvider) {
+ ctx.setState(patch({ preprintProviders: patch({ isLoading: true }) }));
+
+ return this.preprintModerationService.getPreprintProvider(providerId).pipe(
+ tap((data) => {
+ const exists = ctx.getState().preprintProviders.data.some((p) => p.id === data.id);
+
+ ctx.setState(
+ patch({
+ preprintProviders: patch({
+ data: exists ? updateItem((p) => p.id === data.id, data) : insertItem(data),
+ isLoading: false,
+ }),
+ })
+ );
+ }),
+ catchError((error) => handleSectionError(ctx, 'preprintProviders', error))
+ );
+ }
}
diff --git a/src/app/shared/constants/constants.ts b/src/app/shared/constants/constants.ts
new file mode 100644
index 000000000..c5e6b7edd
--- /dev/null
+++ b/src/app/shared/constants/constants.ts
@@ -0,0 +1 @@
+export const DEFAULT_SUPPORT_EMAIL = 'support@osf.io';
diff --git a/src/app/shared/constants/index.ts b/src/app/shared/constants/index.ts
index 9d3ae69f9..c8fbd40d4 100644
--- a/src/app/shared/constants/index.ts
+++ b/src/app/shared/constants/index.ts
@@ -1,6 +1,7 @@
export * from './addon-terms.const';
export * from './addons-category-options.const';
export * from './addons-tab-options.const';
+export * from './constants';
export * from './contributors';
export * from './filter-placeholders';
export * from './input-limits.const';