Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dspace-cris-7' into DSC-1207
Browse files Browse the repository at this point in the history
  • Loading branch information
vins01-4science committed Sep 20, 2023
2 parents 636b5f5 + 3495ce0 commit 7ef26d4
Show file tree
Hide file tree
Showing 19 changed files with 273 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ <h2 id="header" class="border-bottom pb-2">{{'admin.registries.metadata.head' |
<th scope="col">{{'admin.registries.metadata.schemas.table.id' | translate}}</th>
<th scope="col">{{'admin.registries.metadata.schemas.table.namespace' | translate}}</th>
<th scope="col">{{'admin.registries.metadata.schemas.table.name' | translate}}</th>
<th scope="col">
<div class="d-flex justify-content-center">
{{'admin.registries.metadata.schemas.table.download' | translate}}
</div>
</th>
</tr>
</thead>
<tbody>
Expand All @@ -39,6 +44,13 @@ <h2 id="header" class="border-bottom pb-2">{{'admin.registries.metadata.head' |
<td class="selectable-row" (click)="editSchema(schema)"><a [routerLink]="[schema.prefix]">{{schema.id}}</a></td>
<td class="selectable-row" (click)="editSchema(schema)"><a [routerLink]="[schema.prefix]">{{schema.namespace}}</a></td>
<td class="selectable-row" (click)="editSchema(schema)"><a [routerLink]="[schema.prefix]">{{schema.prefix}}</a></td>
<td class="selectable-row">
<div class="d-flex justify-content-center">
<button class="btn btn-sm btn-outline-primary" (click)="onDownloadSchema(schema)">
<i class="fas fa-download" aria-hidden="true" ></i>
</button>
</div>
</td>
</tr>
</tbody>
</table>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MetadataRegistryComponent } from './metadata-registry.component';
import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
import { of as observableOf } from 'rxjs';
import { of, of as observableOf } from 'rxjs';
import { buildPaginatedList } from '../../../core/data/paginated-list.model';
import { TranslateModule } from '@ngx-translate/core';
import { By } from '@angular/platform-browser';
Expand All @@ -20,6 +20,9 @@ import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import {
MetadataSchemaExportService
} from '../../../shared/metadata-export/metadata-schema-export/metadata-schema-export.service';

describe('MetadataRegistryComponent', () => {
let comp: MetadataRegistryComponent;
Expand Down Expand Up @@ -75,7 +78,13 @@ describe('MetadataRegistryComponent', () => {
{ provide: RegistryService, useValue: registryServiceStub },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
{ provide: PaginationService, useValue: paginationService },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{
provide: MetadataSchemaExportService,
useValue: jasmine.createSpyObj('metadataSchemaExportService', {
exportSchema: of(1),
})
}
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(MetadataRegistryComponent, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
import { filter, map, switchMap, take } from 'rxjs/operators';
import { hasValue } from '../../../shared/empty.util';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { toFindListOptions } from '../../../shared/pagination/pagination.utils';
import { NoContent } from '../../../core/shared/NoContent.model';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { PaginationService } from '../../../core/pagination/pagination.service';
import {
MetadataSchemaExportService
} from '../../../shared/metadata-export/metadata-schema-export/metadata-schema-export.service';

@Component({
selector: 'ds-metadata-registry',
Expand Down Expand Up @@ -46,9 +48,9 @@ export class MetadataRegistryComponent {

constructor(private registryService: RegistryService,
private notificationsService: NotificationsService,
private router: Router,
private paginationService: PaginationService,
private translateService: TranslateService) {
private translateService: TranslateService,
private readonly metadataSchemaExportService: MetadataSchemaExportService) {
this.updateSchemas();
}

Expand Down Expand Up @@ -176,4 +178,14 @@ export class MetadataRegistryComponent {
this.paginationService.clearPagination(this.config.id);
}

onDownloadSchema(schema: MetadataSchema): void {
this.metadataSchemaExportService.exportSchema(schema)
.pipe(
take(1),
filter(Object)
).subscribe((processId: number) => {
const title = this.translateService.get('export-schema.process.title');
this.notificationsService.process(processId.toString(), 5000, title);
});
}
}
60 changes: 32 additions & 28 deletions src/app/core/cache/builders/remote-data-build.service.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
import { Injectable } from '@angular/core';
import {
AsyncSubject,
combineLatest as observableCombineLatest,
Observable,
of as observableOf,
} from 'rxjs';
import { map, switchMap, filter, distinctUntilKeyChanged, startWith } from 'rxjs/operators';
import { hasValue, isEmpty, isNotEmpty, hasNoValue, isUndefined } from '../../../shared/empty.util';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { followLink, FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
import { PaginatedList } from '../../data/paginated-list.model';
import { RemoteData } from '../../data/remote-data';
import { RequestService } from '../../data/request.service';
import { ObjectCacheService } from '../object-cache.service';
import { LinkService } from './link.service';
import { HALLink } from '../../shared/hal-link.model';
import { GenericConstructor } from '../../shared/generic-constructor';
import { getClassForType } from './build-decorators';
import { HALResource } from '../../shared/hal-resource.model';
import { PAGINATED_LIST } from '../../data/paginated-list.resource-type';
import { getUrlWithoutEmbedParams } from '../../index/index.selectors';
import { getResourceTypeValueFor } from '../object-cache.reducer';
import { hasSucceeded, isStale, RequestEntryState } from '../../data/request-entry-state.model';
import { getRequestFromRequestHref, getRequestFromRequestUUID } from '../../shared/request.operators';
import { RequestEntry } from '../../data/request-entry.model';
import { ResponseState } from '../../data/response-state.model';
import { getFirstCompletedRemoteData } from '../../shared/operators';
import {Injectable} from '@angular/core';
import {AsyncSubject, combineLatest as observableCombineLatest, lastValueFrom, Observable, of as observableOf,} from 'rxjs';
import {distinctUntilKeyChanged, filter, map, startWith, switchMap} from 'rxjs/operators';
import {hasNoValue, hasValue, isEmpty, isNotEmpty, isUndefined} from '../../../shared/empty.util';
import {createSuccessfulRemoteDataObject$} from '../../../shared/remote-data.utils';
import {followLink, FollowLinkConfig} from '../../../shared/utils/follow-link-config.model';
import {PaginatedList} from '../../data/paginated-list.model';
import {RemoteData} from '../../data/remote-data';
import {RequestService} from '../../data/request.service';
import {ObjectCacheService} from '../object-cache.service';
import {LinkService} from './link.service';
import {HALLink} from '../../shared/hal-link.model';
import {GenericConstructor} from '../../shared/generic-constructor';
import {getClassForType} from './build-decorators';
import {HALResource} from '../../shared/hal-resource.model';
import {PAGINATED_LIST} from '../../data/paginated-list.resource-type';
import {getUrlWithoutEmbedParams} from '../../index/index.selectors';
import {getResourceTypeValueFor} from '../object-cache.reducer';
import {hasSucceeded, isStale, RequestEntryState} from '../../data/request-entry-state.model';
import {getRequestFromRequestHref, getRequestFromRequestUUID} from '../../shared/request.operators';
import {RequestEntry} from '../../data/request-entry.model';
import {ResponseState} from '../../data/response-state.model';
import {getFirstCompletedRemoteData} from '../../shared/operators';

@Injectable()
export class RemoteDataBuildService {
Expand Down Expand Up @@ -233,6 +228,15 @@ export class RemoteDataBuildService {
);
}

async buildFromRequestUUIDAsync<T>(requestUUID$: string | Observable<string>, callback: (rd?: RemoteData<T>) => Observable<unknown>, ...linksToFollow: FollowLinkConfig<any>[]): Promise<RemoteData<T>> {
const response$ = this.buildFromRequestUUID(requestUUID$, ...linksToFollow);

const callbackDone$ = new AsyncSubject<boolean>();
return await lastValueFrom(response$.pipe(
getFirstCompletedRemoteData<T>()
));
}

/**
* Creates a {@link RemoteData} object for a rest request and its response
*
Expand Down
47 changes: 47 additions & 0 deletions src/app/core/data/base/delete-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@ export interface DeleteData<T extends CacheableObject> {
* Only emits once all request related to the DSO has been invalidated.
*/
deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>>;

/**
* Delete an existing object on the server in async way
* @param objectId The id of the object to be removed
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
* metadata should be saved as real metadata
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
* errorMessage, timeCompleted, etc
*/
deleteAsync?(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>>;

/**
* Delete an existing object on the server in async way
* @param href The self link of the object to be removed
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
* metadata should be saved as real metadata
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
* errorMessage, timeCompleted, etc
* Only emits once all request related to the DSO has been invalidated.
*/
deleteByHrefAsync?(href: string, copyVirtualMetadata?: string[]): Promise<RemoteData<NoContent>>;
}

export class DeleteDataImpl<T extends CacheableObject> extends IdentifiableDataService<T> implements DeleteData<T> {
Expand Down Expand Up @@ -84,4 +105,30 @@ export class DeleteDataImpl<T extends CacheableObject> extends IdentifiableDataS

return this.rdbService.buildFromRequestUUIDAndAwait(requestId, () => this.invalidateByHref(href));
}

deleteAsync(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
return this.getIDHrefObs(objectId).pipe(
switchMap((href: string) => this.deleteByHrefAsync(href, copyVirtualMetadata)),
);
}

deleteByHrefAsync(href: string, copyVirtualMetadata?: string[]): Promise<RemoteData<NoContent>> {
const requestId = this.requestService.generateRequestId();

if (copyVirtualMetadata) {
copyVirtualMetadata.forEach((id) =>
href += (href.includes('?') ? '&' : '?')
+ 'copyVirtualMetadata='
+ id,
);
}

const request = new DeleteRequest(requestId, href);
if (hasValue(this.responseMsToLive)) {
request.responseMsToLive = this.responseMsToLive;
}
this.requestService.send(request);

return this.rdbService.buildFromRequestUUIDAsync<NoContent>(requestId, () => this.invalidateByHref(href));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ export class QualityAssuranceSuggestionDataService extends IdentifiableDataServi
return this.deleteData.delete(suggestionId);
}

public deleteSuggestionAsync(suggestionId: string): Observable<RemoteData<NoContent>> {
return this.deleteData.deleteAsync(suggestionId);
}


/**
* Return a Suggestion for a given user id
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div ds-metric-row
*ngFor="let metricRow of (metricRows | async)"
[metricRow]="metricRow"
class="row"
></div>
class="d-flex flex-wrap gap-3 mb-3">
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<ng-container *ngFor="let metric of metricRow.metrics">
<ng-container *ngIf="metric">
<ds-metric-loader [metric]="metric" class="col-3 mb-2"
<ds-metric-loader [metric]="metric"
[class.d-none]="(isHidden(metric.id) | async)"
(hide)="toggleVisibility(metric.id, $event)"></ds-metric-loader>
</ng-container>
Expand Down
23 changes: 21 additions & 2 deletions src/app/openaire/reciter-suggestions/suggestions.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';

import { forkJoin, Observable, of } from 'rxjs';
import { catchError, map, mergeMap, take } from 'rxjs/operators';
import { catchError, map, mergeMap, take, tap } from 'rxjs/operators';

import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { FindListOptions } from '../../core/data/find-list-options.model';
Expand Down Expand Up @@ -166,6 +166,19 @@ export class SuggestionsService {
);
}

public deleteReviewedSuggestionAsync(suggestionId: string): Observable<RemoteData<NoContent>> {
return this.suggestionsDataService.deleteSuggestionAsync(suggestionId).pipe(
tap((response: RemoteData<NoContent>) => {
if (response.isSuccess) {
return response;
} else {
throw new Error('Can\'t delete Suggestion from the Search Target REST service');
}
}),
take(1)
);
}

/**
* Retrieve suggestion targets for the given user
*
Expand Down Expand Up @@ -218,6 +231,12 @@ export class SuggestionsService {
);
}

public notMineAsync(suggestionId): Observable<RemoteData<NoContent>> {
return this.deleteReviewedSuggestionAsync(suggestionId).pipe(
catchError((error) => of(null))
);
}

/**
* Perform a bulk approve and import operation.
* @param workspaceitemService injected dependency
Expand All @@ -243,7 +262,7 @@ export class SuggestionsService {
* @param suggestions the array containing the suggestions
*/
public notMineMultiple(suggestions: OpenaireSuggestion[]): Observable<SuggestionBulkResult> {
return forkJoin(suggestions.map((suggestion: OpenaireSuggestion) => this.notMine(suggestion.id)))
return forkJoin(suggestions.map((suggestion: OpenaireSuggestion) => this.notMineAsync(suggestion.id)))
.pipe(map((results: RemoteData<NoContent>[]) => {
return {
success: results.filter((result) => result != null).length,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component, Inject, OnInit } from '@angular/core';
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';

import { BehaviorSubject, combineLatest } from 'rxjs';
import { take } from 'rxjs/operators';
import { BehaviorSubject, combineLatest, distinctUntilChanged, map, shareReplay, Subscription } from 'rxjs';

import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model';
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
Expand All @@ -11,6 +10,7 @@ import { ContextMenuEntryType } from '../context-menu-entry-type';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { DsoVersioningModalService } from '../../dso-page/dso-versioning-modal-service/dso-versioning-modal.service';
import { hasValue } from '../../empty.util';

@Component({
selector: 'ds-item-version-menu',
Expand All @@ -21,22 +21,22 @@ import { DsoVersioningModalService } from '../../dso-page/dso-versioning-modal-s
/**
* Display a button linking to the item versioning of a DSpaceObject
*/
export class ItemVersionMenuComponent extends ContextMenuEntryComponent implements OnInit {
export class ItemVersionMenuComponent extends ContextMenuEntryComponent implements OnInit, OnDestroy {

/**
* Whether or not the current user is authorized to subscribe the DSpaceObject
*/
canShow$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

/**
* EPerson id of the logged user
* DSpaceObject that is being viewed
*/
epersonId: string;
dso: DSpaceObject;

/**
* DSpaceObject that is being viewed
* Keep track of subscription to unsubscribe on component destroy
*/
dso: DSpaceObject;
sub: Subscription;

/**
* Initialize instance variables
Expand All @@ -59,12 +59,13 @@ export class ItemVersionMenuComponent extends ContextMenuEntryComponent implemen
const isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanCreateVersion, this.contextMenuObject.self);
const isDisabled$ = this.versioningModalService.isNewVersionButtonDisabled(this.contextMenuObject);

combineLatest([isAuthorized$, isDisabled$]).pipe(
take(1)
).subscribe(([isAuthorized, isDisabled]) => {
this.canShow$.next(isAuthorized && !isDisabled);
this.sub = combineLatest([isAuthorized$, isDisabled$]).pipe(
map(([isAuthorized, isDisabled]) => isAuthorized && !isDisabled),
distinctUntilChanged(),
shareReplay(1)
).subscribe((canShow) => {
this.canShow$.next(canShow);
});

}

/**
Expand All @@ -73,4 +74,10 @@ export class ItemVersionMenuComponent extends ContextMenuEntryComponent implemen
createNewVersion(): void {
this.versioningModalService.openCreateVersionModal(this.contextMenuObject);
}

ngOnDestroy(): void {
if (hasValue(this.sub)) {
this.sub.unsubscribe();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class DsDynamicTagComponent extends DsDynamicVocabularyComponent implemen
* Initialize the component, setting up the init form value
*/
ngOnInit() {
this.hasAuthority = this.model.vocabularyOptions && hasValue(this.model.vocabularyOptions.name);
this.hasAuthority = hasValue(this.model.vocabularyOptions) && hasValue(this.model.vocabularyOptions.name);

this.chips = new Chips(
this.model.value as any[],
Expand Down
Loading

0 comments on commit 7ef26d4

Please sign in to comment.