mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge pull request #4488 from alexandrevryghem/w2p-117573_remove-observable-function-calls-from-template-7_x
[Port dspace-7_x] Removed observable function calls from template (part 2)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<div *ngIf="registryService.getActiveMetadataField() | async; then editheader; else createHeader"></div>
|
||||
<div *ngIf="activeMetadataField$ | async; then editheader; else createHeader"></div>
|
||||
|
||||
<ng-template #createHeader>
|
||||
<h2>{{messagePrefix + '.create' | translate}}</h2>
|
||||
|
@@ -11,7 +11,7 @@ import { RegistryService } from '../../../../core/registry/registry.service';
|
||||
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
|
||||
import { MetadataField } from '../../../../core/metadata/metadata-field.model';
|
||||
|
||||
@@ -90,6 +90,8 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
activeMetadataField$: Observable<MetadataField>;
|
||||
|
||||
constructor(public registryService: RegistryService,
|
||||
private formBuilderService: FormBuilderService,
|
||||
private translateService: TranslateService) {
|
||||
@@ -99,70 +101,64 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
|
||||
* Initialize the component, setting up the necessary Models for the dynamic form
|
||||
*/
|
||||
ngOnInit() {
|
||||
combineLatest([
|
||||
this.translateService.get(`${this.messagePrefix}.element`),
|
||||
this.translateService.get(`${this.messagePrefix}.qualifier`),
|
||||
this.translateService.get(`${this.messagePrefix}.scopenote`)
|
||||
]).subscribe(([element, qualifier, scopenote]) => {
|
||||
this.element = new DynamicInputModel({
|
||||
id: 'element',
|
||||
label: element,
|
||||
name: 'element',
|
||||
validators: {
|
||||
required: null,
|
||||
pattern: '^[^. ,]*$',
|
||||
maxLength: 64,
|
||||
},
|
||||
required: true,
|
||||
errorMessages: {
|
||||
pattern: 'error.validation.metadata.element.invalid-pattern',
|
||||
maxLength: 'error.validation.metadata.element.max-length',
|
||||
},
|
||||
});
|
||||
this.qualifier = new DynamicInputModel({
|
||||
id: 'qualifier',
|
||||
label: qualifier,
|
||||
name: 'qualifier',
|
||||
validators: {
|
||||
pattern: '^[^. ,]*$',
|
||||
maxLength: 64,
|
||||
},
|
||||
required: false,
|
||||
errorMessages: {
|
||||
pattern: 'error.validation.metadata.qualifier.invalid-pattern',
|
||||
maxLength: 'error.validation.metadata.qualifier.max-length',
|
||||
},
|
||||
});
|
||||
this.scopeNote = new DynamicTextAreaModel({
|
||||
id: 'scopeNote',
|
||||
label: scopenote,
|
||||
name: 'scopeNote',
|
||||
required: false,
|
||||
rows: 5,
|
||||
});
|
||||
this.formModel = [
|
||||
new DynamicFormGroupModel(
|
||||
{
|
||||
id: 'metadatadatafieldgroup',
|
||||
group:[this.element, this.qualifier, this.scopeNote]
|
||||
})
|
||||
];
|
||||
this.formGroup = this.formBuilderService.createFormGroup(this.formModel);
|
||||
this.registryService.getActiveMetadataField().subscribe((field: MetadataField): void => {
|
||||
if (field == null) {
|
||||
this.clearFields();
|
||||
} else {
|
||||
this.formGroup.patchValue({
|
||||
metadatadatafieldgroup: {
|
||||
element: field.element,
|
||||
qualifier: field.qualifier,
|
||||
scopeNote: field.scopeNote,
|
||||
},
|
||||
});
|
||||
this.element.disabled = true;
|
||||
this.qualifier.disabled = true;
|
||||
}
|
||||
});
|
||||
this.element = new DynamicInputModel({
|
||||
id: 'element',
|
||||
label: this.translateService.instant(`${this.messagePrefix}.element`),
|
||||
name: 'element',
|
||||
validators: {
|
||||
required: null,
|
||||
pattern: '^[^. ,]*$',
|
||||
maxLength: 64,
|
||||
},
|
||||
required: true,
|
||||
errorMessages: {
|
||||
pattern: 'error.validation.metadata.element.invalid-pattern',
|
||||
maxLength: 'error.validation.metadata.element.max-length',
|
||||
},
|
||||
});
|
||||
this.qualifier = new DynamicInputModel({
|
||||
id: 'qualifier',
|
||||
label: this.translateService.instant(`${this.messagePrefix}.qualifier`),
|
||||
name: 'qualifier',
|
||||
validators: {
|
||||
pattern: '^[^. ,]*$',
|
||||
maxLength: 64,
|
||||
},
|
||||
required: false,
|
||||
errorMessages: {
|
||||
pattern: 'error.validation.metadata.qualifier.invalid-pattern',
|
||||
maxLength: 'error.validation.metadata.qualifier.max-length',
|
||||
},
|
||||
});
|
||||
this.scopeNote = new DynamicTextAreaModel({
|
||||
id: 'scopeNote',
|
||||
label: this.translateService.instant(`${this.messagePrefix}.scopenote`),
|
||||
name: 'scopeNote',
|
||||
required: false,
|
||||
rows: 5,
|
||||
});
|
||||
this.formModel = [
|
||||
new DynamicFormGroupModel(
|
||||
{
|
||||
id: 'metadatadatafieldgroup',
|
||||
group:[this.element, this.qualifier, this.scopeNote]
|
||||
})
|
||||
];
|
||||
this.formGroup = this.formBuilderService.createFormGroup(this.formModel);
|
||||
this.registryService.getActiveMetadataField().subscribe((field: MetadataField): void => {
|
||||
if (field == null) {
|
||||
this.clearFields();
|
||||
} else {
|
||||
this.formGroup.patchValue({
|
||||
metadatadatafieldgroup: {
|
||||
element: field.element,
|
||||
qualifier: field.qualifier,
|
||||
scopeNote: field.scopeNote,
|
||||
},
|
||||
});
|
||||
this.element.disabled = true;
|
||||
this.qualifier.disabled = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<div class="container">
|
||||
<ds-alert [type]="'alert-info'" [content]="'item.edit.authorizations.heading'"></ds-alert>
|
||||
<ds-resource-policies [resourceType]="'item'" [resourceName]="(getItemName() | async)"
|
||||
[resourceUUID]="(getItemUUID() | async)">
|
||||
<ds-alert [type]="AlertType.Info" [content]="'item.edit.authorizations.heading'"></ds-alert>
|
||||
<ds-resource-policies [resourceType]="'item'" [resourceName]="itemName$ | async"
|
||||
[resourceUUID]="(item$ | async)?.id">
|
||||
</ds-resource-policies>
|
||||
<ng-container *ngFor="let bundle of (bundles$ | async); trackById">
|
||||
<ng-container *ngFor="let bundle of (bundles$ | async)">
|
||||
<ds-resource-policies [resourceType]="'bundle'" [resourceUUID]="bundle.id" [resourceName]="bundle.name">
|
||||
</ds-resource-policies>
|
||||
<ng-container *ngIf="(bundleBitstreamsMap.get(bundle.id)?.bitstreams | async)?.length > 0">
|
||||
@@ -16,7 +16,7 @@
|
||||
</div>
|
||||
<div class="card-body" [id]="bundle.id" [ngbCollapse]="bundleBitstreamsMap.get(bundle.id).isCollapsed">
|
||||
<ng-container
|
||||
*ngFor="let bitstream of (bundleBitstreamsMap.get(bundle.id).bitstreams | async); trackById">
|
||||
*ngFor="let bitstream of (bundleBitstreamsMap.get(bundle.id).bitstreams | async)">
|
||||
<ds-resource-policies [resourceType]="'bitstream'" [resourceUUID]="bitstream.id"
|
||||
[resourceName]="bitstream.name"></ds-resource-policies>
|
||||
</ng-container>
|
||||
|
@@ -147,17 +147,9 @@ describe('ItemAuthorizationsComponent test suite', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('should get the item UUID', () => {
|
||||
|
||||
expect(comp.getItemUUID()).toBeObservable(cold('(a|)', {
|
||||
a: item.id
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
it('should get the item\'s bundle', () => {
|
||||
|
||||
expect(comp.getItemBundles()).toBeObservable(cold('a', {
|
||||
expect(comp.bundles$).toBeObservable(cold('a', {
|
||||
a: bundles
|
||||
}));
|
||||
|
||||
|
@@ -4,7 +4,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs';
|
||||
import { catchError, filter, first, map, mergeMap, take } from 'rxjs/operators';
|
||||
import { catchError, filter, map, mergeMap, take } from 'rxjs/operators';
|
||||
|
||||
import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
|
||||
import {
|
||||
@@ -17,6 +17,7 @@ import { LinkService } from '../../../core/cache/builders/link.service';
|
||||
import { Bundle } from '../../../core/shared/bundle.model';
|
||||
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||
import { Bitstream } from '../../../core/shared/bitstream.model';
|
||||
import { AlertType } from '../../../shared/alert/alert-type';
|
||||
|
||||
/**
|
||||
* Interface for a bundle's bitstream map entry
|
||||
@@ -52,7 +53,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy {
|
||||
* The target editing item
|
||||
* @type {Observable<Item>}
|
||||
*/
|
||||
private item$: Observable<Item>;
|
||||
item$: Observable<Item>;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
@@ -91,16 +92,13 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
private bitstreamPageSize = 4;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {LinkService} linkService
|
||||
* @param {ActivatedRoute} route
|
||||
* @param nameService
|
||||
*/
|
||||
itemName$: Observable<string>;
|
||||
|
||||
readonly AlertType = AlertType;
|
||||
|
||||
constructor(
|
||||
private linkService: LinkService,
|
||||
private route: ActivatedRoute,
|
||||
protected linkService: LinkService,
|
||||
protected route: ActivatedRoute,
|
||||
public nameService: DSONameService
|
||||
) {
|
||||
}
|
||||
@@ -109,37 +107,19 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy {
|
||||
* Initialize the component, setting up the bundle and bitstream within the item
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.getBundlesPerItem();
|
||||
this.getBundlesPerItem();
|
||||
this.itemName$ = this.getItemName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the item's UUID
|
||||
* Return the item's name
|
||||
*/
|
||||
getItemUUID(): Observable<string> {
|
||||
return this.item$.pipe(
|
||||
map((item: Item) => item.id),
|
||||
first((UUID: string) => isNotEmpty(UUID))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the item's name
|
||||
*/
|
||||
getItemName(): Observable<string> {
|
||||
private getItemName(): Observable<string> {
|
||||
return this.item$.pipe(
|
||||
map((item: Item) => this.nameService.getName(item))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all item's bundles
|
||||
*
|
||||
* @return an observable that emits all item's bundles
|
||||
*/
|
||||
getItemBundles(): Observable<Bundle[]> {
|
||||
return this.bundles$.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bundles per item
|
||||
* and all the bitstreams per bundle
|
||||
|
@@ -1,18 +1,18 @@
|
||||
<div class="container mb-5">
|
||||
<h1>{{'person.orcid.registry.auth' | translate}}</h1>
|
||||
<ng-container *ngIf="(isLinkedToOrcid() | async); then orcidLinked; else orcidNotLinked"></ng-container>
|
||||
<ng-container *ngIf="(isOrcidLinked$ | async); then orcidLinked; else orcidNotLinked"></ng-container>
|
||||
</div>
|
||||
|
||||
<ng-template #orcidLinked>
|
||||
<div data-test="orcidLinked">
|
||||
<div class="row">
|
||||
<div *ngIf="(hasOrcidAuthorizations() | async)" class="col-sm-6 mb-3" data-test="hasOrcidAuthorizations">
|
||||
<div *ngIf="(hasOrcidAuthorizations$ | async)" class="col-sm-6 mb-3" data-test="hasOrcidAuthorizations">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">{{ 'person.page.orcid.granted-authorizations'| translate }}</div>
|
||||
<div class="card-body">
|
||||
<div class="container p-0">
|
||||
<ul>
|
||||
<li *ngFor="let auth of (getOrcidAuthorizations() | async)" data-test="orcidAuthorization">
|
||||
<li *ngFor="let auth of profileAuthorizationScopes$ | async" data-test="orcidAuthorization">
|
||||
{{getAuthorizationDescription(auth) | translate}}
|
||||
</li>
|
||||
</ul>
|
||||
@@ -25,13 +25,13 @@
|
||||
<div class="card-header">{{ 'person.page.orcid.missing-authorizations'| translate }}</div>
|
||||
<div class="card-body">
|
||||
<div class="container">
|
||||
<ds-alert *ngIf="!(hasMissingOrcidAuthorizations() | async)" [type]="'alert-success'" data-test="noMissingOrcidAuthorizations">
|
||||
<ds-alert *ngIf="!(hasMissingOrcidAuthorizations$ | async)" [type]="AlertType.Success" data-test="noMissingOrcidAuthorizations">
|
||||
{{'person.page.orcid.no-missing-authorizations-message' | translate}}
|
||||
</ds-alert>
|
||||
<ds-alert *ngIf="(hasMissingOrcidAuthorizations() | async)" [type]="'alert-warning'" data-test="missingOrcidAuthorizations">
|
||||
<ds-alert *ngIf="(hasMissingOrcidAuthorizations$ | async)" [type]="AlertType.Warning" data-test="missingOrcidAuthorizations">
|
||||
{{'person.page.orcid.missing-authorizations-message' | translate}}
|
||||
<ul>
|
||||
<li *ngFor="let auth of (getMissingOrcidAuthorizations() | async)" data-test="missingOrcidAuthorization">
|
||||
<li *ngFor="let auth of profileAuthorizationScopes$ | async" data-test="missingOrcidAuthorization">
|
||||
{{getAuthorizationDescription(auth) | translate }}
|
||||
</li>
|
||||
</ul>
|
||||
@@ -41,11 +41,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ds-alert *ngIf="(onlyAdminCanDisconnectProfileFromOrcid() | async) && !(ownerCanDisconnectProfileFromOrcid() | async)"
|
||||
[type]="'alert-warning'" data-test="unlinkOnlyAdmin">
|
||||
<ds-alert *ngIf="(onlyAdminCanDisconnectProfileFromOrcid$ | async) && !(ownerCanDisconnectProfileFromOrcid$ | async)"
|
||||
[type]="AlertType.Warning" data-test="unlinkOnlyAdmin">
|
||||
{{ 'person.page.orcid.remove-orcid-message' | translate}}
|
||||
</ds-alert>
|
||||
<div class="row" *ngIf="(ownerCanDisconnectProfileFromOrcid() | async)" data-test="unlinkOwner">
|
||||
<div class="row" *ngIf="(ownerCanDisconnectProfileFromOrcid$ | async)" data-test="unlinkOwner">
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-danger float-right" (click)="unlinkOrcid()"
|
||||
[dsBtnDisabled]="(unlinkProcessing | async)">
|
||||
@@ -54,7 +54,7 @@
|
||||
<span *ngIf="(unlinkProcessing | async)"><i
|
||||
class='fas fa-circle-notch fa-spin'></i> {{'person.page.orcid.unlink.processing' | translate}}</span>
|
||||
</button>
|
||||
<button *ngIf="(hasMissingOrcidAuthorizations() | async)" type="submit"
|
||||
<button *ngIf="(hasMissingOrcidAuthorizations$ | async)" type="submit"
|
||||
class="btn btn-primary float-right" (click)="linkOrcid()">
|
||||
<span><i class="fas fa-check"></i> {{ 'person.page.orcid.grant-authorizations' | translate }}</span>
|
||||
</button>
|
||||
@@ -68,7 +68,7 @@
|
||||
<div class="row">
|
||||
<div class="col-2"><img alt="orcid-logo" src="../../../../assets/images/orcid.logo.icon.svg"/></div>
|
||||
<div class="col">
|
||||
<ds-alert [type]="'alert-info'">{{ getOrcidNotLinkedMessage() | async }}</ds-alert>
|
||||
<ds-alert [type]="AlertType.Info">{{ getOrcidNotLinkedMessage() }}</ds-alert>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@@ -12,6 +12,7 @@ import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||
import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service';
|
||||
import { createFailedRemoteDataObject } from '../../../shared/remote-data.utils';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { AlertType } from '../../../shared/alert/alert-type';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-orcid-auth',
|
||||
@@ -28,43 +29,49 @@ export class OrcidAuthComponent implements OnInit, OnChanges {
|
||||
/**
|
||||
* The list of exposed orcid authorization scopes for the orcid profile
|
||||
*/
|
||||
profileAuthorizationScopes: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
|
||||
profileAuthorizationScopes$: BehaviorSubject<string[]> = new BehaviorSubject([]);
|
||||
|
||||
hasOrcidAuthorizations$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* The list of all orcid authorization scopes missing in the orcid profile
|
||||
*/
|
||||
missingAuthorizationScopes: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
|
||||
missingAuthorizationScopes: BehaviorSubject<string[]> = new BehaviorSubject([]);
|
||||
|
||||
hasMissingOrcidAuthorizations$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* The list of all orcid authorization scopes available
|
||||
*/
|
||||
orcidAuthorizationScopes: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
|
||||
orcidAuthorizationScopes: BehaviorSubject<string[]> = new BehaviorSubject([]);
|
||||
|
||||
/**
|
||||
* A boolean representing if unlink operation is processing
|
||||
*/
|
||||
unlinkProcessing: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
unlinkProcessing: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
|
||||
/**
|
||||
* A boolean representing if orcid profile is linked
|
||||
*/
|
||||
private isOrcidLinked$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
isOrcidLinked$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
|
||||
/**
|
||||
* A boolean representing if only admin can disconnect orcid profile
|
||||
*/
|
||||
private onlyAdminCanDisconnectProfileFromOrcid$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
onlyAdminCanDisconnectProfileFromOrcid$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
|
||||
/**
|
||||
* A boolean representing if owner can disconnect orcid profile
|
||||
*/
|
||||
private ownerCanDisconnectProfileFromOrcid$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
ownerCanDisconnectProfileFromOrcid$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
|
||||
/**
|
||||
* An event emitted when orcid profile is unliked successfully
|
||||
*/
|
||||
@Output() unlink: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
readonly AlertType = AlertType;
|
||||
|
||||
constructor(
|
||||
private orcidAuthService: OrcidAuthService,
|
||||
private translateService: TranslateService,
|
||||
@@ -78,6 +85,8 @@ export class OrcidAuthComponent implements OnInit, OnChanges {
|
||||
this.orcidAuthorizationScopes.next(scopes);
|
||||
this.initOrcidAuthSettings();
|
||||
});
|
||||
this.hasOrcidAuthorizations$ = this.hasOrcidAuthorizations();
|
||||
this.hasMissingOrcidAuthorizations$ = this.hasMissingOrcidAuthorizations();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
@@ -90,18 +99,11 @@ export class OrcidAuthComponent implements OnInit, OnChanges {
|
||||
* Check if the list of exposed orcid authorization scopes for the orcid profile has values
|
||||
*/
|
||||
hasOrcidAuthorizations(): Observable<boolean> {
|
||||
return this.profileAuthorizationScopes.asObservable().pipe(
|
||||
return this.profileAuthorizationScopes$.pipe(
|
||||
map((scopes: string[]) => scopes.length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of exposed orcid authorization scopes for the orcid profile
|
||||
*/
|
||||
getOrcidAuthorizations(): Observable<string[]> {
|
||||
return this.profileAuthorizationScopes.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the list of exposed orcid authorization scopes for the orcid profile has values
|
||||
*/
|
||||
@@ -111,26 +113,12 @@ export class OrcidAuthComponent implements OnInit, OnChanges {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of exposed orcid authorization scopes for the orcid profile
|
||||
*/
|
||||
getMissingOrcidAuthorizations(): Observable<string[]> {
|
||||
return this.profileAuthorizationScopes.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean representing if orcid profile is linked
|
||||
*/
|
||||
isLinkedToOrcid(): Observable<boolean> {
|
||||
return this.isOrcidLinked$.asObservable();
|
||||
}
|
||||
|
||||
getOrcidNotLinkedMessage(): Observable<string> {
|
||||
getOrcidNotLinkedMessage(): string {
|
||||
const orcid = this.item.firstMetadataValue('person.identifier.orcid');
|
||||
if (orcid) {
|
||||
return this.translateService.get('person.page.orcid.orcid-not-linked-message', { 'orcid': orcid });
|
||||
return this.translateService.instant('person.page.orcid.orcid-not-linked-message', { 'orcid': orcid });
|
||||
} else {
|
||||
return this.translateService.get('person.page.orcid.no-orcid-message');
|
||||
return this.translateService.instant('person.page.orcid.no-orcid-message');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,13 +131,6 @@ export class OrcidAuthComponent implements OnInit, OnChanges {
|
||||
return 'person.page.orcid.scope.' + scope.substring(1).replace('/', '-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean representing if only admin can disconnect orcid profile
|
||||
*/
|
||||
onlyAdminCanDisconnectProfileFromOrcid(): Observable<boolean> {
|
||||
return this.onlyAdminCanDisconnectProfileFromOrcid$.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean representing if owner can disconnect orcid profile
|
||||
*/
|
||||
@@ -215,7 +196,7 @@ export class OrcidAuthComponent implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
private setOrcidAuthorizationsFromItem(): void {
|
||||
this.profileAuthorizationScopes.next(this.orcidAuthService.getOrcidAuthorizationScopesByItem(this.item));
|
||||
this.profileAuthorizationScopes$.next(this.orcidAuthService.getOrcidAuthorizationScopesByItem(this.item));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,13 +3,13 @@
|
||||
<div class="container">
|
||||
<h2>{{ 'person.orcid.registry.queue' | translate }}</h2>
|
||||
|
||||
<ds-alert *ngIf="!(processing$ | async) && (getList() | async)?.payload?.totalElements == 0"
|
||||
<ds-alert *ngIf="!(processing$ | async) && (list$ | async)?.payload?.totalElements == 0"
|
||||
[type]="AlertTypeEnum.Info">
|
||||
{{ 'person.page.orcid.sync-queue.empty-message' | translate}}
|
||||
</ds-alert>
|
||||
<ds-pagination *ngIf="!(processing$ | async) && (getList() | async)?.payload?.totalElements > 0"
|
||||
<ds-pagination *ngIf="!(processing$ | async) && (list$ | async)?.payload?.totalElements > 0"
|
||||
[paginationOptions]="paginationOptions"
|
||||
[collectionSize]="(getList() | async)?.payload?.totalElements"
|
||||
[collectionSize]="(list$ | async)?.payload?.totalElements"
|
||||
[retainScrollPosition]="false" [hideGear]="true" (paginationChange)="updateList()">
|
||||
|
||||
<div class="table-responsive">
|
||||
@@ -22,7 +22,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let entry of (getList() | async)?.payload?.page" data-test="orcidQueueElementRow">
|
||||
<tr *ngFor="let entry of (list$ | async)?.payload?.page" data-test="orcidQueueElementRow">
|
||||
<td style="width: 15%" class="text-center align-middle">
|
||||
<i [ngClass]="getIconClass(entry)" [ngbTooltip]="getIconTooltip(entry) | translate"
|
||||
class="fa-2x" aria-hidden="true"></i>
|
||||
|
@@ -47,13 +47,12 @@ export class OrcidQueueComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* A list of orcid queue records
|
||||
*/
|
||||
private list$: BehaviorSubject<RemoteData<PaginatedList<OrcidQueue>>> = new BehaviorSubject<RemoteData<PaginatedList<OrcidQueue>>>({} as any);
|
||||
list$: BehaviorSubject<RemoteData<PaginatedList<OrcidQueue>>> = new BehaviorSubject<RemoteData<PaginatedList<OrcidQueue>>>({} as any);
|
||||
|
||||
/**
|
||||
* The AlertType enumeration
|
||||
* @type {AlertType}
|
||||
*/
|
||||
AlertTypeEnum = AlertType;
|
||||
readonly AlertTypeEnum = AlertType;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
@@ -99,13 +98,6 @@ export class OrcidQueueComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of orcid queue records
|
||||
*/
|
||||
getList(): Observable<RemoteData<PaginatedList<OrcidQueue>>> {
|
||||
return this.list$.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the icon class for the queue object type
|
||||
*
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<nav [ngClass]="{'open': !(menuCollapsed | async)}"
|
||||
[@slideMobileNav]="!(windowService.isXsOrSm() | async) ? 'default' : ((menuCollapsed | async) ? 'collapsed' : 'expanded')"
|
||||
[@slideMobileNav]="(isMobile$ | async) !== true ? 'default' : ((menuCollapsed | async) ? 'collapsed' : 'expanded')"
|
||||
class="navbar navbar-light navbar-expand-md px-md-0 pt-md-0 pt-3 navbar-container" role="navigation"
|
||||
[attr.aria-label]="'nav.main.description' | translate" id="main-navbar">
|
||||
<!-- TODO remove navbar-container class when https://github.com/twbs/bootstrap/issues/24726 is fixed -->
|
||||
|
@@ -71,16 +71,16 @@
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div *ngIf="!(processBulkDeleteService.isProcessing$() |async)">{{'process.overview.delete.body' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }}</div>
|
||||
<div *ngIf="processBulkDeleteService.isProcessing$() |async" class="alert alert-info">
|
||||
<div *ngIf="(isProcessing$ | async) !== true">{{'process.overview.delete.body' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }}</div>
|
||||
<div *ngIf="(isProcessing$ | async) === true" class="alert alert-info">
|
||||
<span class="spinner-border spinner-border-sm spinner-button" role="status" aria-hidden="true"></span>
|
||||
<span> {{ 'process.overview.delete.processing' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }}</span>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<button class="btn btn-primary mr-2" [dsBtnDisabled]="processBulkDeleteService.isProcessing$() |async"
|
||||
<button class="btn btn-primary mr-2" [dsBtnDisabled]="(isProcessing$ | async) === true"
|
||||
(click)="closeModal()">{{'process.detail.delete.cancel' | translate}}</button>
|
||||
<button id="delete-confirm" class="btn btn-danger"
|
||||
[dsBtnDisabled]="processBulkDeleteService.isProcessing$() |async"
|
||||
[dsBtnDisabled]="(isProcessing$ | async) === true"
|
||||
(click)="deleteSelected()">{{ 'process.overview.delete' | translate: {count: processBulkDeleteService.getAmountOfSelectedProcesses()} }}
|
||||
</button>
|
||||
</div>
|
||||
|
@@ -51,11 +51,12 @@ export class ProcessOverviewComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
dateFormat = 'yyyy-MM-dd HH:mm:ss';
|
||||
|
||||
processesToDelete: string[] = [];
|
||||
private modalRef: any;
|
||||
|
||||
isProcessingSub: Subscription;
|
||||
|
||||
isProcessing$: Observable<boolean>;
|
||||
|
||||
constructor(protected processService: ProcessDataService,
|
||||
protected paginationService: PaginationService,
|
||||
protected ePersonService: EPersonDataService,
|
||||
@@ -69,6 +70,7 @@ export class ProcessOverviewComponent implements OnInit, OnDestroy {
|
||||
ngOnInit(): void {
|
||||
this.setProcesses();
|
||||
this.processBulkDeleteService.clearAllProcesses();
|
||||
this.isProcessing$ = this.processBulkDeleteService.isProcessing$();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -13,12 +13,12 @@
|
||||
<p>{{'researcher.profile.not.associated' | translate}}</p>
|
||||
</div>
|
||||
<button *ngIf="!researcherProfile" class="btn btn-primary mr-2"
|
||||
[dsBtnDisabled]="(isProcessingCreate() | async)"
|
||||
[dsBtnDisabled]="(processingCreate$ | async) === true"
|
||||
(click)="createProfile()">
|
||||
<span *ngIf="(isProcessingCreate() | async)">
|
||||
<span *ngIf="(processingCreate$ | async) === true">
|
||||
<i class='fas fa-circle-notch fa-spin'></i> {{'researcher.profile.action.processing' | translate}}
|
||||
</span>
|
||||
<span *ngIf="!(isProcessingCreate() | async)">
|
||||
<span *ngIf="(processingCreate$ | async) !== true">
|
||||
<i class="fas fa-plus"></i> {{'researcher.profile.create.new' | translate}}
|
||||
</span>
|
||||
</button>
|
||||
@@ -27,10 +27,10 @@
|
||||
<i class="fas fa-info-circle"></i> {{'researcher.profile.view' | translate}}
|
||||
</button>
|
||||
<button class="btn btn-danger" [dsBtnDisabled]="!researcherProfile" (click)="deleteProfile(researcherProfile)">
|
||||
<span *ngIf="(isProcessingDelete() | async)">
|
||||
<span *ngIf="(processingDelete$ | async) === true">
|
||||
<i class='fas fa-circle-notch fa-spin'></i> {{'researcher.profile.action.processing' | translate}}
|
||||
</span>
|
||||
<span *ngIf="!(isProcessingDelete() | async)">
|
||||
<span *ngIf="(processingDelete$ | async) !== true">
|
||||
<i class="fas fa-trash-alt"></i> {{'researcher.profile.delete' | translate}}
|
||||
</span>
|
||||
</button>
|
||||
|
@@ -3,7 +3,7 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { map, mergeMap, switchMap, take, tap } from 'rxjs/operators';
|
||||
|
||||
import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../../core/shared/operators';
|
||||
@@ -157,24 +157,6 @@ export class ProfilePageResearcherFormComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean representing if a delete operation is pending.
|
||||
*
|
||||
* @return {Observable<boolean>}
|
||||
*/
|
||||
isProcessingDelete(): Observable<boolean> {
|
||||
return this.processingDelete$.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean representing if a create operation is pending.
|
||||
*
|
||||
* @return {Observable<boolean>}
|
||||
*/
|
||||
isProcessingCreate(): Observable<boolean> {
|
||||
return this.processingCreate$.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new profile related to the current user from scratch.
|
||||
*/
|
||||
|
@@ -44,13 +44,13 @@
|
||||
<p class="m-0"><a href="javascript:void(0);" (click)="this.klaroService.showSettings()">{{ MESSAGE_PREFIX + '.google-recaptcha.open-cookie-settings' | translate }}</a></p>
|
||||
</ds-alert>
|
||||
|
||||
<div class="my-3" *ngIf="isRecaptchaCookieAccepted() && (googleRecaptchaService.captchaVersion() | async) === 'v2'">
|
||||
<ds-google-recaptcha [captchaMode]="(googleRecaptchaService.captchaMode() | async)"
|
||||
<div class="my-3" *ngIf="isRecaptchaCookieAccepted() && (captchaVersion$ | async) === 'v2'">
|
||||
<ds-google-recaptcha [captchaMode]="(captchaMode$ | async)"
|
||||
(executeRecaptcha)="register($event)" (checkboxChecked)="onCheckboxChecked($event)"
|
||||
(showNotification)="showNotification($event)"></ds-google-recaptcha>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="!((googleRecaptchaService.captchaVersion() | async) === 'v2' && (googleRecaptchaService.captchaMode() | async) === 'invisible'); else v2Invisible">
|
||||
<ng-container *ngIf="!((captchaVersion$ | async) === 'v2' && (captchaMode$ | async) === 'invisible'); else v2Invisible">
|
||||
<button class="btn btn-primary" [dsBtnDisabled]="form.invalid || registrationVerification && !isRecaptchaCookieAccepted() || disableUntilChecked" (click)="register()">
|
||||
{{ MESSAGE_PREFIX + '.submit' | translate }}
|
||||
</button>
|
||||
|
@@ -66,13 +66,9 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit {
|
||||
|
||||
subscriptions: Subscription[] = [];
|
||||
|
||||
captchaVersion(): Observable<string> {
|
||||
return this.googleRecaptchaService.captchaVersion();
|
||||
}
|
||||
captchaVersion$: Observable<string>;
|
||||
|
||||
captchaMode(): Observable<string> {
|
||||
return this.googleRecaptchaService.captchaMode();
|
||||
}
|
||||
captchaMode$: Observable<string>;
|
||||
|
||||
constructor(
|
||||
private epersonRegistrationService: EpersonRegistrationService,
|
||||
@@ -94,6 +90,8 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.captchaVersion$ = this.googleRecaptchaService.captchaVersion();
|
||||
this.captchaMode$ = this.googleRecaptchaService.captchaMode();
|
||||
const validators: ValidatorFn[] = [
|
||||
Validators.required,
|
||||
Validators.email,
|
||||
@@ -150,7 +148,7 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit {
|
||||
register(tokenV2?) {
|
||||
if (!this.form.invalid) {
|
||||
if (this.registrationVerification) {
|
||||
this.subscriptions.push(combineLatest([this.captchaVersion(), this.captchaMode()]).pipe(
|
||||
this.subscriptions.push(combineLatest([this.captchaVersion$, this.captchaMode$]).pipe(
|
||||
switchMap(([captchaVersion, captchaMode]) => {
|
||||
if (captchaVersion === 'v3') {
|
||||
return this.googleRecaptchaService.getRecaptchaToken('register_email');
|
||||
@@ -213,7 +211,7 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit {
|
||||
*/
|
||||
disableUntilCheckedFcn(): Observable<boolean> {
|
||||
const checked$ = this.checkboxCheckedSubject$.asObservable();
|
||||
return combineLatest([this.captchaVersion(), this.captchaMode(), checked$]).pipe(
|
||||
return combineLatest([this.captchaVersion$, this.captchaMode$, checked$]).pipe(
|
||||
// disable if checkbox is not checked or if reCaptcha is not in v2 checkbox mode
|
||||
switchMap(([captchaVersion, captchaMode, checked]) => captchaVersion === 'v2' && captchaMode === 'checkbox' ? of(!checked) : of(false)),
|
||||
startWith(true),
|
||||
|
@@ -2,35 +2,36 @@
|
||||
<ds-eperson-search-box *ngIf="isListOfEPerson" (search)="onSearch($event)"></ds-eperson-search-box>
|
||||
<ds-group-search-box *ngIf="!isListOfEPerson" (search)="onSearch($event)"></ds-group-search-box>
|
||||
|
||||
<ds-pagination *ngIf="(getList() | async)?.payload?.totalElements > 0"
|
||||
[paginationOptions]="paginationOptions"
|
||||
[collectionSize]="(getList() | async)?.payload?.totalElements"
|
||||
[retainScrollPosition]="true"
|
||||
[hideGear]="true">
|
||||
<ng-container *ngIf="(list$ | async) as list">
|
||||
<ds-pagination *ngIf="list.totalElements > 0"
|
||||
[paginationOptions]="paginationOptions"
|
||||
[collectionSize]="list.totalElements"
|
||||
[retainScrollPosition]="true"
|
||||
[hideGear]="true">
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="groups" class="table table-sm table-striped table-hover table-bordered">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th>{{'resource-policies.form.eperson-group-list.table.headers.id' | translate}}</th>
|
||||
<th>{{'resource-policies.form.eperson-group-list.table.headers.name' | translate}}</th>
|
||||
<th>{{'resource-policies.form.eperson-group-list.table.headers.action' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let entry of (getList() | async)?.payload?.page"
|
||||
[class.table-primary]="isSelected(entry) | async">
|
||||
<td>{{entry.id}}</td>
|
||||
<td>{{dsoNameService.getName(entry)}}</td>
|
||||
<td class="text-center">
|
||||
<button class="btn btn-sm btn-outline-primary" (click)="emitSelect(entry)">
|
||||
{{'resource-policies.form.eperson-group-list.select.btn' | translate}}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</ds-pagination>
|
||||
<div class="table-responsive">
|
||||
<table id="groups" class="table table-sm table-striped table-hover table-bordered">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th>{{ 'resource-policies.form.eperson-group-list.table.headers.id' | translate }}</th>
|
||||
<th>{{ 'resource-policies.form.eperson-group-list.table.headers.name' | translate }}</th>
|
||||
<th>{{ 'resource-policies.form.eperson-group-list.table.headers.action' | translate }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let entry of list.page"
|
||||
[class.table-primary]="(entrySelectedId$ | async) === entry.id">
|
||||
<td>{{ entry.id }}</td>
|
||||
<td>{{ dsoNameService.getName(entry) }}</td>
|
||||
<td class="text-center">
|
||||
<button class="btn btn-sm btn-outline-primary" (click)="emitSelect(entry)">
|
||||
{{ 'resource-policies.form.eperson-group-list.select.btn' | translate }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</ds-pagination>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
@@ -3,7 +3,7 @@ import { ChangeDetectorRef, Component, Injector, NO_ERRORS_SCHEMA } from '@angul
|
||||
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { cold } from 'jasmine-marbles';
|
||||
import { hot } from 'jasmine-marbles';
|
||||
import uniqueId from 'lodash/uniqueId';
|
||||
|
||||
import { createSuccessfulRemoteDataObject } from '../remote-data.utils';
|
||||
@@ -22,14 +22,13 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { PaginationService } from '../../core/pagination/pagination.service';
|
||||
import { PaginationServiceStub } from '../testing/pagination-service.stub';
|
||||
|
||||
describe('EpersonGroupListComponent test suite', () => {
|
||||
describe('EpersonGroupListComponent', () => {
|
||||
let comp: EpersonGroupListComponent;
|
||||
let compAsAny: any;
|
||||
let fixture: ComponentFixture<EpersonGroupListComponent>;
|
||||
let de;
|
||||
let groupService: any;
|
||||
let epersonService: any;
|
||||
let paginationService;
|
||||
let paginationService: PaginationServiceStub;
|
||||
|
||||
const paginationOptions: PaginationComponentOptions = new PaginationComponentOptions();
|
||||
paginationOptions.id = uniqueId('eperson-group-list-pagination-test');
|
||||
@@ -91,7 +90,6 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
}));
|
||||
|
||||
describe('', () => {
|
||||
let testComp: TestComponent;
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
|
||||
// synchronous beforeEach
|
||||
@@ -101,7 +99,6 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
<ds-eperson-group-list [isListOfEPerson]="isListOfEPerson" [initSelected]="initSelected"></ds-eperson-group-list>`;
|
||||
|
||||
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
||||
testComp = testFixture.componentInstance;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -129,7 +126,6 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
afterEach(() => {
|
||||
comp = null;
|
||||
compAsAny = null;
|
||||
de = null;
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
@@ -147,16 +143,15 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(compAsAny.entrySelectedId.value).toBe(EPersonMock.id);
|
||||
expect(comp.entrySelectedId$.value).toBe(EPersonMock.id);
|
||||
});
|
||||
|
||||
it('should init the list of eperson', () => {
|
||||
epersonService.searchByScope.and.returnValue(observableOf(epersonPaginatedListRD));
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(compAsAny.list$.value).toEqual(epersonPaginatedListRD);
|
||||
expect(comp.getList()).toBeObservable(cold('a', {
|
||||
a: epersonPaginatedListRD
|
||||
expect(comp.list$).toBeObservable(hot('(a|)', {
|
||||
a: epersonPaginatedList,
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -165,23 +160,13 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
comp.emitSelect(EPersonMock);
|
||||
|
||||
expect(comp.select.emit).toHaveBeenCalled();
|
||||
expect(compAsAny.entrySelectedId.value).toBe(EPersonMock.id);
|
||||
expect(comp.entrySelectedId$.value).toBe(EPersonMock.id);
|
||||
});
|
||||
|
||||
it('should return true when entry is selected', () => {
|
||||
compAsAny.entrySelectedId.next(EPersonMock.id);
|
||||
it('should return the entrySelectedId$ value', () => {
|
||||
comp.entrySelectedId$.next(EPersonMock.id);
|
||||
|
||||
expect(comp.isSelected(EPersonMock)).toBeObservable(cold('a', {
|
||||
a: true
|
||||
}));
|
||||
});
|
||||
|
||||
it('should return false when entry is not selected', () => {
|
||||
compAsAny.entrySelectedId.next('');
|
||||
|
||||
expect(comp.isSelected(EPersonMock)).toBeObservable(cold('a', {
|
||||
a: false
|
||||
}));
|
||||
expect(comp.entrySelectedId$.value).toBe(EPersonMock.id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -199,7 +184,6 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
afterEach(() => {
|
||||
comp = null;
|
||||
compAsAny = null;
|
||||
de = null;
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
@@ -217,16 +201,15 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(compAsAny.entrySelectedId.value).toBe(GroupMock.id);
|
||||
expect(comp.entrySelectedId$.value).toBe(GroupMock.id);
|
||||
});
|
||||
|
||||
it('should init the list of group', () => {
|
||||
groupService.searchGroups.and.returnValue(observableOf(groupPaginatedListRD));
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(compAsAny.list$.value).toEqual(groupPaginatedListRD);
|
||||
expect(comp.getList()).toBeObservable(cold('a', {
|
||||
a: groupPaginatedListRD
|
||||
expect(comp.list$).toBeObservable(hot('(a|)', {
|
||||
a: groupPaginatedList,
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -235,27 +218,16 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
comp.emitSelect(GroupMock);
|
||||
|
||||
expect(comp.select.emit).toHaveBeenCalled();
|
||||
expect(compAsAny.entrySelectedId.value).toBe(GroupMock.id);
|
||||
expect(comp.entrySelectedId$.value).toBe(GroupMock.id);
|
||||
});
|
||||
|
||||
it('should return true when entry is selected', () => {
|
||||
compAsAny.entrySelectedId.next(EPersonMock.id);
|
||||
it('should return the entrySelectedId$ value', () => {
|
||||
comp.entrySelectedId$.next(GroupMock.id);
|
||||
|
||||
expect(comp.isSelected(EPersonMock)).toBeObservable(cold('a', {
|
||||
a: true
|
||||
}));
|
||||
});
|
||||
|
||||
it('should return false when entry is not selected', () => {
|
||||
compAsAny.entrySelectedId.next('');
|
||||
|
||||
expect(comp.isSelected(EPersonMock)).toBeObservable(cold('a', {
|
||||
a: false
|
||||
}));
|
||||
expect(comp.entrySelectedId$.value).toBe(GroupMock.id);
|
||||
});
|
||||
|
||||
it('should update list on search triggered', () => {
|
||||
const options: PaginationComponentOptions = comp.paginationOptions;
|
||||
const event: SearchEvent = {
|
||||
scope: 'metadata',
|
||||
query: 'test'
|
||||
@@ -263,7 +235,7 @@ describe('EpersonGroupListComponent test suite', () => {
|
||||
spyOn(comp, 'updateList');
|
||||
comp.onSearch(event);
|
||||
|
||||
expect(compAsAny.updateList).toHaveBeenCalledWith('metadata', 'test');
|
||||
expect(comp.updateList).toHaveBeenCalledWith('metadata', 'test');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,14 +1,12 @@
|
||||
import { Component, EventEmitter, Injector, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
|
||||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import uniqueId from 'lodash/uniqueId';
|
||||
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
||||
import { hasValue, isNotEmpty } from '../empty.util';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { EPERSON } from '../../core/eperson/models/eperson.resource-type';
|
||||
import { GROUP } from '../../core/eperson/models/group.resource-type';
|
||||
@@ -16,10 +14,12 @@ import { ResourceType } from '../../core/shared/resource-type';
|
||||
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
|
||||
import { GroupDataService } from '../../core/eperson/group-data.service';
|
||||
import { fadeInOut } from '../animations/fade';
|
||||
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
|
||||
import { getAllCompletedRemoteData, getRemoteDataPayload } from '../../core/shared/operators';
|
||||
import { PaginationService } from '../../core/pagination/pagination.service';
|
||||
import { FindListOptions } from '../../core/data/find-list-options.model';
|
||||
import { getDataServiceFor } from '../../core/data/base/data-service.decorator';
|
||||
import { EPerson } from '../../core/eperson/models/eperson.model';
|
||||
import { Group } from '../../core/eperson/models/group.model';
|
||||
|
||||
export interface SearchEvent {
|
||||
scope: string;
|
||||
@@ -79,21 +79,13 @@ export class EpersonGroupListComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* A list of eperson or group
|
||||
*/
|
||||
private list$: BehaviorSubject<RemoteData<PaginatedList<DSpaceObject>>> = new BehaviorSubject<RemoteData<PaginatedList<DSpaceObject>>>({} as any);
|
||||
list$: Observable<PaginatedList<EPerson | Group>>;
|
||||
|
||||
/**
|
||||
* The eperson or group's id selected
|
||||
* @type {string}
|
||||
*/
|
||||
private entrySelectedId: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
private subs: Subscription[] = [];
|
||||
|
||||
private pageConfigSub: Subscription;
|
||||
entrySelectedId$: BehaviorSubject<string> = new BehaviorSubject('');
|
||||
|
||||
/**
|
||||
* Initialize instance variables and inject the properly DataService
|
||||
@@ -119,7 +111,7 @@ export class EpersonGroupListComponent implements OnInit, OnDestroy {
|
||||
this.paginationOptions.pageSize = 5;
|
||||
|
||||
if (this.initSelected) {
|
||||
this.entrySelectedId.next(this.initSelected);
|
||||
this.entrySelectedId$.next(this.initSelected);
|
||||
}
|
||||
|
||||
this.updateList(this.currentSearchScope, this.currentSearchQuery);
|
||||
@@ -133,28 +125,9 @@ export class EpersonGroupListComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
emitSelect(entry: DSpaceObject): void {
|
||||
this.select.emit(entry);
|
||||
this.entrySelectedId.next(entry.id);
|
||||
this.entrySelectedId$.next(entry.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of eperson or group
|
||||
*/
|
||||
getList(): Observable<RemoteData<PaginatedList<DSpaceObject>>> {
|
||||
return this.list$.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean representing if a table row is selected
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isSelected(entry: DSpaceObject): Observable<boolean> {
|
||||
return this.entrySelectedId.asObservable().pipe(
|
||||
map((selectedId) => isNotEmpty(selectedId) && selectedId === entry.id)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method called on search
|
||||
*/
|
||||
@@ -169,38 +142,26 @@ export class EpersonGroupListComponent implements OnInit, OnDestroy {
|
||||
* Retrieve a paginate list of eperson or group
|
||||
*/
|
||||
updateList(scope: string, query: string): void {
|
||||
if (hasValue(this.pageConfigSub)) {
|
||||
this.pageConfigSub.unsubscribe();
|
||||
}
|
||||
this.pageConfigSub = this.paginationService.getCurrentPagination(this.paginationOptions.id, this.paginationOptions)
|
||||
.subscribe((paginationOptions) => {
|
||||
const options: FindListOptions = Object.assign({}, new FindListOptions(), {
|
||||
this.list$ = this.paginationService.getCurrentPagination(this.paginationOptions.id, this.paginationOptions).pipe(
|
||||
switchMap((paginationOptions) => {
|
||||
const options: FindListOptions = Object.assign(new FindListOptions(), {
|
||||
elementsPerPage: paginationOptions.pageSize,
|
||||
currentPage: paginationOptions.currentPage
|
||||
});
|
||||
currentPage: paginationOptions.currentPage,
|
||||
});
|
||||
|
||||
const search$: Observable<RemoteData<PaginatedList<DSpaceObject>>> = this.isListOfEPerson ?
|
||||
(this.dataService as EPersonDataService).searchByScope(scope, query, options) :
|
||||
(this.dataService as GroupDataService).searchGroups(query, options);
|
||||
|
||||
this.subs.push(search$.pipe(getFirstCompletedRemoteData())
|
||||
.subscribe((list: RemoteData<PaginatedList<DSpaceObject>>) => {
|
||||
if (hasValue(this.list$)) {
|
||||
this.list$.next(list);
|
||||
}
|
||||
})
|
||||
return this.isListOfEPerson ?
|
||||
(this.dataService as EPersonDataService).searchByScope(scope, query, options) :
|
||||
(this.dataService as GroupDataService).searchGroups(query, options);
|
||||
}),
|
||||
getAllCompletedRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.list$ = null;
|
||||
this.subs
|
||||
.filter((subscription) => hasValue(subscription))
|
||||
.forEach((subscription) => subscription.unsubscribe());
|
||||
this.paginationService.clearPagination(this.paginationOptions.id);
|
||||
}
|
||||
|
||||
|
@@ -137,10 +137,10 @@ export class HostWindowService {
|
||||
}
|
||||
|
||||
isXsOrSm(): Observable<boolean> {
|
||||
return observableCombineLatest(
|
||||
return observableCombineLatest([
|
||||
this.isXs(),
|
||||
this.isSm()
|
||||
).pipe(
|
||||
]).pipe(
|
||||
map(([isXs, isSm]) => isXs || isSm),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
|
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
<ng-content></ng-content>
|
||||
|
||||
<div *ngIf="shouldShowBottomPager | async">
|
||||
<div *ngIf="showBottomPager$ | async">
|
||||
<div *ngIf="showPaginator" class="pagination justify-content-center clearfix bottom">
|
||||
<ngb-pagination [attr.aria-label]="('pagination-control.page-number-bar' | translate) + paginationOptions.id"
|
||||
[boundaryLinks]="paginationOptions.boundaryLinks"
|
||||
|
@@ -184,6 +184,11 @@ export class PaginationComponent implements OnChanges, OnDestroy, OnInit {
|
||||
|
||||
public showingDetails$: Observable<PaginationDetails>;
|
||||
|
||||
/**
|
||||
* Whether the current pagination should show a bottom pages
|
||||
*/
|
||||
showBottomPager$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
@@ -213,7 +218,7 @@ export class PaginationComponent implements OnChanges, OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.collectionSize.currentValue !== changes.collectionSize.previousValue) {
|
||||
if (hasValue(changes.collectionSize)) {
|
||||
this.showingDetails$ = this.getShowingDetails(this.collectionSize);
|
||||
}
|
||||
}
|
||||
@@ -253,6 +258,7 @@ export class PaginationComponent implements OnChanges, OnDestroy, OnInit {
|
||||
this.sortField$ = this.paginationService.getCurrentSort(this.id, sortOptions).pipe(
|
||||
map((currentSort) => currentSort.field)
|
||||
);
|
||||
this.showBottomPager$ = this.shouldShowBottomPager;
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<div class="container">
|
||||
<h4 class="mb-3">{{'resource-policies.create.page.heading' | translate}} {{targetResourceName}}</h4>
|
||||
<h1 class="mb-3">{{'resource-policies.create.page.heading' | translate}} {{targetResourceName}}</h1>
|
||||
|
||||
<ds-resource-policy-form [isProcessing]="isProcessing()"
|
||||
(reset)="redirectToAuthorizationsPage()"
|
||||
|
@@ -82,6 +82,9 @@ export abstract class ThemedComponent<T> implements AfterViewInit, OnDestroy, On
|
||||
}
|
||||
|
||||
initComponentInstance(changes?: SimpleChanges) {
|
||||
if (hasValue(this.themeSub)) {
|
||||
this.themeSub.unsubscribe();
|
||||
}
|
||||
this.themeSub = this.themeService?.getThemeName$().subscribe(() => {
|
||||
this.renderComponentInstance(changes);
|
||||
});
|
||||
|
@@ -2,11 +2,11 @@
|
||||
#sectionAdd="ngbDropdown"
|
||||
placement="bottom-right"
|
||||
class="d-inline-block"
|
||||
[ngClass]="{'w-100': windowService.isXs()}">
|
||||
[ngClass]="{'w-100': isXs$}">
|
||||
<ng-container *ngIf="hasSections$ | async">
|
||||
<button class="btn btn-outline-primary dropdown-toggle"
|
||||
id="sectionControls"
|
||||
[ngClass]="{'w-100': (windowService.isXs() | async)}"
|
||||
[ngClass]="{'w-100': (isXs$ | async)}"
|
||||
ngbDropdownToggle>
|
||||
{{ 'submission.sections.general.add-more' | translate }} <i class="fa fa-plus" aria-hidden="true"></i>
|
||||
</button>
|
||||
@@ -14,7 +14,7 @@
|
||||
<div ngbDropdownMenu
|
||||
class="sections-dropdown-menu"
|
||||
aria-labelledby="sectionControls"
|
||||
[ngClass]="{'w-100': (windowService.isXs() | async)}">
|
||||
[ngClass]="{'w-100': (isXs$ | async)}">
|
||||
<button class="dropdown-item disabled" *ngIf="!(hasSections$ | async)">
|
||||
{{ 'submission.sections.general.no-sections' | translate }}
|
||||
</button>
|
||||
|
@@ -42,6 +42,11 @@ export class SubmissionFormSectionAddComponent implements OnInit {
|
||||
*/
|
||||
public hasSections$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* A boolean representing whether it's a small screen
|
||||
*/
|
||||
isXs$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
@@ -62,6 +67,7 @@ export class SubmissionFormSectionAddComponent implements OnInit {
|
||||
this.hasSections$ = this.sectionList$.pipe(
|
||||
map((list: SectionDataObject[]) => list.length > 0)
|
||||
);
|
||||
this.isXs$ = this.windowService.isXs();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<div class="container-fluid">
|
||||
<div *ngIf="!(isLoading() | async)" class="submission-form-header mb-3 d-flex flex-wrap position-sticky">
|
||||
<div *ngIf="(isLoading$ | async) !== true" class="submission-form-header mb-3 d-flex flex-wrap position-sticky">
|
||||
<div *ngIf="(uploadEnabled$ | async)" class="w-100">
|
||||
<ds-submission-upload-files [submissionId]="submissionId"
|
||||
[collectionId]="collectionId"
|
||||
@@ -26,14 +26,14 @@
|
||||
</div>
|
||||
|
||||
<div class="submission-form-content">
|
||||
<ds-themed-loading *ngIf="(isLoading() | async)" message="Loading..."></ds-themed-loading>
|
||||
<ds-themed-loading *ngIf="(isLoading$ | async) === true" [message]="'form.loading' | translate"></ds-themed-loading>
|
||||
<ng-container *ngFor="let object of (submissionSections | async)">
|
||||
<ds-submission-section-container [collectionId]="collectionId"
|
||||
[submissionId]="submissionId"
|
||||
[sectionData]="object"></ds-submission-section-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div *ngIf="!(isLoading() | async)" class="submission-form-footer mt-3 mb-3 position-sticky">
|
||||
<div *ngIf="(isLoading$ | async) !== true" class="submission-form-footer mt-3 mb-3 position-sticky">
|
||||
<ds-submission-form-footer [submissionId]="submissionId"></ds-submission-form-footer>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectorRef, Component, NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { of as observableOf } from 'rxjs';
|
||||
@@ -26,6 +26,7 @@ import { Item } from '../../core/shared/item.model';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { SectionsService } from '../sections/sections.service';
|
||||
import { VisibilityType } from '../sections/visibility-type';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
describe('SubmissionFormComponent', () => {
|
||||
|
||||
@@ -47,7 +48,9 @@ describe('SubmissionFormComponent', () => {
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [],
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
],
|
||||
declarations: [
|
||||
SubmissionFormComponent,
|
||||
TestComponent
|
||||
@@ -60,7 +63,6 @@ describe('SubmissionFormComponent', () => {
|
||||
ChangeDetectorRef,
|
||||
SubmissionFormComponent
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
@@ -117,7 +119,7 @@ describe('SubmissionFormComponent', () => {
|
||||
expect(compAsAny.submissionSections).toBeUndefined();
|
||||
expect(compAsAny.subs).toEqual([]);
|
||||
expect(submissionServiceStub.startAutoSave).not.toHaveBeenCalled();
|
||||
expect(comp.loading).toBeObservable(cold('(a|)', { a: true }));
|
||||
expect(comp.isLoading$).toBeObservable(cold('(a|)', { a: true }));
|
||||
done();
|
||||
});
|
||||
|
||||
|
@@ -88,7 +88,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
* A boolean representing if a submission form is pending
|
||||
* @type {Observable<boolean>}
|
||||
*/
|
||||
public loading: Observable<boolean> = observableOf(true);
|
||||
public isLoading$: Observable<boolean> = observableOf(true);
|
||||
|
||||
/**
|
||||
* Emits true when the submission config has bitstream uploading enabled in submission
|
||||
@@ -160,7 +160,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
this.uploadEnabled$ = this.sectionsService.isSectionTypeAvailable(this.submissionId, SectionsType.Upload);
|
||||
|
||||
// check if is submission loading
|
||||
this.loading = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
||||
this.isLoading$ = this.submissionService.getSubmissionObject(this.submissionId).pipe(
|
||||
filter(() => this.isActive),
|
||||
map((submission: SubmissionObjectEntry) => submission.isLoading),
|
||||
map((isLoading: boolean) => isLoading),
|
||||
@@ -266,13 +266,6 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if submission form is loading
|
||||
*/
|
||||
isLoading(): Observable<boolean> {
|
||||
return this.loading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if submission form is loading
|
||||
*/
|
||||
|
@@ -120,28 +120,26 @@
|
||||
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="getCcLicenseLink$()">
|
||||
<ng-container *ngVar="getCcLicenseLink$() | async as licenseLink">
|
||||
<div *ngIf="!licenseLink">
|
||||
<ds-themed-loading></ds-themed-loading>
|
||||
<ng-container *ngIf="ccLicenseLink$ | async as licenseLink">
|
||||
<div *ngIf="!licenseLink">
|
||||
<ds-themed-loading></ds-themed-loading>
|
||||
</div>
|
||||
<div *ngIf="licenseLink"
|
||||
class="mt-2 p-4 bg-light text-dark">
|
||||
<div>
|
||||
{{ 'submission.sections.ccLicense.link' | translate }}
|
||||
</div>
|
||||
<div *ngIf="licenseLink"
|
||||
class="mt-2 p-4 bg-light text-dark">
|
||||
<div>
|
||||
{{ 'submission.sections.ccLicense.link' | translate }}
|
||||
</div>
|
||||
<a class="license-link" href="{{ licenseLink }}" target="_blank" rel="noopener noreferrer">
|
||||
{{ licenseLink }}
|
||||
</a>
|
||||
<div class="m-2">
|
||||
<div (click)="setAccepted(!accepted)">
|
||||
<input type="checkbox"
|
||||
class="mr-2"
|
||||
title="accepted"
|
||||
[checked]="accepted">
|
||||
<span> {{ 'submission.sections.ccLicense.confirmation' | translate }}</span>
|
||||
</div>
|
||||
<a class="license-link" href="{{ licenseLink }}" target="_blank" rel="noopener noreferrer">
|
||||
{{ licenseLink }}
|
||||
</a>
|
||||
<div class="m-2">
|
||||
<div (click)="setAccepted(!accepted)">
|
||||
<input type="checkbox"
|
||||
class="mr-2"
|
||||
title="accepted"
|
||||
[checked]="accepted">
|
||||
<span> {{ 'submission.sections.ccLicense.confirmation' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, Inject, OnChanges, SimpleChanges, OnInit } from '@angular/core';
|
||||
import { Observable, of as observableOf, Subscription, tap } from 'rxjs';
|
||||
import { Field, Option, SubmissionCcLicence } from '../../../core/submission/models/submission-cc-license.model';
|
||||
import {
|
||||
@@ -15,7 +15,7 @@ import { SectionDataObject } from '../models/section-data.model';
|
||||
import { SectionsService } from '../sections.service';
|
||||
import { WorkspaceitemSectionCcLicenseObject } from '../../../core/submission/models/workspaceitem-section-cc-license.model';
|
||||
import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
|
||||
import { isNotEmpty } from '../../../shared/empty.util';
|
||||
import { isNotEmpty, hasValue, hasNoValue } from '../../../shared/empty.util';
|
||||
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
|
||||
import { SubmissionCcLicenseUrlDataService } from '../../../core/submission/submission-cc-license-url-data.service';
|
||||
import {ConfigurationDataService} from '../../../core/data/configuration-data.service';
|
||||
@@ -30,7 +30,7 @@ import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||
styleUrls: ['./submission-section-cc-licenses.component.scss']
|
||||
})
|
||||
@renderSectionFor(SectionsType.CcLicense)
|
||||
export class SubmissionSectionCcLicensesComponent extends SectionModelComponent {
|
||||
export class SubmissionSectionCcLicensesComponent extends SectionModelComponent implements OnChanges, OnInit {
|
||||
|
||||
/**
|
||||
* The form id
|
||||
@@ -106,6 +106,8 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
|
||||
return this.data.accepted;
|
||||
}
|
||||
|
||||
ccLicenseLink$: Observable<string>;
|
||||
|
||||
constructor(
|
||||
protected modalService: NgbModal,
|
||||
protected sectionService: SectionsService,
|
||||
@@ -125,6 +127,19 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
if (hasNoValue(this.ccLicenseLink$)) {
|
||||
this.ccLicenseLink$ = this.getCcLicenseLink$();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (hasValue(changes.sectionData) || hasValue(changes.submissionCcLicenses)) {
|
||||
this.ccLicenseLink$ = this.getCcLicenseLink$();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The data of this section.
|
||||
*/
|
||||
@@ -149,6 +164,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
|
||||
},
|
||||
uri: undefined,
|
||||
});
|
||||
this.ccLicenseLink$ = this.getCcLicenseLink$();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,6 +196,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
|
||||
},
|
||||
accepted: false,
|
||||
});
|
||||
this.ccLicenseLink$ = this.getCcLicenseLink$();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,18 +3,17 @@ Template for the identifiers submission section component
|
||||
@author Kim Shepherd
|
||||
-->
|
||||
<!-- Main identifier data -->
|
||||
<ng-container *ngVar="(getIdentifierData() | async) as identifierData">
|
||||
<ng-container *ngIf="identifierData && identifierData.identifiers">
|
||||
<div>
|
||||
<span>{{'submission.sections.identifiers.info' | translate}}</span>
|
||||
<ul>
|
||||
<ng-container *ngFor="let identifier of identifierData.identifiers">
|
||||
<ng-container *ngIf="identifierData.displayTypes.includes(identifier.identifierType) && identifier.value">
|
||||
<li>{{'submission.sections.identifiers.' + identifier.identifierType + '_label' | translate}}
|
||||
{{identifier.value}}</li>
|
||||
<ng-container *ngIf="(identifierData$ | async) as identifierData">
|
||||
<div *ngIf="identifierData.identifiers">
|
||||
<span>{{ 'submission.sections.identifiers.info' | translate }}</span>
|
||||
<ul>
|
||||
<ng-container *ngFor="let identifier of identifierData.identifiers">
|
||||
<ng-container *ngIf="identifierData.displayTypes.includes(identifier.identifierType) && identifier.value">
|
||||
<li>{{ 'submission.sections.identifiers.' + identifier.identifierType + '_label' | translate }}
|
||||
{{ identifier.value }}
|
||||
</li>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ul>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ul>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import {ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
|
||||
import { Observable, of as observableOf, Subscription } from 'rxjs';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { SectionsType } from '../sections-type';
|
||||
import { SectionModelComponent } from '../models/section.model';
|
||||
import { renderSectionFor } from '../sections-decorator';
|
||||
import { SectionDataObject } from '../models/section-data.model';
|
||||
import { SubmissionService } from '../../submission.service';
|
||||
import { AlertType } from '../../../shared/alert/alert-type';
|
||||
import { SectionsService } from '../sections.service';
|
||||
import { WorkspaceitemSectionIdentifiersObject } from '../../../core/submission/models/workspaceitem-section-identifiers.model';
|
||||
|
||||
@@ -26,11 +25,6 @@ import { WorkspaceitemSectionIdentifiersObject } from '../../../core/submission/
|
||||
|
||||
@renderSectionFor(SectionsType.Identifiers)
|
||||
export class SubmissionSectionIdentifiersComponent extends SectionModelComponent {
|
||||
/**
|
||||
* The Alert categories.
|
||||
* @type {AlertType}
|
||||
*/
|
||||
public AlertTypeEnum = AlertType;
|
||||
|
||||
/**
|
||||
* Variable to track if the section is loading.
|
||||
@@ -42,14 +36,7 @@ export class SubmissionSectionIdentifiersComponent extends SectionModelComponent
|
||||
* Observable identifierData subject
|
||||
* @type {Observable<WorkspaceitemSectionIdentifiersObject>}
|
||||
*/
|
||||
public identifierData$: Observable<WorkspaceitemSectionIdentifiersObject> = new Observable<WorkspaceitemSectionIdentifiersObject>();
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
public subbedIdentifierData: WorkspaceitemSectionIdentifiersObject;
|
||||
public identifierData$: Observable<WorkspaceitemSectionIdentifiersObject>;
|
||||
|
||||
/**
|
||||
* Initialize instance variables.
|
||||
@@ -71,10 +58,6 @@ export class SubmissionSectionIdentifiersComponent extends SectionModelComponent
|
||||
super(injectedCollectionId, injectedSectionData, injectedSubmissionId);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all instance variables and retrieve configuration.
|
||||
*/
|
||||
@@ -83,13 +66,6 @@ export class SubmissionSectionIdentifiersComponent extends SectionModelComponent
|
||||
this.identifierData$ = this.getIdentifierData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if identifier section has read-only visibility
|
||||
*/
|
||||
isReadOnly(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions, if needed.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user