Merge remote-tracking branch 'upstream/dspace-8_x' into w2p-117544_support-for-disabled-elements-for-screen-readers-8.0

This commit is contained in:
Jens Vannerum
2024-08-27 11:23:37 +02:00
72 changed files with 324 additions and 156 deletions

View File

@@ -165,6 +165,7 @@
"@angular-eslint/no-output-native": "warn",
"@angular-eslint/no-output-on-prefix": "warn",
"@angular-eslint/no-conflicting-lifecycle": "warn",
"@angular-eslint/use-lifecycle-interface": "error",
"@typescript-eslint/no-inferrable-types":[
"error",

View File

@@ -4,7 +4,7 @@
# Test build:
# docker build -f Dockerfile.dist -t dspace/dspace-angular:latest-dist .
FROM node:18-alpine as build
FROM node:18-alpine AS build
# Ensure Python and other build tools are available
# These are needed to install some node modules, especially on linux/arm64

View File

@@ -59,19 +59,19 @@ A default/demo version of this image is built *automatically*.
## To refresh / pull DSpace images from Dockerhub
```
docker-compose -f docker/docker-compose.yml pull
docker compose -f docker/docker-compose.yml pull
```
## To build DSpace images using code in your branch
```
docker-compose -f docker/docker-compose.yml build
docker compose -f docker/docker-compose.yml build
```
## To start DSpace (REST and Angular) from your branch
This command provides a quick way to start both the frontend & backend from this single codebase
```
docker-compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d
docker compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d
```
Keep in mind, you may also start the backend by cloning the 'DSpace/DSpace' GitHub repository separately. See the next section.
@@ -86,14 +86,14 @@ _The system will be started in 2 steps. Each step shares the same docker network
From 'DSpace/DSpace' clone (build first as needed):
```
docker-compose -p d8 up -d
docker compose -p d8 up -d
```
NOTE: More detailed instructions on starting the backend via Docker can be found in the [Docker Compose instructions for the Backend](https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/README.md).
From 'DSpace/dspace-angular' clone (build first as needed)
```
docker-compose -p d8 -f docker/docker-compose.yml up -d
docker compose -p d8 -f docker/docker-compose.yml up -d
```
At this point, you should be able to access the UI from http://localhost:4000,
@@ -105,21 +105,21 @@ This allows you to run the Angular UI in *production* mode, pointing it at the d
(https://demo.dspace.org/server/ or https://sandbox.dspace.org/server/).
```
docker-compose -f docker/docker-compose-dist.yml pull
docker-compose -f docker/docker-compose-dist.yml build
docker-compose -p d8 -f docker/docker-compose-dist.yml up -d
docker compose -f docker/docker-compose-dist.yml pull
docker compose -f docker/docker-compose-dist.yml build
docker compose -p d8 -f docker/docker-compose-dist.yml up -d
```
## Ingest test data from AIPDIR
Create an administrator
```
docker-compose -p d8 -f docker/cli.yml run --rm dspace-cli create-administrator -e test@test.edu -f admin -l user -p admin -c en
docker compose -p d8 -f docker/cli.yml run --rm dspace-cli create-administrator -e test@test.edu -f admin -l user -p admin -c en
```
Load content from AIP files
```
docker-compose -p d8 -f docker/cli.yml -f ./docker/cli.ingest.yml run --rm dspace-cli
docker compose -p d8 -f docker/cli.yml -f ./docker/cli.ingest.yml run --rm dspace-cli
```
## Alternative Ingest - Use Entities dataset
@@ -127,12 +127,12 @@ _Delete your docker volumes or use a unique project (-p) name_
Start DSpace with Database Content from a database dump
```
docker-compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml -f docker/db.entities.yml up -d
docker compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml -f docker/db.entities.yml up -d
```
Load assetstore content and trigger a re-index of the repository
```
docker-compose -p d8 -f docker/cli.yml -f docker/cli.assetstore.yml run --rm dspace-cli
docker compose -p d8 -f docker/cli.yml -f docker/cli.assetstore.yml run --rm dspace-cli
```
## End to end testing of the REST API (runs in GitHub Actions CI).
@@ -140,5 +140,5 @@ _In this instance, only the REST api runs in Docker using the Entities dataset.
This command is only really useful for testing our Continuous Integration process.
```
docker-compose -p d8ci -f docker/docker-compose-ci.yml up -d
docker compose -p d8ci -f docker/docker-compose-ci.yml up -d
```

View File

@@ -14,7 +14,7 @@
# # Therefore, it should be kept in sync with that file
services:
dspacedb:
image: dspace/dspace-postgres-pgcrypto::${DSPACE_VER:-latest}-loadsql
image: "${DOCKER_OWNER:-dspace}/dspace-postgres-pgcrypto:${DSPACE_VER:-latest}-loadsql"
environment:
# This LOADSQL should be kept in sync with the URL in DSpace/DSpace
# This SQL is available from https://github.com/DSpace-Labs/AIP-Files/releases/tag/demo-entities-data
@@ -34,4 +34,4 @@ services:
- |
while (!</dev/tcp/dspacedb/5432) > /dev/null 2>&1; do sleep 1; done;
/dspace/bin/dspace database migrate ignored
java -jar /dspace/webapps/server-boot.jar --dspace.dir=/dspace
java -jar /dspace/webapps/server-boot.jar --dspace.dir=/dspace

View File

@@ -101,7 +101,7 @@ services:
# * First, run precreate-core to create the core (if it doesn't yet exist). If exists already, this is a no-op
# * Second, copy configsets to this core:
# Updates to Solr configs require the container to be rebuilt/restarted:
# `docker-compose -p d7 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d --build dspacesolr`
# `docker compose -p d7 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d --build dspacesolr`
entrypoint:
- /bin/bash
- '-c'

View File

@@ -1,6 +1,6 @@
{
"name": "dspace-angular",
"version": "8.0.0",
"version": "8.1.0-next",
"scripts": {
"ng": "ng",
"config:watch": "nodemon",

View File

@@ -4,7 +4,10 @@ import {
NgForOf,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnDestroy,
} from '@angular/core';
import {
Router,
RouterLink,
@@ -60,7 +63,7 @@ import { MetadataSchemaFormComponent } from './metadata-schema-form/metadata-sch
* A component used for managing all existing metadata schemas within the repository.
* The admin can create, edit or delete metadata schemas here.
*/
export class MetadataRegistryComponent {
export class MetadataRegistryComponent implements OnDestroy {
/**
* A list of all the current metadata schemas within the repository

View File

@@ -4,6 +4,7 @@ import {
} from '@angular/common';
import {
Component,
OnInit,
ViewChild,
} from '@angular/core';
import {
@@ -40,7 +41,7 @@ import { FilteredCollections } from './filtered-collections.model';
],
standalone: true,
})
export class FilteredCollectionsComponent {
export class FilteredCollectionsComponent implements OnInit {
queryForm: FormGroup;
results: FilteredCollections = new FilteredCollections();

View File

@@ -5,6 +5,7 @@ import {
} from '@angular/common';
import {
Component,
OnInit,
ViewChild,
} from '@angular/core';
import {
@@ -68,7 +69,7 @@ import { QueryPredicate } from './query-predicate.model';
],
standalone: true,
})
export class FilteredItemsComponent {
export class FilteredItemsComponent implements OnInit {
collections: OptionVO[];
presetQueries: PresetQuery[];
@@ -92,7 +93,7 @@ export class FilteredItemsComponent {
private formBuilder: FormBuilder,
private restService: DspaceRestService) {}
ngOnInit() {
ngOnInit(): void {
this.loadCollections();
this.loadPresetQueries();
this.loadMetadataFields();

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { getCollectionEditRoute } from '../../../../../collection-page/collection-page-routing-paths';
@@ -21,10 +24,10 @@ import { SearchResultGridElementComponent } from '../../../../../shared/object-g
/**
* The component for displaying a list element for a collection search result on the admin search page
*/
export class CollectionAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CollectionSearchResult, Collection> {
export class CollectionAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CollectionSearchResult, Collection> implements OnInit {
editPath: string;
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.editPath = getCollectionEditRoute(this.dso.uuid);
}

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { getCommunityEditRoute } from '../../../../../community-page/community-page-routing-paths';
@@ -21,10 +24,10 @@ import { SearchResultGridElementComponent } from '../../../../../shared/object-g
/**
* The component for displaying a list element for a community search result on the admin search page
*/
export class CommunityAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CommunitySearchResult, Community> {
export class CommunityAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CommunitySearchResult, Community> implements OnInit {
editPath: string;
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.editPath = getCommunityEditRoute(this.dso.uuid);
}

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@@ -22,10 +25,10 @@ import { SearchResultListElementComponent } from '../../../../../shared/object-l
/**
* The component for displaying a list element for a collection search result on the admin search page
*/
export class CollectionAdminSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> {
export class CollectionAdminSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> implements OnInit {
editPath: string;
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.editPath = getCollectionEditRoute(this.dso.uuid);
}

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@@ -22,10 +25,10 @@ import { SearchResultListElementComponent } from '../../../../../shared/object-l
/**
* The component for displaying a list element for a community search result on the admin search page
*/
export class CommunityAdminSearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> {
export class CommunityAdminSearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> implements OnInit {
editPath: string;
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.editPath = getCommunityEditRoute(this.dso.uuid);
}

View File

@@ -1,5 +1,8 @@
import { AsyncPipe } from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs';
@@ -28,7 +31,7 @@ import { hasValue } from '../../../shared/empty.util';
],
standalone: true,
})
export class CollectionCurateComponent {
export class CollectionCurateComponent implements OnInit {
dsoRD$: Observable<RemoteData<Collection>>;
collectionName$: Observable<string>;

View File

@@ -97,7 +97,7 @@ export class CollectionSourceControlsComponent implements OnInit, OnDestroy {
) {
}
ngOnInit() {
ngOnInit(): void {
// ensure the contentSource gets updated after being set to stale
this.contentSource$ = this.collectionService.findByHref(this.collection._links.self.href, false).pipe(
getAllSucceededRemoteDataPayload(),

View File

@@ -27,6 +27,14 @@ export class ForwardClientIpInterceptor implements HttpInterceptor {
*/
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const clientIp = this.req.get('x-forwarded-for') || this.req.connection.remoteAddress;
return next.handle(httpRequest.clone({ setHeaders: { 'X-Forwarded-For': clientIp } }));
const headers = { 'X-Forwarded-For': clientIp };
// if the request has a user-agent retain it
const userAgent = this.req.get('user-agent');
if (userAgent) {
headers['User-Agent'] = userAgent;
}
return next.handle(httpRequest.clone({ setHeaders: headers }));
}
}

View File

@@ -31,7 +31,7 @@ export class ClientMathService extends MathService {
protected mathJaxOptions = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
inlineMath: [['$', '$'], ['$$', '$$'], ['\\(', '\\)']],
},
svg: {
fontCache: 'global',
@@ -108,7 +108,7 @@ export class ClientMathService extends MathService {
*/
render(element: HTMLElement) {
if (environment.markdown.mathjax) {
this._window.nativeWindow.MathJax.typesetPromise([element]);
return (window as any).MathJax.typesetPromise([element]) as Promise<any>;
}
}
}

View File

@@ -22,8 +22,8 @@ export class MockMathService extends MathService {
return of(true);
}
render(element: HTMLElement): void {
return;
render(element: HTMLElement): Promise<any> {
return Promise.resolve();
}
}

View File

@@ -15,5 +15,5 @@ export abstract class MathService {
protected abstract registerMathJaxAsync(config: MathJaxConfig): Promise<any>;
abstract ready(): Observable<boolean>;
abstract render(element: HTMLElement): void;
abstract render(element: HTMLElement): Promise<any>;
}

View File

@@ -47,6 +47,6 @@ export class ServerMathService extends MathService {
}
render(element: HTMLElement) {
return;
return Promise.resolve();
}
}

View File

@@ -1,5 +1,8 @@
/* eslint-disable max-classes-per-file */
import { Injectable } from '@angular/core';
import {
Injectable,
OnDestroy,
} from '@angular/core';
import { Observable } from 'rxjs';
import { Duplicate } from '../../shared/object-list/duplicate-data/duplicate.model';
@@ -33,7 +36,8 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
*
*/
@Injectable({ providedIn: 'root' })
export class SubmissionDuplicateDataService extends BaseDataService<Duplicate> implements SearchData<Duplicate> {
export class SubmissionDuplicateDataService extends BaseDataService<Duplicate>
implements SearchData<Duplicate>, OnDestroy {
/**
* The ResponseParsingService constructor name

View File

@@ -1,21 +1,25 @@
<div class="item-metadata" *ngIf="form">
<div class="button-row top d-flex my-2 space-children-mr ml-gap">
<button class="mr-auto btn btn-success" id="dso-add-btn" [dsDisabled]="form.newValue || (saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.add-button' | translate"
[title]="dsoType + '.edit.metadata.add-button' | translate"
(click)="add()"><i class="fas fa-plus" aria-hidden="true"></i>
<span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.add-button' | translate }}</span>
</button>
<button class="btn btn-warning ml-1" id="dso-reinstate-btn" *ngIf="isReinstatable" [dsDisabled]="(saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.reinstate-button' | translate"
[title]="dsoType + '.edit.metadata.reinstate-button' | translate"
(click)="reinstate()"><i class="fas fa-undo-alt" aria-hidden="true"></i>
<span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.reinstate-button' | translate }}</span>
</button>
<button class="btn btn-primary ml-1" id="dso-save-btn" [dsDisabled]="!hasChanges || (saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.save-button' | translate"
[title]="dsoType + '.edit.metadata.save-button' | translate"
(click)="submit()"><i class="fas fa-save" aria-hidden="true"></i>
<span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.save-button' | translate }}</span>
</button>
<button class="btn btn-danger ml-1" id="dso-discard-btn" *ngIf="!isReinstatable"
[attr.aria-label]="dsoType + '.edit.metadata.discard-button' | translate"
[title]="dsoType + '.edit.metadata.discard-button' | translate"
[dsDisabled]="!hasChanges || (saving$ | async)"
(click)="discard()"><i class="fas fa-times" aria-hidden="true"></i>
@@ -74,16 +78,19 @@
<div class="button-row bottom d-inline-block w-100">
<div class="mt-2 float-right space-children-mr ml-gap">
<button class="btn btn-warning" *ngIf="isReinstatable" [dsDisabled]="(saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.reinstate-button' | translate"
[title]="dsoType + '.edit.metadata.reinstate-button' | translate"
(click)="reinstate()">
<i class="fas fa-undo-alt" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.reinstate-button' | translate }}
</button>
<button class="btn btn-primary" [dsDisabled]="!hasChanges || (saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.save-button' | translate"
[title]="dsoType + '.edit.metadata.save-button' | translate"
(click)="submit()">
<i class="fas fa-save" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.save-button' | translate }}
</button>
<button class="btn btn-danger" *ngIf="!isReinstatable"
[attr.aria-label]="dsoType + '.edit.metadata.discard-button' | translate"
[title]="dsoType + '.edit.metadata.discard-button' | translate"
[dsDisabled]="!hasChanges || (saving$ | async)"
(click)="discard()">

View File

@@ -7,6 +7,7 @@ import {
import {
Component,
Inject,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@@ -36,7 +37,7 @@ import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbn
/**
* The component for displaying a list element for an item search result of the type Person
*/
export class PersonSearchResultListElementComponent extends ItemSearchResultListElementComponent {
export class PersonSearchResultListElementComponent extends ItemSearchResultListElementComponent implements OnInit {
public constructor(
protected truncatableService: TruncatableService,

View File

@@ -2,7 +2,10 @@ import {
AsyncPipe,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import {
ActivatedRoute,
Router,
@@ -47,7 +50,7 @@ import { BrowserOnlyPipe } from '../../shared/utils/browser-only.pipe';
/**
* Component for a user to enter a new password for a forgot token.
*/
export class ForgotPasswordFormComponent {
export class ForgotPasswordFormComponent implements OnInit {
registration$: Observable<Registration>;

View File

@@ -10,6 +10,7 @@ import {
Component,
ElementRef,
Inject,
OnDestroy,
OnInit,
PLATFORM_ID,
} from '@angular/core';
@@ -62,7 +63,7 @@ import { VarDirective } from '../../shared/utils/var.directive';
standalone: true,
imports: [VarDirective, NgIf, NgClass, NgFor, ListableObjectComponentLoaderComponent, ErrorComponent, ThemedLoadingComponent, AsyncPipe, TranslateModule],
})
export class RecentItemListComponent implements OnInit {
export class RecentItemListComponent implements OnInit, OnDestroy {
itemRD$: Observable<RemoteData<PaginatedList<Item>>>;
paginationConfig: PaginationComponentOptions;
sortConfig: SortOptions;

View File

@@ -3,7 +3,10 @@ import {
NgForOf,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import {
ActivatedRoute,
Router,
@@ -47,7 +50,7 @@ import { AbstractSimpleItemActionComponent } from '../simple-item-action/abstrac
/**
* Component responsible for rendering the Item Register DOI page
*/
export class ItemRegisterDoiComponent extends AbstractSimpleItemActionComponent {
export class ItemRegisterDoiComponent extends AbstractSimpleItemActionComponent implements OnInit {
protected messageKey = 'register-doi';
doiToUpdateMessage = 'item.edit.' + this.messageKey + '.to-update';

View File

@@ -7,6 +7,7 @@ import {
import {
ChangeDetectionStrategy,
Component,
OnDestroy,
OnInit,
} from '@angular/core';
import {
@@ -79,7 +80,7 @@ import { ItemOperation } from '../item-operation/itemOperation.model';
/**
* Component for displaying an item's status
*/
export class ItemStatusComponent implements OnInit {
export class ItemStatusComponent implements OnInit, OnDestroy {
/**
* The item to display the status for

View File

@@ -2,7 +2,10 @@ import {
AsyncPipe,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -28,7 +31,7 @@ import { ItemVersionsComponent } from '../../versions/item-versions.component';
/**
* Component for listing and managing an item's version history
*/
export class ItemVersionHistoryComponent {
export class ItemVersionHistoryComponent implements OnInit {
/**
* The item to display the version history for
*/

View File

@@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import {
Component,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
@@ -56,7 +57,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
],
standalone: true,
})
export class OrcidQueueComponent implements OnInit, OnDestroy {
export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges {
/**
* The item for which showing the orcid settings

View File

@@ -10,6 +10,7 @@ import {
ElementRef,
Inject,
Input,
OnInit,
PLATFORM_ID,
} from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
@@ -43,7 +44,7 @@ import { AbstractIncrementalListComponent } from '../abstract-incremental-list/a
* This component is used for displaying relations between items
* It expects a parent item and relationship type, as well as a label to display on top
*/
export class RelatedItemsComponent extends AbstractIncrementalListComponent<Observable<RemoteData<PaginatedList<Item>>>> {
export class RelatedItemsComponent extends AbstractIncrementalListComponent<Observable<RemoteData<PaginatedList<Item>>>> implements OnInit {
/**
* The parent of the list of related items to display

View File

@@ -6,6 +6,7 @@ import {
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
@@ -111,7 +112,7 @@ export interface QualityAssuranceEventData {
* Component to display a modal window for linking a project to an Quality Assurance event
* Shows information about the selected project and a selectable list.
*/
export class ProjectEntryImportModalComponent implements OnInit {
export class ProjectEntryImportModalComponent implements OnInit, OnDestroy {
/**
* The external source entry
*/

View File

@@ -5,7 +5,9 @@ import {
NgIf,
} from '@angular/common';
import {
AfterViewInit,
Component,
OnDestroy,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
@@ -40,7 +42,7 @@ import { NotificationsStateService } from '../../notifications-state.service';
standalone: true,
imports: [AlertComponent, NgIf, ThemedLoadingComponent, PaginationComponent, NgFor, RouterLink, AsyncPipe, TranslateModule, DatePipe],
})
export class QualityAssuranceSourceComponent implements OnInit {
export class QualityAssuranceSourceComponent implements OnDestroy, OnInit, AfterViewInit {
/**
* The pagination system configuration for HTML listing.

View File

@@ -4,8 +4,10 @@ import {
NgIf,
} from '@angular/common';
import {
AfterViewInit,
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import {
@@ -50,7 +52,7 @@ import { SuggestionTargetsStateService } from '../suggestion-targets.state.servi
],
standalone: true,
})
export class PublicationClaimComponent implements OnInit {
export class PublicationClaimComponent implements AfterViewInit, OnDestroy, OnInit {
/**
* The source for which to list targets

View File

@@ -2,6 +2,7 @@ import { NgIf } from '@angular/common';
import {
Component,
Input,
OnInit,
Optional,
} from '@angular/core';
import {
@@ -27,7 +28,7 @@ import { ValueInputComponent } from '../value-input.component';
standalone: true,
imports: [FormsModule, NgIf, TranslateModule],
})
export class DateValueInputComponent extends ValueInputComponent<string> {
export class DateValueInputComponent extends ValueInputComponent<string> implements OnInit {
/**
* The current value of the date string
*/
@@ -38,7 +39,7 @@ export class DateValueInputComponent extends ValueInputComponent<string> {
*/
@Input() initialValue;
ngOnInit() {
ngOnInit(): void {
this.value = this.initialValue;
}

View File

@@ -2,6 +2,7 @@ import { NgIf } from '@angular/common';
import {
Component,
Input,
OnInit,
Optional,
} from '@angular/core';
import {
@@ -27,7 +28,7 @@ import { ValueInputComponent } from '../value-input.component';
standalone: true,
imports: [FormsModule, NgIf, TranslateModule],
})
export class StringValueInputComponent extends ValueInputComponent<string> {
export class StringValueInputComponent extends ValueInputComponent<string> implements OnInit {
/**
* The current value of the string
*/
@@ -38,7 +39,7 @@ export class StringValueInputComponent extends ValueInputComponent<string> {
*/
@Input() initialValue;
ngOnInit() {
ngOnInit(): void {
this.value = this.initialValue;
}

View File

@@ -7,6 +7,7 @@ import {
EventEmitter,
Input,
OnChanges,
OnInit,
Optional,
Output,
SimpleChanges,
@@ -39,7 +40,7 @@ import { ParameterSelectComponent } from './parameter-select/parameter-select.co
standalone: true,
imports: [NgIf, NgFor, ParameterSelectComponent, TranslateModule],
})
export class ProcessParametersComponent implements OnChanges {
export class ProcessParametersComponent implements OnChanges, OnInit {
/**
* The currently selected script
*/
@@ -59,7 +60,7 @@ export class ProcessParametersComponent implements OnChanges {
*/
parameterValues: ProcessParameter[];
ngOnInit() {
ngOnInit(): void {
if (hasValue(this.initialParams)) {
this.parameterValues = this.initialParams;
}

View File

@@ -3,6 +3,7 @@ import {
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
@@ -44,7 +45,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
* Component for a user to edit their security information
* Displays a form containing a password field and a confirmation of the password
*/
export class ProfilePageSecurityFormComponent implements OnInit {
export class ProfilePageSecurityFormComponent implements OnDestroy, OnInit {
/**
* Emits the validity of the password

View File

@@ -189,7 +189,6 @@ export const klaroConfiguration: any = {
purposes: ['registration-password-recovery'],
required: false,
cookies: [
[/^klaro-.+$/],
CAPTCHA_COOKIE,
],
onAccept: `window.refreshCaptchaScript?.call()`,

View File

@@ -8,6 +8,7 @@ import {
Component,
Inject,
Injector,
OnInit,
} from '@angular/core';
import { Router } from '@angular/router';
import {
@@ -35,7 +36,7 @@ import { MenuService } from '../../../menu/menu.service';
standalone: true,
imports: [NgbDropdownModule, NgbTooltipModule, NgFor, NgIf, NgComponentOutlet, TranslateModule, AsyncPipe, DisabledDirective],
})
export class DsoEditMenuExpandableSectionComponent extends MenuSectionComponent {
export class DsoEditMenuExpandableSectionComponent extends MenuSectionComponent implements OnInit {
menuID: MenuID = MenuID.DSO_EDIT;
itemModel;

View File

@@ -1,6 +1,8 @@
import {
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
@@ -15,7 +17,7 @@ import { AlertType } from '../alert/alert-type';
standalone: true,
imports: [AlertComponent],
})
export class ErrorComponent {
export class ErrorComponent implements OnDestroy, OnInit {
@Input() message = 'Error...';
@@ -31,7 +33,7 @@ export class ErrorComponent {
}
ngOnInit() {
ngOnInit(): void {
if (this.message === undefined) {
this.subscription = this.translate.get('error.default').subscribe((message: string) => {
this.message = message;
@@ -39,7 +41,7 @@ export class ErrorComponent {
}
}
ngOnDestroy() {
ngOnDestroy(): void {
if (this.subscription !== undefined) {
this.subscription.unsubscribe();
}

View File

@@ -6,11 +6,13 @@ import {
NgTemplateOutlet,
} from '@angular/common';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
ContentChildren,
DoCheck,
EventEmitter,
Inject,
Input,
@@ -145,7 +147,8 @@ import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/d
],
standalone: true,
})
export class DsDynamicFormControlContainerComponent extends DynamicFormControlContainerComponent implements OnInit, OnChanges, OnDestroy {
export class DsDynamicFormControlContainerComponent extends DynamicFormControlContainerComponent
implements OnInit, OnChanges, OnDestroy, AfterViewInit, DoCheck {
@ContentChildren(DynamicTemplateDirective) contentTemplateList: QueryList<DynamicTemplateDirective>;
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('templates') inputTemplateList: QueryList<DynamicTemplateDirective>;

View File

@@ -9,6 +9,7 @@ import {
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
ViewChild,
@@ -94,7 +95,7 @@ import { DynamicOneboxModel } from './dynamic-onebox.model';
],
standalone: true,
})
export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent implements OnInit {
export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent implements OnDestroy, OnInit {
@Input() group: UntypedFormGroup;
@Input() model: DynamicOneboxModel;

View File

@@ -6,6 +6,7 @@ import {
Component,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
import { Router } from '@angular/router';
@@ -59,7 +60,7 @@ import { SearchResult } from '../../../../../search/models/search-result.model';
/**
* Tab for inside the lookup model that represents the currently selected relationships
*/
export class DsDynamicLookupRelationSelectionTabComponent {
export class DsDynamicLookupRelationSelectionTabComponent implements OnInit {
/**
* A string that describes the type of relationship
*/
@@ -122,7 +123,7 @@ export class DsDynamicLookupRelationSelectionTabComponent {
/**
* Set up the selection and pagination on load
*/
ngOnInit() {
ngOnInit(): void {
this.resetRoute();
this.selectionRD$ = this.searchConfigService.paginatedSearchOptions
.pipe(

View File

@@ -4,6 +4,7 @@ import {
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
@@ -38,7 +39,7 @@ import { isEmpty } from '../../empty.util';
standalone: true,
})
export class NumberPickerComponent implements OnInit, ControlValueAccessor {
export class NumberPickerComponent implements OnChanges, OnInit, ControlValueAccessor {
@Input() id: string;
@Input() step: number;
@Input() min: number;

View File

@@ -5,6 +5,8 @@ import {
import {
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import {
@@ -35,7 +37,7 @@ import { AccessStatusObject } from './access-status.model';
/**
* Component rendering the access status of an item as a badge
*/
export class AccessStatusBadgeComponent {
export class AccessStatusBadgeComponent implements OnDestroy, OnInit {
@Input() object: DSpaceObject;
accessStatus$: Observable<string>;

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { Observable } from 'rxjs';
import { find } from 'rxjs/operators';
import { Context } from 'src/app/core/shared/context.model';
@@ -29,7 +32,7 @@ import { SearchResultDetailElementComponent } from '../search-result-detail-elem
})
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.DetailedListElement)
export class WorkflowItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkflowItemSearchResult, WorkflowItem> {
export class WorkflowItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkflowItemSearchResult, WorkflowItem> implements OnInit {
/**
* The item object that belonging to the result object
@@ -51,7 +54,7 @@ export class WorkflowItemSearchResultDetailElementComponent extends SearchResult
/**
* Initialize all instance variables
*/
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.linkService.resolveLink(this.dso, followLink('item'));
this.initItem(this.dso.item as Observable<RemoteData<Item>>);

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { Observable } from 'rxjs';
import { find } from 'rxjs/operators';
@@ -29,7 +32,7 @@ import { SearchResultDetailElementComponent } from '../search-result-detail-elem
})
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.DetailedListElement)
export class WorkspaceItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkspaceItemSearchResult, WorkspaceItem> {
export class WorkspaceItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkspaceItemSearchResult, WorkspaceItem> implements OnInit {
/**
* The item object that belonging to the result object
@@ -51,7 +54,7 @@ export class WorkspaceItemSearchResultDetailElementComponent extends SearchResul
/**
* Initialize all instance variables
*/
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.linkService.resolveLink(this.dso, followLink('item'));
this.initItem(this.dso.item as Observable<RemoteData<Item>>);

View File

@@ -3,7 +3,10 @@ import {
NgFor,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@@ -35,7 +38,7 @@ import { SearchResultGridElementComponent } from '../../search-result-grid-eleme
/**
* The component for displaying a grid element for an item search result of the type Publication
*/
export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> {
export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> implements OnInit {
/**
* Route to the item's page
*/

View File

@@ -5,6 +5,7 @@ import {
import {
Component,
Input,
OnInit,
} from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs';
@@ -28,7 +29,7 @@ import { IdentifierData } from './identifier-data.model';
/**
* Component rendering an identifier, eg. DOI or handle
*/
export class IdentifierDataComponent {
export class IdentifierDataComponent implements OnInit {
@Input() item: Item;
identifiers$: Observable<IdentifierData>;

View File

@@ -5,6 +5,7 @@ import {
import {
Component,
Inject,
OnInit,
} from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs';
@@ -40,7 +41,7 @@ import { ThemedItemListPreviewComponent } from '../../item-list-preview/themed-i
imports: [NgIf, ThemedItemListPreviewComponent, AsyncPipe, TranslateModule, VarDirective],
})
@listableObjectComponent(ClaimedApprovedTaskSearchResult, ViewMode.ListElement)
export class ClaimedApprovedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> {
export class ClaimedApprovedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> implements OnInit {
/**
* A boolean representing if to show submitter information
@@ -69,7 +70,7 @@ export class ClaimedApprovedSearchResultListElementComponent extends SearchResul
/**
* Initialize all instance variables
*/
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.linkService.resolveLinks(this.dso,
followLink('workflowitem',

View File

@@ -5,6 +5,7 @@ import {
import {
Component,
Inject,
OnInit,
} from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs';
@@ -40,7 +41,7 @@ import { ThemedItemListPreviewComponent } from '../../item-list-preview/themed-i
imports: [NgIf, ThemedItemListPreviewComponent, AsyncPipe, TranslateModule, VarDirective],
})
@listableObjectComponent(ClaimedDeclinedTaskSearchResult, ViewMode.ListElement)
export class ClaimedDeclinedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> {
export class ClaimedDeclinedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> implements OnInit {
/**
* A boolean representing if to show submitter information
@@ -69,7 +70,7 @@ export class ClaimedDeclinedSearchResultListElementComponent extends SearchResul
/**
* Initialize all instance variables
*/
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.linkService.resolveLinks(this.dso,
followLink('workflowitem',

View File

@@ -6,6 +6,7 @@ import {
import {
Component,
Inject,
OnInit,
} from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@@ -43,7 +44,7 @@ import { SearchResultListElementComponent } from '../../search-result-list-eleme
})
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.ListElement)
export class WorkflowItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkflowItemSearchResult, WorkflowItem> {
export class WorkflowItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkflowItemSearchResult, WorkflowItem> implements OnInit {
LinkTypes = CollectionElementLinkType;
ViewModes = ViewMode;
@@ -75,7 +76,7 @@ export class WorkflowItemSearchResultListElementComponent extends SearchResultLi
/**
* Initialize all instance variables
*/
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.deriveSearchResult();
this.showThumbnails = this.appConfig.browseBy.showThumbnails;

View File

@@ -6,6 +6,7 @@ import {
import {
Component,
Inject,
OnInit,
} from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@@ -43,7 +44,7 @@ import { SearchResultListElementComponent } from '../../search-result-list-eleme
})
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.ListElement)
export class WorkspaceItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkspaceItemSearchResult, WorkspaceItem> {
export class WorkspaceItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkspaceItemSearchResult, WorkspaceItem> implements OnInit {
LinkTypes = CollectionElementLinkType;
ViewModes = ViewMode;
@@ -75,7 +76,7 @@ export class WorkspaceItemSearchResultListElementComponent extends SearchResult
/**
* Initialize all instance variables
*/
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
this.deriveSearchResult();
this.showThumbnails = this.appConfig.browseBy.showThumbnails;

View File

@@ -2,7 +2,10 @@ import {
NgClass,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { Collection } from '../../../../core/shared/collection.model';
@@ -23,7 +26,7 @@ import { SearchResultListElementComponent } from '../search-result-list-element.
* Component representing a collection search result in list view
*/
@listableObjectComponent(CollectionSearchResult, ViewMode.ListElement)
export class CollectionSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> {
export class CollectionSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> implements OnInit {
/**
* Display thumbnails if required by configuration

View File

@@ -2,7 +2,10 @@ import {
NgClass,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { Community } from '../../../../core/shared/community.model';
@@ -23,13 +26,12 @@ import { SearchResultListElementComponent } from '../search-result-list-element.
* Component representing a community search result in list view
*/
@listableObjectComponent(CommunitySearchResult, ViewMode.ListElement)
export class CommunitySearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> {
export class CommunitySearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> implements OnInit {
/**
* Display thumbnails if required by configuration
*/
showThumbnails: boolean;
ngOnInit(): void {
super.ngOnInit();
this.showThumbnails = this.showThumbnails ?? this.appConfig.browseBy.showThumbnails;

View File

@@ -4,7 +4,10 @@ import {
NgFor,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import { Item } from '../../../../../../core/shared/item.model';
@@ -30,7 +33,7 @@ import { SearchResultListElementComponent } from '../../../search-result-list-el
/**
* The component for displaying a list element for an item search result of the type Publication
*/
export class ItemSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {
export class ItemSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> implements OnInit {
/**
* Route to the item's page
*/

View File

@@ -3,7 +3,10 @@ import {
NgClass,
NgIf,
} from '@angular/common';
import { Component } from '@angular/core';
import {
Component,
OnInit,
} from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import {
Observable,
@@ -41,7 +44,7 @@ import { SearchResultListElementComponent } from '../search-result-list-element/
* It displays the name of the parent, title and description of the object. All of which are customizable in the child
* component by overriding the relevant methods of this component
*/
export class SidebarSearchListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends SearchResultListElementComponent<T, K> {
export class SidebarSearchListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends SearchResultListElementComponent<T, K> implements OnInit {
/**
* Observable for the title of the parent object (displayed above the object's title)
*/

View File

@@ -7,6 +7,7 @@ import {
ElementRef,
EventEmitter,
OnDestroy,
OnInit,
Output,
ViewChild,
} from '@angular/core';
@@ -65,7 +66,7 @@ export const compareArraysUsingFieldUuids = () =>
selector: 'ds-paginated-drag-drop-abstract',
template: '',
})
export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpaceObject> implements OnDestroy {
export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpaceObject> implements OnInit, OnDestroy {
/**
* A view on the child pagination component
*/
@@ -142,7 +143,7 @@ export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpace
/**
* Initialize the observables
*/
ngOnInit() {
ngOnInit(): void {
this.initializeObjectsRD();
this.initializeURL();
this.initializeUpdates();

View File

@@ -8,7 +8,7 @@
{{'search.filters.filter.' + filterConfig.name + '.min.label' | translate}}
</span>
<input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'"
class="form-control" (blur)="onSubmit()"
class="form-control"
[attr.aria-label]="minLabel"
[placeholder]="minLabel"
/>
@@ -20,7 +20,7 @@
{{'search.filters.filter.' + filterConfig.name + '.max.label' | translate}}
</span>
<input type="text" [(ngModel)]="range[1]" [name]="filterConfig.paramName + '.max'"
class="form-control" (blur)="onSubmit()"
class="form-control"
[attr.aria-label]="maxLabel"
[placeholder]="maxLabel"
/>
@@ -33,7 +33,8 @@
<ng-container *ngIf="shouldShowSlider()">
<nouislider [connect]="true" [config]="config" [min]="min" [max]="max" [step]="1"
[dsDebounce]="250" (onDebounce)="onSubmit()"
[dsDebounce]="250"
(change)="onSliderChange($event)"
(keydown)="startKeyboardControl()" (keyup)="stopKeyboardControl()"
[(ngModel)]="range" ngDefaultControl>
</nouislider>
@@ -43,5 +44,8 @@
<ds-search-facet-range-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value" [inPlaceSearch]="inPlaceSearch"></ds-search-facet-range-option>
</div>
</ng-container>
<button (click)="onSubmit()" class="btn btn-primary">
{{'search.filters.search.submit' | translate}}
</button>
</div>
</div>

View File

@@ -91,6 +91,11 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
*/
range: [number | undefined, number | undefined];
/**
* The range currently selected by the slider
*/
sliderRange: [number | undefined, number | undefined];
/**
* Whether the sider is being controlled by the keyboard.
* Supresses any changes until the key is released.
@@ -145,6 +150,15 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
};
}
/**
* Updates the sliderRange property with the current slider range.
* This method is called whenever the slider value changes, but it does not immediately apply the changes.
* @param range - The current range selected by the slider
*/
onSliderChange(range: [number | undefined, number | undefined]): void {
this.sliderRange = range;
}
/**
* Submits new custom range values to the range filter from the widget
*/
@@ -182,5 +196,4 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
shouldShowSlider(): boolean {
return isPlatformBrowser(this.platformId);
}
}

View File

@@ -19,9 +19,9 @@
<span><i class="fas fa-cloud-upload"
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">
<input class="form-control-file d-none" requireFile #file="ngModel" type="file" name="file-upload"
<input class="form-control-file d-none" type="file" name="file-upload"
id="file-upload"
[ngModel]="fileObject" (ngModelChange)="setFile($event)">
(change)="handleFileInput($event)">
{{'uploader.browse' | translate}}
</label>
</p>

View File

@@ -54,7 +54,7 @@ export class FileDropzoneNoUploaderComponent implements OnInit {
/**
* The function to call when file is added
*/
@Output() onFileAdded: EventEmitter<any> = new EventEmitter<any>();
@Output() onFileAdded: EventEmitter<File> = new EventEmitter<File>();
/**
* The uploader configuration options
@@ -83,15 +83,17 @@ export class FileDropzoneNoUploaderComponent implements OnInit {
}
@HostListener('window:drop', ['$event'])
onDrop(event: any) {
onDrop(event: DragEvent) {
event.preventDefault();
event.stopPropagation();
}
@HostListener('window:dragover', ['$event'])
onDragOver(event: any) {
onDragOver(event: DragEvent) {
// Show drop area on the page
event.preventDefault();
if ((event.target as any).tagName !== 'HTML') {
event.stopPropagation();
if ((event.target as HTMLElement).tagName !== 'HTML') {
this.isOverDocumentDropZone = observableOf(true);
}
}
@@ -105,11 +107,18 @@ export class FileDropzoneNoUploaderComponent implements OnInit {
}
}
public handleFileInput(event: Event) {
const input = event.target as HTMLInputElement;
if (input.files && input.files.length > 0) {
this.setFile(input.files);
}
}
/**
* Set file
* @param files
*/
setFile(files) {
public setFile(files: FileList) {
this.fileObject = files.length > 0 ? files[0] : undefined;
this.onFileAdded.emit(this.fileObject);
}

View File

@@ -6,10 +6,16 @@
top: 0;
left: 0;
z-index: -1;
display: block;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.ds-document-drop-zone-active {
z-index: var(--ds-drop-zone-area-z-index) !important;
opacity: 1;
visibility: visible;
}
.ds-document-drop-zone-inner {

View File

@@ -1,12 +1,14 @@
import { CommonModule } from '@angular/common';
import { HttpXsrfTokenExtractor } from '@angular/common/http';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
EventEmitter,
HostListener,
Input,
OnInit,
Output,
ViewEncapsulation,
} from '@angular/core';
@@ -43,7 +45,7 @@ import { UploaderProperties } from './uploader-properties.model';
standalone: true,
imports: [TranslateModule, FileUploadModule, CommonModule, DisabledDirective],
})
export class UploaderComponent {
export class UploaderComponent implements OnInit, AfterViewInit {
/**
* The message to show when drag files on the drop zone
@@ -123,7 +125,7 @@ export class UploaderComponent {
/**
* Method provided by Angular. Invoked after the constructor.
*/
ngOnInit() {
ngOnInit(): void {
this.uploaderId = 'ds-drag-and-drop-uploader' + uniqueId();
this.checkConfig(this.uploadFilesOptions);
this.uploader = new FileUploader({
@@ -148,7 +150,7 @@ export class UploaderComponent {
}
}
ngAfterViewInit() {
ngAfterViewInit(): void {
this.uploader.onAfterAddingAll = ((items) => {
this.onFileSelected.emit(items);
});

View File

@@ -55,30 +55,40 @@ export class MarkdownDirective implements OnInit, OnDestroy {
async render(value: string, forcePreview = false): Promise<SafeHtml> {
if (isEmpty(value) || (!environment.markdown.enabled && !forcePreview)) {
return value;
this.el.innerHTML = value;
return;
} else {
if (environment.markdown.mathjax) {
this.renderMathjaxThenMarkdown(value);
} else {
this.renderMarkdown(value);
}
}
}
private renderMathjaxThenMarkdown(value: string) {
const sanitized = this.sanitizer.sanitize(SecurityContext.HTML, value);
this.el.innerHTML = sanitized;
this.mathService.ready().pipe(
filter((ready) => ready),
take(1),
takeUntil(this.alive$),
).subscribe(() => {
this.mathService.render(this.el)?.then(_ => {
this.renderMarkdown(this.el.innerHTML, true);
});
});
}
private async renderMarkdown(value: string, alreadySanitized = false) {
const MarkdownIt = await this.markdownIt;
const md = new MarkdownIt({
html: true,
linkify: true,
});
const html = this.sanitizer.sanitize(SecurityContext.HTML, md.render(value));
const html = alreadySanitized ? md.render(value) : this.sanitizer.sanitize(SecurityContext.HTML, md.render(value));
this.el.innerHTML = html;
if (environment.markdown.mathjax) {
this.renderMathjax();
}
}
private renderMathjax() {
this.mathService.ready().pipe(
filter((ready) => ready),
take(1),
takeUntil(this.alive$),
).subscribe(() => {
this.mathService.render(this.el);
});
}
ngOnDestroy() {

View File

@@ -5,6 +5,7 @@ import {
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
@@ -60,7 +61,7 @@ import { SubmissionService } from '../../submission.service';
DisabledDirective,
],
})
export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
export class SubmissionFormCollectionComponent implements OnDestroy, OnChanges, OnInit {
/**
* The current collection id this submission belonging to

View File

@@ -3,6 +3,7 @@ import {
Component,
Input,
OnChanges,
OnDestroy,
} from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import {
@@ -43,7 +44,7 @@ import parseSectionErrors from '../../utils/parseSectionErrors';
],
standalone: true,
})
export class SubmissionUploadFilesComponent implements OnChanges {
export class SubmissionUploadFilesComponent implements OnChanges, OnDestroy {
/**
* The collection id this submission belonging to

View File

@@ -7,6 +7,7 @@ import {
ChangeDetectionStrategy,
Component,
Inject,
OnInit,
} from '@angular/core';
import {
TranslateModule,
@@ -48,7 +49,7 @@ import { SectionsService } from '../sections.service';
standalone: true,
})
export class SubmissionSectionDuplicatesComponent extends SectionModelComponent {
export class SubmissionSectionDuplicatesComponent extends SectionModelComponent implements OnInit {
protected readonly Metadata = Metadata;
/**
* The Alert categories.

View File

@@ -7,6 +7,7 @@ import {
ChangeDetectionStrategy,
Component,
Inject,
OnInit,
} from '@angular/core';
import {
TranslateModule,
@@ -47,7 +48,7 @@ import { SectionsService } from '../sections.service';
standalone: true,
})
export class SubmissionSectionIdentifiersComponent extends SectionModelComponent {
export class SubmissionSectionIdentifiersComponent extends SectionModelComponent implements OnInit {
/**
* The Alert categories.
* @type {AlertType}
@@ -76,7 +77,6 @@ export class SubmissionSectionIdentifiersComponent extends SectionModelComponent
/**
* Initialize instance variables.
*
* @param {PaginationService} paginationService
* @param {TranslateService} translate
* @param {SectionsService} sectionService
* @param {SubmissionService} submissionService
@@ -93,7 +93,7 @@ export class SubmissionSectionIdentifiersComponent extends SectionModelComponent
super(injectedCollectionId, injectedSectionData, injectedSubmissionId);
}
ngOnInit() {
ngOnInit(): void {
super.ngOnInit();
}

View File

@@ -50,16 +50,6 @@ export const ROUTES: Route[] = [
},
data: { title: 'workspace-item.delete', breadcrumbKey: 'workspace-item.delete' },
},
{
canActivate: [authenticatedGuard],
path: 'delete',
component: ThemedWorkspaceItemsDeletePageComponent,
resolve: {
dso: itemFromWorkspaceResolver,
breadcrumb: i18nBreadcrumbResolver,
},
data: { title: 'workspace-item.delete', breadcrumbKey: 'workspace-item.delete' },
},
],
},
];

View File

@@ -5881,7 +5881,7 @@
"workflow-item.delete.notification.success.title": "Gelöscht",
// "workflow-item.delete.notification.success.content": "This workflow item was successfully deleted",
"workflow-item.delete.notification.success.content": "Dieses Workflow-Item wurde gelöscht.",
"workflow-item.delete.notification.success.content": "Dieses Workflow-Item wurde erfolgreich gelöscht.",
// "workflow-item.delete.notification.error.title": "Something went wrong",
"workflow-item.delete.notification.error.title": "Das hat leider nicht funktioniert.",
@@ -5926,4 +5926,36 @@
// "workflow-item.send-back.button.confirm": "Send back"
"workflow-item.send-back.button.confirm": "Zurücksenden",
// "workflow-item.view.breadcrumbs": "Workflow View",
"workflow-item.view.breadcrumbs": "Workflow-Ansicht",
// "workspace-item.view.breadcrumbs": "Workspace View",
"workspace-item.view.breadcrumbs": "Workspace-Ansicht",
// "workspace-item.view.title": "Workspace View",
"workspace-item.view.title": "Workspace-Ansicht",
// "workspace-item.delete.breadcrumbs": "Workspace Delete",
"workspace-item.delete.breadcrumbs": "Workspace-Item löschen",
// "workspace-item.delete.header": "Delete workspace item",
"workspace-item.delete.header": "Workspace-Item löschen",
// "workspace-item.delete.button.confirm": "Delete",
"workspace-item.delete.button.confirm": "Löschen",
// "workspace-item.delete.button.cancel": "Cancel",
"workspace-item.delete.button.cancel": "Abbrechen",
// "workspace-item.delete.notification.success.title": "Deleted",
"workspace-item.delete.notification.success.title": "Gelöscht",
// "workspace-item.delete.title": "This workspace item was successfully deleted",
"workspace-item.delete.title": "Dieses Workspace-Item wurde erfolgreich gelöscht.",
// "workspace-item.delete.notification.error.title": "Something went wrong",
"workspace-item.delete.notification.error.title": "Das hat leider nicht funktioniert.",
// "workspace-item.delete.notification.error.content": "The workspace item could not be deleted",
"workspace-item.delete.notification.error.content": "Das Workspace-Item konnte nicht gelöscht werden.",
}

View File

@@ -6386,10 +6386,10 @@
"submission.workflow.tasks.pool.show-detail": "Afficher le détail",
// "submission.workspace.generic.view": "View",
"submission.workspace.generic.view": "Voir",
"submission.workspace.generic.view": "Afficher",
// "submission.workspace.generic.view-help": "Select this option to view the item's metadata.",
"submission.workspace.generic.view-help": "Sélectionner cette option pour voir les métadonnées de l'item.",
"submission.workspace.generic.view-help": "Sélectionner cette option pour afficher les métadonnées de l'item.",
// "thumbnail.default.alt": "Thumbnail Image",
"thumbnail.default.alt": "Vignette d'image",