Merge branch 'DURACOM-234' into DURACOM-240-mathjax

This commit is contained in:
Giuseppe Digilio
2024-03-20 12:02:40 +01:00
36 changed files with 145 additions and 78 deletions

View File

@@ -1,6 +1,7 @@
import { import {
AsyncPipe, AsyncPipe,
NgClass, NgClass,
NgFor,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
@@ -83,6 +84,7 @@ import { ValidateEmailNotTaken } from './validators/email-taken.validator';
imports: [ imports: [
FormComponent, FormComponent,
NgIf, NgIf,
NgFor,
AsyncPipe, AsyncPipe,
TranslateModule, TranslateModule,
NgClass, NgClass,

View File

@@ -1,6 +1,7 @@
import { import {
AsyncPipe, AsyncPipe,
NgClass, NgClass,
NgFor,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
@@ -54,6 +55,7 @@ import { LdnService } from '../ldn-services-model/ldn-services.model';
changeDetection: ChangeDetectionStrategy.Default, changeDetection: ChangeDetectionStrategy.Default,
imports: [ imports: [
NgIf, NgIf,
NgFor,
TranslateModule, TranslateModule,
AsyncPipe, AsyncPipe,
PaginationComponent, PaginationComponent,

View File

@@ -1,7 +1,5 @@
import { SearchResult } from '../../../shared/search/models/search-result.model'; import { SearchResult } from '../../../shared/search/models/search-result.model';
import { searchResultFor } from '../../../shared/search/search-result-element-decorator';
import { AdminNotifyMessage } from './admin-notify-message.model'; import { AdminNotifyMessage } from './admin-notify-message.model';
@searchResultFor(AdminNotifyMessage)
export class AdminNotifySearchResult extends SearchResult<AdminNotifyMessage> { export class AdminNotifySearchResult extends SearchResult<AdminNotifyMessage> {
} }

View File

@@ -1,6 +1,7 @@
import { import {
AsyncPipe, AsyncPipe,
NgForOf, NgForOf,
NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
Component, Component,
@@ -59,6 +60,7 @@ import { QueryPredicate } from './query-predicate.model';
NgbAccordionModule, NgbAccordionModule,
TranslateModule, TranslateModule,
AsyncPipe, AsyncPipe,
NgIf,
NgForOf, NgForOf,
FiltersComponent, FiltersComponent,
], ],

View File

@@ -8,7 +8,10 @@ import {
OnInit, OnInit,
} from '@angular/core'; } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs'; import {
BehaviorSubject,
Observable,
} from 'rxjs';
import { import {
APP_CONFIG, APP_CONFIG,
@@ -20,7 +23,7 @@ import { RemoteData } from '../../../../../core/data/remote-data';
import { Context } from '../../../../../core/shared/context.model'; import { Context } from '../../../../../core/shared/context.model';
import { Item } from '../../../../../core/shared/item.model'; import { Item } from '../../../../../core/shared/item.model';
import { import {
getAllSucceededRemoteData, getFirstCompletedRemoteData,
getRemoteDataPayload, getRemoteDataPayload,
} from '../../../../../core/shared/operators'; } from '../../../../../core/shared/operators';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
@@ -49,7 +52,7 @@ export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends S
/** /**
* The item linked to the workflow item * The item linked to the workflow item
*/ */
public item$: Observable<Item>; public item$: BehaviorSubject<Item> = new BehaviorSubject<Item>(undefined);
constructor(private linkService: LinkService, constructor(private linkService: LinkService,
protected truncatableService: TruncatableService, protected truncatableService: TruncatableService,
@@ -65,6 +68,11 @@ export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends S
ngOnInit(): void { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.dso = this.linkService.resolveLink(this.dso, followLink('item')); this.dso = this.linkService.resolveLink(this.dso, followLink('item'));
this.item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()); (this.dso.item as Observable<RemoteData<Item>>).pipe(
getFirstCompletedRemoteData(),
getRemoteDataPayload())
.subscribe((item: Item) => {
this.item$.next(item);
});
} }
} }

View File

@@ -31,7 +31,6 @@ import { Context } from '../../../../../core/shared/context.model';
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model'; import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
import { Item } from '../../../../../core/shared/item.model'; import { Item } from '../../../../../core/shared/item.model';
import { import {
getAllSucceededRemoteData,
getFirstCompletedRemoteData, getFirstCompletedRemoteData,
getRemoteDataPayload, getRemoteDataPayload,
} from '../../../../../core/shared/operators'; } from '../../../../../core/shared/operators';
@@ -63,7 +62,7 @@ export class WorkspaceItemSearchResultAdminWorkflowListElementComponent extends
/** /**
* The item linked to the workflow item * The item linked to the workflow item
*/ */
public item$: Observable<Item>; public item$: BehaviorSubject<Item> = new BehaviorSubject<Item>(undefined);
/** /**
* The id of the item linked to the workflow item * The id of the item linked to the workflow item
@@ -90,11 +89,14 @@ export class WorkspaceItemSearchResultAdminWorkflowListElementComponent extends
ngOnInit(): void { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.dso = this.linkService.resolveLink(this.dso, followLink('item')); this.dso = this.linkService.resolveLink(this.dso, followLink('item'));
this.item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()); const item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getFirstCompletedRemoteData(), getRemoteDataPayload());
this.item$.pipe( item$.pipe(
take(1), take(1),
tap((item: Item) => this.itemId = item.id), tap((item: Item) => {
this.item$.next(item);
this.itemId = item.id;
}),
mergeMap((item: Item) => this.retrieveSupervisorOrders(item.id)), mergeMap((item: Item) => this.retrieveSupervisorOrders(item.id)),
).subscribe((supervisionOrderList: SupervisionOrder[]) => { ).subscribe((supervisionOrderList: SupervisionOrder[]) => {
this.supervisionOrder$.next(supervisionOrderList); this.supervisionOrder$.next(supervisionOrderList);

View File

@@ -1,7 +1,7 @@
import { import {
ExtraOptions, InMemoryScrollingOptions,
NoPreloading,
Route, Route,
RouterConfigOptions,
} from '@angular/router'; } from '@angular/router';
import { NOTIFICATIONS_MODULE_PATH } from './admin/admin-routing-paths'; import { NOTIFICATIONS_MODULE_PATH } from './admin/admin-routing-paths';
@@ -26,6 +26,7 @@ import { COMMUNITY_MODULE_PATH } from './community-page/community-page-routing-p
import { AuthBlockingGuard } from './core/auth/auth-blocking.guard'; import { AuthBlockingGuard } from './core/auth/auth-blocking.guard';
import { AuthenticatedGuard } from './core/auth/authenticated.guard'; import { AuthenticatedGuard } from './core/auth/authenticated.guard';
import { GroupAdministratorGuard } from './core/data/feature-authorization/feature-authorization-guard/group-administrator.guard'; import { GroupAdministratorGuard } from './core/data/feature-authorization/feature-authorization-guard/group-administrator.guard';
import { SiteAdministratorGuard } from './core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import { SiteRegisterGuard } from './core/data/feature-authorization/feature-authorization-guard/site-register.guard'; import { SiteRegisterGuard } from './core/data/feature-authorization/feature-authorization-guard/site-register.guard';
import { EndUserAgreementCurrentUserGuard } from './core/end-user-agreement/end-user-agreement-current-user.guard'; import { EndUserAgreementCurrentUserGuard } from './core/end-user-agreement/end-user-agreement-current-user.guard';
import { ReloadGuard } from './core/reload/reload.guard'; import { ReloadGuard } from './core/reload/reload.guard';
@@ -155,7 +156,7 @@ export const APP_ROUTES: Route[] = [
path: ADMIN_MODULE_PATH, path: ADMIN_MODULE_PATH,
loadChildren: () => import('./admin/admin-routes') loadChildren: () => import('./admin/admin-routes')
.then((m) => m.ROUTES), .then((m) => m.ROUTES),
canActivate: [EndUserAgreementCurrentUserGuard], canActivate: [SiteAdministratorGuard, EndUserAgreementCurrentUserGuard],
}, },
{ {
path: NOTIFICATIONS_MODULE_PATH, path: NOTIFICATIONS_MODULE_PATH,
@@ -260,12 +261,10 @@ export const APP_ROUTES: Route[] = [
], ],
}, },
]; ];
export const APP_ROUTING_CONF: ExtraOptions = { export const APP_ROUTING_CONF: RouterConfigOptions = {
// enableTracing: true,
useHash: false,
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
initialNavigation: 'enabledBlocking',
preloadingStrategy: NoPreloading,
onSameUrlNavigation: 'reload', onSameUrlNavigation: 'reload',
}; };
export const APP_ROUTING_SCROLL_CONF: InMemoryScrollingOptions = {
scrollPositionRestoration: 'top',
anchorScrolling: 'enabled',
};

View File

@@ -12,7 +12,11 @@ import {
NgModule, NgModule,
} from '@angular/core'; } from '@angular/core';
import { import {
NoPreloading,
provideRouter, provideRouter,
withEnabledBlockingInitialNavigation,
withInMemoryScrolling,
withPreloading,
withRouterConfig, withRouterConfig,
} from '@angular/router'; } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@@ -52,6 +56,7 @@ import {
import { import {
APP_ROUTES, APP_ROUTES,
APP_ROUTING_CONF, APP_ROUTING_CONF,
APP_ROUTING_SCROLL_CONF,
} from './app-routes'; } from './app-routes';
import { BROWSE_BY_DECORATOR_MAP } from './browse-by/browse-by-switcher/browse-by-decorator'; import { BROWSE_BY_DECORATOR_MAP } from './browse-by/browse-by-switcher/browse-by-decorator';
import { AuthInterceptor } from './core/auth/auth.interceptor'; import { AuthInterceptor } from './core/auth/auth.interceptor';
@@ -105,7 +110,13 @@ const IMPORTS = [
]; ];
const PROVIDERS = [ const PROVIDERS = [
provideRouter(APP_ROUTES, withRouterConfig(APP_ROUTING_CONF)), provideRouter(
APP_ROUTES,
withRouterConfig(APP_ROUTING_CONF),
withInMemoryScrolling(APP_ROUTING_SCROLL_CONF),
withEnabledBlockingInitialNavigation(),
withPreloading(NoPreloading),
),
{ {
provide: APP_BASE_HREF, provide: APP_BASE_HREF,
useFactory: getBaseHref, useFactory: getBaseHref,

View File

@@ -24,6 +24,7 @@ import { AuthenticateAction } from '../../core/auth/auth.actions';
import { CoreState } from '../../core/core-state.model'; import { CoreState } from '../../core/core-state.model';
import { EPersonDataService } from '../../core/eperson/eperson-data.service'; import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { Registration } from '../../core/shared/registration.model'; import { Registration } from '../../core/shared/registration.model';
import { ProfilePageSecurityFormComponent } from '../../profile-page/profile-page-security-form/profile-page-security-form.component';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { import {
createFailedRemoteDataObject$, createFailedRemoteDataObject$,
@@ -84,6 +85,8 @@ describe('ForgotPasswordFormComponent', () => {
{ provide: NotificationsService, useValue: notificationsService }, { provide: NotificationsService, useValue: notificationsService },
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).overrideComponent(ForgotPasswordFormComponent, {
remove: { imports: [ ProfilePageSecurityFormComponent ] },
}).compileComponents(); }).compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {

View File

@@ -166,7 +166,7 @@ describe('EditRelationshipComponent', () => {
comp.url = url; comp.url = url;
comp.fieldUpdate = fieldUpdate1; comp.fieldUpdate = fieldUpdate1;
comp.editItem = item; comp.editItem = item;
comp.relatedItem$ = observableOf(relatedItem); comp.relatedItem$.next(relatedItem);
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -13,9 +13,9 @@ import {
} from '@ng-bootstrap/ng-bootstrap'; } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { import {
BehaviorSubject,
combineLatest as observableCombineLatest, combineLatest as observableCombineLatest,
Observable, Observable,
of,
} from 'rxjs'; } from 'rxjs';
import { import {
filter, filter,
@@ -45,7 +45,6 @@ import { ListableObjectComponentLoaderComponent } from '../../../../shared/objec
import { VirtualMetadataComponent } from '../../virtual-metadata/virtual-metadata.component'; import { VirtualMetadataComponent } from '../../virtual-metadata/virtual-metadata.component';
@Component({ @Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'ds-edit-relationship', selector: 'ds-edit-relationship',
styleUrls: ['./edit-relationship.component.scss'], styleUrls: ['./edit-relationship.component.scss'],
templateUrl: './edit-relationship.component.html', templateUrl: './edit-relationship.component.html',
@@ -95,7 +94,7 @@ export class EditRelationshipComponent implements OnChanges {
/** /**
* The related item of this relationship * The related item of this relationship
*/ */
relatedItem$: Observable<Item>; relatedItem$: BehaviorSubject<Item> = new BehaviorSubject<Item>(null);
/** /**
* The view-mode we're currently on * The view-mode we're currently on
@@ -128,16 +127,19 @@ export class EditRelationshipComponent implements OnChanges {
getRemoteDataPayload(), getRemoteDataPayload(),
filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid)), filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid)),
); );
this.relatedItem$ = observableCombineLatest( observableCombineLatest([
this.leftItem$, this.leftItem$,
this.rightItem$, this.rightItem$,
).pipe( ]).pipe(
map((items: Item[]) => map((items: Item[]) =>
items.find((item) => item.uuid !== this.editItem.uuid), items.find((item) => item.uuid !== this.editItem.uuid),
), ),
); take(1),
).subscribe((relatedItem) => {
this.relatedItem$.next(relatedItem);
});
} else { } else {
this.relatedItem$ = of(this.update.relatedItem); this.relatedItem$.next(this.update.relatedItem);
} }
} }
@@ -146,10 +148,10 @@ export class EditRelationshipComponent implements OnChanges {
*/ */
remove(): void { remove(): void {
this.closeVirtualMetadataModal(); this.closeVirtualMetadataModal();
observableCombineLatest( observableCombineLatest([
this.leftItem$, this.leftItem$,
this.rightItem$, this.rightItem$,
).pipe( ]).pipe(
map((items: Item[]) => map((items: Item[]) =>
items.map((item) => this.objectUpdatesService items.map((item) => this.objectUpdatesService
.isSelectedVirtualMetadata(this.url, this.relationship.id, item.uuid)), .isSelectedVirtualMetadata(this.url, this.relationship.id, item.uuid)),

View File

@@ -1,5 +1,6 @@
import { import {
AsyncPipe, AsyncPipe,
NgFor,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
@@ -21,6 +22,7 @@ import {
standalone: true, standalone: true,
imports: [ imports: [
NgIf, NgIf,
NgFor,
AsyncPipe, AsyncPipe,
], ],
styleUrls: ['./ePerson-data.component.scss'], styleUrls: ['./ePerson-data.component.scss'],

View File

@@ -1,4 +1,7 @@
import { NgIf } from '@angular/common'; import {
NgFor,
NgIf,
} from '@angular/common';
import { import {
Component, Component,
Input, Input,
@@ -20,6 +23,7 @@ import { ObjectKeysPipe } from '../../../shared/utils/object-keys-pipe';
imports: [ imports: [
TranslateModule, TranslateModule,
NgIf, NgIf,
NgFor,
ObjectKeysPipe, ObjectKeysPipe,
], ],
standalone: true, standalone: true,

View File

@@ -1,3 +1,4 @@
import { NgIf } from '@angular/common';
import { import {
Component, Component,
EventEmitter, EventEmitter,
@@ -26,6 +27,7 @@ import { SuggestionEvidencesComponent } from './suggestion-evidences/suggestion-
templateUrl: './suggestion-list-element.component.html', templateUrl: './suggestion-list-element.component.html',
animations: [fadeIn], animations: [fadeIn],
imports: [ imports: [
NgIf,
TranslateModule, TranslateModule,
ItemSearchResultListElementComponent, ItemSearchResultListElementComponent,
SuggestionActionsComponent, SuggestionActionsComponent,

View File

@@ -1,5 +1,6 @@
import { import {
AsyncPipe, AsyncPipe,
NgFor,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
@@ -44,6 +45,7 @@ import { SuggestionTargetsStateService } from '../suggestion-targets.state.servi
TranslateModule, TranslateModule,
PaginationComponent, PaginationComponent,
NgIf, NgIf,
NgFor,
RouterLink, RouterLink,
], ],
standalone: true, standalone: true,

View File

@@ -13,7 +13,9 @@ import { of as observableOf } from 'rxjs';
import { RestResponse } from '../../core/cache/response.models'; import { RestResponse } from '../../core/cache/response.models';
import { EPersonDataService } from '../../core/eperson/eperson-data.service'; import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { AlertComponent } from '../../shared/alert/alert.component';
import { FormBuilderService } from '../../shared/form/builder/form-builder.service'; import { FormBuilderService } from '../../shared/form/builder/form-builder.service';
import { FormComponent } from '../../shared/form/form.component';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { VarDirective } from '../../shared/utils/var.directive'; import { VarDirective } from '../../shared/utils/var.directive';
import { ProfilePageSecurityFormComponent } from './profile-page-security-form.component'; import { ProfilePageSecurityFormComponent } from './profile-page-security-form.component';
@@ -52,6 +54,8 @@ describe('ProfilePageSecurityFormComponent', () => {
FormBuilderService, FormBuilderService,
], ],
schemas: [NO_ERRORS_SCHEMA], schemas: [NO_ERRORS_SCHEMA],
}).overrideComponent(ProfilePageSecurityFormComponent, {
remove: { imports: [ FormComponent, AlertComponent ] },
}).compileComponents(); }).compileComponents();
})); }));

View File

@@ -1,3 +1,4 @@
import { NgIf } from '@angular/common';
import { import {
Component, Component,
EventEmitter, EventEmitter,
@@ -32,6 +33,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
selector: 'ds-profile-page-security-form', selector: 'ds-profile-page-security-form',
templateUrl: './profile-page-security-form.component.html', templateUrl: './profile-page-security-form.component.html',
imports: [ imports: [
NgIf,
FormComponent, FormComponent,
AlertComponent, AlertComponent,
TranslateModule, TranslateModule,

View File

@@ -12,7 +12,6 @@ import {
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { import {
EventType, EventType,
NavigationEnd,
Router, Router,
RouterLink, RouterLink,
RouterLinkActive, RouterLinkActive,
@@ -26,7 +25,10 @@ import {
Subscription, Subscription,
} from 'rxjs'; } from 'rxjs';
import { import {
distinctUntilChanged,
filter,
map, map,
startWith,
take, take,
} from 'rxjs/operators'; } from 'rxjs/operators';
@@ -37,6 +39,7 @@ import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { BrowseDefinition } from '../../../core/shared/browse-definition.model'; import { BrowseDefinition } from '../../../core/shared/browse-definition.model';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { isNotEmpty } from '../../empty.util';
export interface ComColPageNavOption { export interface ComColPageNavOption {
id: string; id: string;
@@ -123,15 +126,18 @@ export class ComcolPageBrowseByComponent implements OnDestroy, OnInit {
this.subs.push(combineLatest([ this.subs.push(combineLatest([
this.allOptions$, this.allOptions$,
this.router.events, this.router.events.pipe(
]).subscribe(([navOptions, scrollEvent]: [ComColPageNavOption[], Scroll]) => { startWith(this.router),
if (scrollEvent.type === EventType.Scroll) { filter((next: Router|Scroll) => (isNotEmpty((next as Router)?.url) || (next as Scroll)?.type === EventType.Scroll)),
map((next: Router|Scroll) => (next as Router)?.url || (next as Scroll).routerEvent.urlAfterRedirects),
distinctUntilChanged(),
),
]).subscribe(([navOptions, url]: [ComColPageNavOption[], string]) => {
for (const option of navOptions) { for (const option of navOptions) {
if (option.routerLink === (scrollEvent.routerEvent as NavigationEnd).urlAfterRedirects.split('?')[0]) { if (option.routerLink === url?.split('?')[0]) {
this.currentOption$.next(option); this.currentOption$.next(option);
} }
} }
}
})); }));
} }

View File

@@ -1,4 +1,7 @@
import { AsyncPipe } from '@angular/common'; import {
AsyncPipe,
NgIf,
} from '@angular/common';
import { import {
Component, Component,
EventEmitter, EventEmitter,
@@ -18,6 +21,7 @@ import { LoadingComponent } from '../loading/loading.component';
templateUrl: './item-withdrawn-reinstate-modal.component.html', templateUrl: './item-withdrawn-reinstate-modal.component.html',
styleUrls: ['./item-withdrawn-reinstate-modal.component.scss'], styleUrls: ['./item-withdrawn-reinstate-modal.component.scss'],
imports: [ imports: [
NgIf,
TranslateModule, TranslateModule,
LoadingComponent, LoadingComponent,
FormsModule, FormsModule,

View File

@@ -3,15 +3,15 @@ import { Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { Item } from 'src/app/core/shared/item.model';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { ItemDataService } from '../../../core/data/item-data.service'; import { ItemDataService } from '../../../core/data/item-data.service';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { QualityAssuranceEventDataService } from '../../../core/notifications/qa/events/quality-assurance-event-data.service'; import { QualityAssuranceEventDataService } from '../../../core/notifications/qa/events/quality-assurance-event-data.service';
import { QualityAssuranceEventObject } from '../../../core/notifications/qa/models/quality-assurance-event.model'; import { QualityAssuranceEventObject } from '../../../core/notifications/qa/models/quality-assurance-event.model';
import { Item } from '../../../core/shared/item.model';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { ItemWithdrawnReinstateModalComponent } from '../../correction-suggestion/withdrawn-reinstate-modal.component'; import { ItemWithdrawnReinstateModalComponent } from '../../correction-suggestion/item-withdrawn-reinstate-modal.component';
import { NotificationsService } from '../../notifications/notifications.service'; import { NotificationsService } from '../../notifications/notifications.service';
export const REQUEST_WITHDRAWN = 'REQUEST/WITHDRAWN'; export const REQUEST_WITHDRAWN = 'REQUEST/WITHDRAWN';

View File

@@ -4,6 +4,7 @@ import {
Inject, Inject,
OnInit, OnInit,
} from '@angular/core'; } from '@angular/core';
import { RouterLinkActive } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { isNotEmpty } from '../../empty.util'; import { isNotEmpty } from '../../empty.util';
@@ -17,7 +18,7 @@ import { ExternalLinkMenuItemModel } from './models/external-link.model';
styleUrls: ['./menu-item.component.scss'], styleUrls: ['./menu-item.component.scss'],
templateUrl: './external-link-menu-item.component.html', templateUrl: './external-link-menu-item.component.html',
standalone: true, standalone: true,
imports: [NgClass, TranslateModule], imports: [NgClass, TranslateModule, RouterLinkActive],
}) })
export class ExternalLinkMenuItemComponent implements OnInit { export class ExternalLinkMenuItemComponent implements OnInit {
item: ExternalLinkMenuItemModel; item: ExternalLinkMenuItemModel;

View File

@@ -3,6 +3,7 @@ import {
Component, Component,
Inject, Inject,
} from '@angular/core'; } from '@angular/core';
import { RouterLinkActive } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { OnClickMenuItemModel } from './models/onclick.model'; import { OnClickMenuItemModel } from './models/onclick.model';
@@ -15,7 +16,7 @@ import { OnClickMenuItemModel } from './models/onclick.model';
styleUrls: ['./menu-item.component.scss', './onclick-menu-item.component.scss'], styleUrls: ['./menu-item.component.scss', './onclick-menu-item.component.scss'],
templateUrl: './onclick-menu-item.component.html', templateUrl: './onclick-menu-item.component.html',
standalone: true, standalone: true,
imports: [NgIf, TranslateModule], imports: [NgIf, TranslateModule, RouterLinkActive],
}) })
export class OnClickMenuItemComponent { export class OnClickMenuItemComponent {
item: OnClickMenuItemModel; item: OnClickMenuItemModel;

View File

@@ -10,6 +10,7 @@ import { Item } from '../../../../core/shared/item.model';
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
import { AbstractComponentLoaderComponent } from '../../../abstract-component-loader/abstract-component-loader.component'; import { AbstractComponentLoaderComponent } from '../../../abstract-component-loader/abstract-component-loader.component';
import { DynamicComponentLoaderDirective } from '../../../abstract-component-loader/dynamic-component-loader.directive';
import { MyDSpaceActionsResult } from '../../mydspace-actions'; import { MyDSpaceActionsResult } from '../../mydspace-actions';
import { ClaimedTaskActionsAbstractComponent } from '../abstract/claimed-task-actions-abstract.component'; import { ClaimedTaskActionsAbstractComponent } from '../abstract/claimed-task-actions-abstract.component';
import { getComponentByWorkflowTaskOption } from './claimed-task-actions-decorator'; import { getComponentByWorkflowTaskOption } from './claimed-task-actions-decorator';
@@ -18,6 +19,7 @@ import { getComponentByWorkflowTaskOption } from './claimed-task-actions-decorat
selector: 'ds-claimed-task-actions-loader', selector: 'ds-claimed-task-actions-loader',
templateUrl: '../../../abstract-component-loader/abstract-component-loader.component.html', templateUrl: '../../../abstract-component-loader/abstract-component-loader.component.html',
standalone: true, standalone: true,
imports: [ DynamicComponentLoaderDirective ],
}) })
/** /**
* Component for loading a ClaimedTaskAction component depending on the "option" input * Component for loading a ClaimedTaskAction component depending on the "option" input

View File

@@ -1,10 +1,8 @@
import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.model'; import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.model';
import { SearchResult } from '../../search/models/search-result.model'; import { SearchResult } from '../../search/models/search-result.model';
import { searchResultFor } from '../../search/search-result-element-decorator';
/** /**
* Represents a search result object of a ClaimedTask object * Represents a search result object of a ClaimedTask object
*/ */
@searchResultFor(ClaimedTask)
export class ClaimedTaskSearchResult extends SearchResult<ClaimedTask> { export class ClaimedTaskSearchResult extends SearchResult<ClaimedTask> {
} }

View File

@@ -1,7 +1,5 @@
import { Collection } from '../../../core/shared/collection.model'; import { Collection } from '../../../core/shared/collection.model';
import { SearchResult } from '../../search/models/search-result.model'; import { SearchResult } from '../../search/models/search-result.model';
import { searchResultFor } from '../../search/search-result-element-decorator';
@searchResultFor(Collection)
export class CollectionSearchResult extends SearchResult<Collection> { export class CollectionSearchResult extends SearchResult<Collection> {
} }

View File

@@ -1,7 +1,5 @@
import { Community } from '../../../core/shared/community.model'; import { Community } from '../../../core/shared/community.model';
import { SearchResult } from '../../search/models/search-result.model'; import { SearchResult } from '../../search/models/search-result.model';
import { searchResultFor } from '../../search/search-result-element-decorator';
@searchResultFor(Community)
export class CommunitySearchResult extends SearchResult<Community> { export class CommunitySearchResult extends SearchResult<Community> {
} }

View File

@@ -2,10 +2,8 @@ import { GenericConstructor } from '../../../core/shared/generic-constructor';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { inheritEquatable } from '../../../core/utilities/equals.decorators'; import { inheritEquatable } from '../../../core/utilities/equals.decorators';
import { SearchResult } from '../../search/models/search-result.model'; import { SearchResult } from '../../search/models/search-result.model';
import { searchResultFor } from '../../search/search-result-element-decorator';
import { ListableObject } from './listable-object.model'; import { ListableObject } from './listable-object.model';
@searchResultFor(Item)
@inheritEquatable(SearchResult) @inheritEquatable(SearchResult)
export class ItemSearchResult extends SearchResult<Item> { export class ItemSearchResult extends SearchResult<Item> {

View File

@@ -15,6 +15,7 @@ import { ListableObject } from '../listable-object.model';
@Component({ @Component({
selector: 'ds-objects-collection-tabulatable', selector: 'ds-objects-collection-tabulatable',
template: ``, template: ``,
standalone: true,
}) })
/** /**

View File

@@ -1,10 +1,8 @@
import { PoolTask } from '../../../core/tasks/models/pool-task-object.model'; import { PoolTask } from '../../../core/tasks/models/pool-task-object.model';
import { SearchResult } from '../../search/models/search-result.model'; import { SearchResult } from '../../search/models/search-result.model';
import { searchResultFor } from '../../search/search-result-element-decorator';
/** /**
* Represents a search result object of a PoolTask object * Represents a search result object of a PoolTask object
*/ */
@searchResultFor(PoolTask)
export class PoolTaskSearchResult extends SearchResult<PoolTask> { export class PoolTaskSearchResult extends SearchResult<PoolTask> {
} }

View File

@@ -1,10 +1,8 @@
import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { WorkflowItem } from '../../../core/submission/models/workflowitem.model';
import { SearchResult } from '../../search/models/search-result.model'; import { SearchResult } from '../../search/models/search-result.model';
import { searchResultFor } from '../../search/search-result-element-decorator';
/** /**
* Represents a search result object of a WorkflowItem object * Represents a search result object of a WorkflowItem object
*/ */
@searchResultFor(WorkflowItem)
export class WorkflowItemSearchResult extends SearchResult<WorkflowItem> { export class WorkflowItemSearchResult extends SearchResult<WorkflowItem> {
} }

View File

@@ -1,10 +1,8 @@
import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model'; import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
import { SearchResult } from '../../search/models/search-result.model'; import { SearchResult } from '../../search/models/search-result.model';
import { searchResultFor } from '../../search/search-result-element-decorator';
/** /**
* Represents a search result object of a WorkspaceItem object * Represents a search result object of a WorkspaceItem object
*/ */
@searchResultFor(WorkspaceItem)
export class WorkspaceItemSearchResult extends SearchResult<WorkspaceItem> { export class WorkspaceItemSearchResult extends SearchResult<WorkspaceItem> {
} }

View File

@@ -1,24 +1,36 @@
import { AdminNotifyMessage } from '../../admin/admin-notify-dashboard/models/admin-notify-message.model';
import { AdminNotifySearchResult } from '../../admin/admin-notify-dashboard/models/admin-notify-message-search-result.model';
import { Collection } from '../../core/shared/collection.model';
import { Community } from '../../core/shared/community.model';
import { GenericConstructor } from '../../core/shared/generic-constructor'; import { GenericConstructor } from '../../core/shared/generic-constructor';
import { Item } from '../../core/shared/item.model';
import { WorkflowItem } from '../../core/submission/models/workflowitem.model';
import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model';
import { ClaimedTask } from '../../core/tasks/models/claimed-task-object.model';
import { PoolTask } from '../../core/tasks/models/pool-task-object.model';
import { ClaimedTaskSearchResult } from '../object-collection/shared/claimed-task-search-result.model';
import { CollectionSearchResult } from '../object-collection/shared/collection-search-result.model';
import { CommunitySearchResult } from '../object-collection/shared/community-search-result.model';
import { ItemSearchResult } from '../object-collection/shared/item-search-result.model';
import { ListableObject } from '../object-collection/shared/listable-object.model'; import { ListableObject } from '../object-collection/shared/listable-object.model';
import { PoolTaskSearchResult } from '../object-collection/shared/pool-task-search-result.model';
import { WorkflowItemSearchResult } from '../object-collection/shared/workflow-item-search-result.model';
import { WorkspaceItemSearchResult } from '../object-collection/shared/workspace-item-search-result.model';
/** /**
* Contains the mapping between a search result component and a DSpaceObject * Contains the mapping between a search result component and a DSpaceObject
*/ */
const searchResultMap = new Map(); export const SEARCH_RESULT_MAP = new Map<string| GenericConstructor<ListableObject>, GenericConstructor<ListableObject>>([
[AdminNotifyMessage, AdminNotifySearchResult],
[ClaimedTask, ClaimedTaskSearchResult],
[PoolTask, PoolTaskSearchResult],
[Collection, CollectionSearchResult],
[Community, CommunitySearchResult],
[Item, ItemSearchResult],
[WorkflowItem, WorkflowItemSearchResult],
[WorkspaceItem, WorkspaceItemSearchResult],
]);
/**
* Used to map Search Result components to their matching DSpaceObject
* @param {GenericConstructor<ListableObject>} domainConstructor The constructor of the DSpaceObject
* @returns Decorator function that performs the actual mapping on initialization of the component
*/
export function searchResultFor(domainConstructor: GenericConstructor<ListableObject>) {
return function decorator(searchResult: any) {
if (!searchResult) {
return;
}
searchResultMap.set(domainConstructor, searchResult);
};
}
/** /**
* Requests the matching component based on a given DSpaceObject's constructor * Requests the matching component based on a given DSpaceObject's constructor
@@ -26,5 +38,5 @@ export function searchResultFor(domainConstructor: GenericConstructor<ListableOb
* @returns The component's constructor that matches the given DSpaceObject * @returns The component's constructor that matches the given DSpaceObject
*/ */
export function getSearchResultFor(domainConstructor: GenericConstructor<ListableObject>) { export function getSearchResultFor(domainConstructor: GenericConstructor<ListableObject>) {
return searchResultMap.get(domainConstructor); return SEARCH_RESULT_MAP.get(domainConstructor);
} }

View File

@@ -14,10 +14,10 @@
</div> </div>
<div class="well ds-base-drop-zone mt-1 mb-3 text-muted p-2"> <div class="well ds-base-drop-zone mt-1 mb-3 text-muted p-2">
<p class="text-center m-0 p-0 d-flex justify-content-center align-items-center" <p class="text-center m-0 p-0 d-flex justify-content-center align-items-center"
*ngIf="fileObject!==null"> {{ fileObject.name }} </p> *ngIf="fileObject"> {{ fileObject?.name }} </p>
<p class="text-center m-0 p-0 d-flex justify-content-center align-items-center"> <p class="text-center m-0 p-0 d-flex justify-content-center align-items-center">
<span><i class="fas fa-cloud-upload" <span><i class="fas fa-cloud-upload"
aria-hidden="true"></i> {{ (fileObject === null ? dropMessageLabel : dropMessageLabelReplacement) | translate}} {{'uploader.or' | translate}}</span> aria-hidden="true"></i> {{ ((fileObject === null || fileObject === undefined) ? dropMessageLabel : dropMessageLabelReplacement) | translate}} {{'uploader.or' | translate}}</span>
<label class="btn btn-link m-0 p-0 ml-1"> <label class="btn btn-link m-0 p-0 ml-1">
<input class="form-control-file d-none" requireFile #file="ngModel" type="file" name="file-upload" <input class="form-control-file d-none" requireFile #file="ngModel" type="file" name="file-upload"
id="file-upload" id="file-upload"

View File

@@ -11,6 +11,7 @@ import {
providers: [ providers: [
{ provide: NG_VALIDATORS, useExisting: IpV4Validator, multi: true }, { provide: NG_VALIDATORS, useExisting: IpV4Validator, multi: true },
], ],
standalone: true,
}) })
/** /**
* Validator to validate if an Ip is in the right format * Validator to validate if an Ip is in the right format

View File

@@ -1,3 +1,4 @@
import { NgFor } from '@angular/common';
import { import {
Component, Component,
Input, Input,
@@ -29,6 +30,7 @@ import { SubmissionImportExternalCollectionComponent } from '../import-external-
styleUrls: ['./submission-import-external-preview.component.scss'], styleUrls: ['./submission-import-external-preview.component.scss'],
templateUrl: './submission-import-external-preview.component.html', templateUrl: './submission-import-external-preview.component.html',
imports: [ imports: [
NgFor,
TranslateModule, TranslateModule,
], ],
standalone: true, standalone: true,

View File

@@ -46,7 +46,13 @@
"angularCompilerOptions": { "angularCompilerOptions": {
"fullTemplateTypeCheck": true, "fullTemplateTypeCheck": true,
"strictInjectionParameters": true, "strictInjectionParameters": true,
"strictInputAccessModifiers": true "strictInputAccessModifiers": true,
"extendedDiagnostics": {
// The categories to use for specific diagnostics.
"checks": {
"missingControlFlowDirective": "error"
},
}
}, },
"exclude": [ "exclude": [
"cypress.config.ts" "cypress.config.ts"