Skip to content
Merged
10 changes: 0 additions & 10 deletions src/app/features/moderation/models/moderator-json-api.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,4 @@ export interface ModeratorAddRequestModel {
full_name?: string;
email?: string;
};
// relationships: {
// users?: {
// data?: RelationshipUsersData;
// };
// };
}

interface RelationshipUsersData {
id?: string;
type?: 'users';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
@if (isCurrentResourceLoading() || isResourceConfirming()) {
<osf-loading-spinner></osf-loading-spinner>
} @else if (isPreviewMode() && currentResource()) {
<form class="flex flex-column gap-4" [formGroup]="form">
<p>{{ 'resources.check' | translate }}</p>

@let resourceType = currentResource()?.type;
@let iconName = resourceType === 'analytic_code' ? 'code' : resourceType;
@let icon = `assets/icons/colored/${iconName}-colored.svg`;
@let resourceName = resourceType === RegistryResourceType.Code ? 'Analytic Code' : resourceType;

<div class="flex align-content-end gap-3 content">
<img [src]="icon" alt="resource-type icon" class="align-self-start" />
<div class="flex flex-column gap-3 mt-1">
<div class="flex flex-column gap-2">
<h2>{{ resourceName }}</h2>
<a [href]="'https://doi/' + currentResource()?.pid">https://doi/{{ currentResource()?.pid }}</a>
</div>
<p>{{ currentResource()?.description }}</p>
</div>
</div>

<div class="flex justify-content-between w-full gap-1">
<p-button
class="btn-full-width"
[label]="'common.buttons.edit' | translate"
severity="info"
(click)="backToEdit()"
/>
<p-button
class="btn-full-width"
[label]="'resources.add' | translate"
severity="primary"
(onClick)="onAddResource()"
/>
</div>
</form>
} @else {
<osf-resource-form
[formGroup]="form"
[showCancelButton]="true"
[showPreviewButton]="false"
[cancelButtonLabel]="'common.buttons.cancel'"
[primaryButtonLabel]="'common.buttons.preview'"
(cancelClicked)="closeDialog()"
(submitClicked)="previewResource()"
/>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.content {
overflow: hidden;
text-overflow: clip;
white-space: wrap;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-word;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { AddResourceDialogComponent } from './add-resource-dialog.component';

describe('AddResourceDialogComponent', () => {
let component: AddResourceDialogComponent;
let fixture: ComponentFixture<AddResourceDialogComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AddResourceDialogComponent],
}).compileComponents();

fixture = TestBed.createComponent(AddResourceDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { createDispatchMap, select } from '@ngxs/store';

import { TranslatePipe, TranslateService } from '@ngx-translate/core';

import { Button } from 'primeng/button';
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';

import { finalize, take } from 'rxjs';

import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';

import { LoadingSpinnerComponent } from '@osf/shared/components';
import { InputLimits } from '@osf/shared/constants';
import { RegistryResourceType } from '@osf/shared/enums';
import { SelectOption } from '@osf/shared/models';
import { CustomValidators } from '@osf/shared/utils';

import { resourceTypeOptions } from '../../constants';
import { AddResource, ConfirmAddResource } from '../../models';
import {
ConfirmAddRegistryResource,
PreviewRegistryResource,
RegistryResourcesSelectors,
SilentDelete,
} from '../../store/registry-resources';
import { ResourceFormComponent } from '../resource-form/resource-form.component';

@Component({
selector: 'osf-add-resource-dialog',
imports: [Button, TranslatePipe, ReactiveFormsModule, LoadingSpinnerComponent, ResourceFormComponent],
templateUrl: './add-resource-dialog.component.html',
styleUrl: './add-resource-dialog.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AddResourceDialogComponent {
protected readonly dialogRef = inject(DynamicDialogRef);
protected readonly currentResource = select(RegistryResourcesSelectors.getCurrentResource);
protected readonly isCurrentResourceLoading = select(RegistryResourcesSelectors.isCurrentResourceLoading);
private translateService = inject(TranslateService);

private dialogConfig = inject(DynamicDialogConfig);
private registryId: string = this.dialogConfig.data.id;

protected inputLimits = InputLimits;
protected isResourceConfirming = signal(false);

protected form = new FormGroup({
pid: new FormControl<string | null>('', [CustomValidators.requiredTrimmed(), CustomValidators.doiValidator]),
resourceType: new FormControl<string | null>('', [Validators.required]),
description: new FormControl<string | null>(''),
});

private readonly actions = createDispatchMap({
previewResource: PreviewRegistryResource,
confirmAddResource: ConfirmAddRegistryResource,
deleteResource: SilentDelete,
});

public resourceOptions = signal<SelectOption[]>(resourceTypeOptions);
public isPreviewMode = signal<boolean>(false);

protected readonly RegistryResourceType = RegistryResourceType;

previewResource(): void {
if (this.form.invalid) {
return;
}

const addResource: AddResource = {
pid: this.form.controls['pid'].value ?? '',
resource_type: this.form.controls['resourceType'].value ?? '',
description: this.form.controls['description'].value ?? '',
};

const currentResource = this.currentResource();
if (!currentResource) {
throw new Error(this.translateService.instant('resources.errors.noCurrentResource'));
}

this.actions.previewResource(currentResource.id, addResource).subscribe(() => {
this.isPreviewMode.set(true);
});
}

backToEdit() {
this.isPreviewMode.set(false);
}

onAddResource() {
const addResource: ConfirmAddResource = {
finalized: true,
};
const currentResource = this.currentResource();

if (!currentResource) {
throw new Error(this.translateService.instant('resources.errors.noRegistryId'));
}

this.isResourceConfirming.set(true);
this.actions
.confirmAddResource(addResource, currentResource.id, this.registryId)
.pipe(
take(1),
finalize(() => {
this.dialogRef.close(true);
this.isResourceConfirming.set(false);
})
)
.subscribe({});
}

closeDialog(): void {
this.dialogRef.close();
const currentResource = this.currentResource();
if (!currentResource) {
throw new Error(this.translateService.instant('resources.errors.noRegistryId'));
}
this.actions.deleteResource(currentResource.id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@if (isCurrentResourceLoading()) {
<osf-loading-spinner></osf-loading-spinner>
} @else {
<osf-resource-form
[formGroup]="form"
[showCancelButton]="true"
[showPreviewButton]="false"
[cancelButtonLabel]="'common.buttons.cancel'"
[primaryButtonLabel]="'common.buttons.save'"
(cancelClicked)="dialogRef.close()"
(submitClicked)="save()"
/>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { EditResourceDialogComponent } from './edit-resource-dialog.component';

describe('EditResourceDialogComponent', () => {
let component: EditResourceDialogComponent;
let fixture: ComponentFixture<EditResourceDialogComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [EditResourceDialogComponent],
}).compileComponents();

fixture = TestBed.createComponent(EditResourceDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { createDispatchMap, select } from '@ngxs/store';

import { TranslateService } from '@ngx-translate/core';

import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';

import { finalize, take } from 'rxjs';

import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';

import { LoadingSpinnerComponent } from '@osf/shared/components';
import { CustomValidators } from '@osf/shared/utils';

import { AddResource, RegistryResource } from '../../models';
import { RegistryResourcesSelectors, UpdateResource } from '../../store/registry-resources';
import { ResourceFormComponent } from '../resource-form/resource-form.component';

@Component({
selector: 'osf-edit-resource-dialog',
imports: [LoadingSpinnerComponent, ReactiveFormsModule, ResourceFormComponent],
templateUrl: './edit-resource-dialog.component.html',
styleUrl: './edit-resource-dialog.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EditResourceDialogComponent {
protected readonly dialogRef = inject(DynamicDialogRef);
protected readonly isCurrentResourceLoading = select(RegistryResourcesSelectors.isCurrentResourceLoading);
private translateService = inject(TranslateService);

private dialogConfig = inject(DynamicDialogConfig);
private registryId: string = this.dialogConfig.data.id;
private resource: RegistryResource = this.dialogConfig.data.resource as RegistryResource;

protected form = new FormGroup({
pid: new FormControl<string | null>('', [CustomValidators.requiredTrimmed(), CustomValidators.doiValidator]),
resourceType: new FormControl<string | null>('', [Validators.required]),
description: new FormControl<string | null>(''),
});

private readonly actions = createDispatchMap({
updateResource: UpdateResource,
});

constructor() {
this.form.patchValue({
pid: this.resource.pid || '',
resourceType: this.resource.type || '',
description: this.resource.description || '',
});
}

save() {
if (this.form.invalid) {
return;
}

const addResource: AddResource = {
pid: this.form.controls['pid'].value ?? '',
resource_type: this.form.controls['resourceType'].value ?? '',
description: this.form.controls['description'].value ?? '',
};

if (!this.resource.id) {
throw new Error(this.translateService.instant('resources.errors.noRegistryId'));
}

this.actions
.updateResource(this.registryId, this.resource.id, addResource)
.pipe(
take(1),
finalize(() => {
this.dialogRef.close(true);
})
)
.subscribe();
}
}
3 changes: 3 additions & 0 deletions src/app/features/registry/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export * from './add-resource-dialog/add-resource-dialog.component';
export * from './edit-resource-dialog/edit-resource-dialog.component';
export * from './registration-links-card/registration-links-card.component';
export * from './registry-revisions/registry-revisions.component';
export * from './registry-statuses/registry-statuses.component';
export * from './resource-form/resource-form.component';
export * from './withdraw-dialog/withdraw-dialog.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<form class="flex flex-column gap-4" [formGroup]="formGroup()" (ngSubmit)="handleSubmit()">
<osf-text-input
[control]="getControl('pid')"
[label]="'DOI'"
[placeholder]="'https://doi.org/'"
[maxLength]="inputLimits.name.maxLength"
>
@if (getControl('pid').hasError('invalidDoi')) {
<span>{{ 'resources.errors.doiValidation' | translate }}</span>
}
</osf-text-input>

<osf-form-select
[fullWidth]="true"
[options]="resourceOptions()"
[appendTo]="'body'"
[control]="getControl('resourceType')"
[placeholder]="'resources.selectAResourceType'"
/>

<div>
<label [for]="'coi-reason'">{{ 'resources.descriptionLabel' | translate }}</label>
<textarea class="w-full" pTextarea id="coi-reason" [rows]="3" [formControl]="getControl('description')"></textarea>
</div>

<div class="flex justify-content-between w-full gap-1">
@if (showCancelButton()) {
<p-button
class="btn-full-width"
[label]="cancelButtonLabel() | translate"
severity="info"
(click)="handleCancel()"
/>
}
<p-button
class="btn-full-width"
[label]="primaryButtonLabel() | translate"
(onClick)="handleSubmit()"
[disabled]="formGroup().invalid"
/>
</div>
</form>
Loading