Merge remote-tracking branch 'upstream/main' into themeable-section-upload-file

This commit is contained in:
Mark H. Wood
2023-05-19 13:31:05 -04:00
346 changed files with 17536 additions and 5209 deletions

View File

@@ -1,17 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

View File

@@ -31,6 +31,8 @@ jobs:
# When Chrome version is specified, we pin to a specific version of Chrome # When Chrome version is specified, we pin to a specific version of Chrome
# Comment this out to use the latest release # Comment this out to use the latest release
#CHROME_VERSION: "90.0.4430.212-1" #CHROME_VERSION: "90.0.4430.212-1"
# Bump Node heap size (OOM in CI after upgrading to Angular 15)
NODE_OPTIONS: '--max-old-space-size=4096'
strategy: strategy:
# Create a matrix of Node versions to test against (in parallel) # Create a matrix of Node versions to test against (in parallel)
matrix: matrix:

View File

@@ -274,9 +274,18 @@
} }
} }
}, },
"defaultProject": "dspace-angular",
"cli": { "cli": {
"analytics": false, "analytics": false,
"defaultCollection": "@angular-eslint/schematics" "schematicCollections": [
"@angular-eslint/schematics"
]
},
"schematics": {
"@angular-eslint/schematics:application": {
"setParserOptionsProject": true
},
"@angular-eslint/schematics:library": {
"setParserOptionsProject": true
}
} }
} }

View File

@@ -187,6 +187,9 @@ languages:
- code: gd - code: gd
label: Gàidhlig label: Gàidhlig
active: true active: true
- code: it
label: Italiano
active: true
- code: lv - code: lv
label: Latviešu label: Latviešu
active: true active: true
@@ -214,6 +217,9 @@ languages:
- code: tr - code: tr
label: Türkçe label: Türkçe
active: true active: true
- code: vi
label: Tiếng Việt
active: true
- code: kk - code: kk
label: Қазақ label: Қазақ
active: true active: true

View File

@@ -17,9 +17,9 @@
"build:stats": "ng build --stats-json", "build:stats": "ng build --stats-json",
"build:prod": "yarn run build:ssr", "build:prod": "yarn run build:ssr",
"build:ssr": "ng build --configuration production && ng run dspace-angular:server:production", "build:ssr": "ng build --configuration production && ng run dspace-angular:server:production",
"test": "ng test --sourceMap=true --watch=false --configuration test", "test": "ng test --source-map=true --watch=false --configuration test",
"test:watch": "nodemon --exec \"ng test --sourceMap=true --watch=true --configuration test\"", "test:watch": "nodemon --exec \"ng test --source-map=true --watch=true --configuration test\"",
"test:headless": "ng test --sourceMap=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage", "test:headless": "ng test --source-map=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage",
"lint": "ng lint", "lint": "ng lint",
"lint-fix": "ng lint --fix=true", "lint-fix": "ng lint --fix=true",
"e2e": "ng e2e", "e2e": "ng e2e",
@@ -55,136 +55,136 @@
"ts-node": "10.2.1" "ts-node": "10.2.1"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "~13.3.12", "@angular/animations": "^15.2.8",
"@angular/cdk": "^13.2.6", "@angular/cdk": "^15.2.8",
"@angular/common": "~13.3.12", "@angular/common": "^15.2.8",
"@angular/compiler": "~13.3.12", "@angular/compiler": "^15.2.8",
"@angular/core": "~13.3.12", "@angular/core": "^15.2.8",
"@angular/forms": "~13.3.12", "@angular/forms": "^15.2.8",
"@angular/localize": "13.3.12", "@angular/localize": "15.2.8",
"@angular/platform-browser": "~13.3.12", "@angular/platform-browser": "^15.2.8",
"@angular/platform-browser-dynamic": "~13.3.12", "@angular/platform-browser-dynamic": "^15.2.8",
"@angular/platform-server": "~13.3.12", "@angular/platform-server": "^15.2.8",
"@angular/router": "~13.3.12", "@angular/router": "^15.2.8",
"@babel/runtime": "7.17.2", "@babel/runtime": "7.21.0",
"@kolkov/ngx-gallery": "^2.0.1", "@kolkov/ngx-gallery": "^2.0.1",
"@material-ui/core": "^4.11.0", "@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1", "@material-ui/icons": "^4.11.3",
"@ng-bootstrap/ng-bootstrap": "^11.0.0", "@ng-bootstrap/ng-bootstrap": "^11.0.0",
"@ng-dynamic-forms/core": "^15.0.0", "@ng-dynamic-forms/core": "^15.0.0",
"@ng-dynamic-forms/ui-ng-bootstrap": "^15.0.0", "@ng-dynamic-forms/ui-ng-bootstrap": "^15.0.0",
"@ngrx/effects": "^13.0.2", "@ngrx/effects": "^15.4.0",
"@ngrx/router-store": "^13.0.2", "@ngrx/router-store": "^15.4.0",
"@ngrx/store": "^13.0.2", "@ngrx/store": "^15.4.0",
"@nguniversal/express-engine": "^13.0.2", "@nguniversal/express-engine": "^15.2.1",
"@ngx-translate/core": "^13.0.0", "@ngx-translate/core": "^14.0.0",
"@nicky-lenaers/ngx-scroll-to": "^13.0.0", "@nicky-lenaers/ngx-scroll-to": "^14.0.0",
"@types/grecaptcha": "^3.0.4", "@types/grecaptcha": "^3.0.4",
"angular-idle-preload": "3.0.0", "angular-idle-preload": "3.0.0",
"angulartics2": "^12.0.0", "angulartics2": "^12.2.0",
"axios": "^0.27.2", "axios": "^0.27.2",
"bootstrap": "^4.6.1", "bootstrap": "^4.6.1",
"cerialize": "0.1.18", "cerialize": "0.1.18",
"cli-progress": "^3.8.0", "cli-progress": "^3.12.0",
"colors": "^1.4.0", "colors": "^1.4.0",
"compression": "^1.7.4", "compression": "^1.7.4",
"cookie-parser": "1.4.5", "cookie-parser": "1.4.6",
"core-js": "^3.7.0", "core-js": "^3.30.1",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"date-fns-tz": "^1.3.7", "date-fns-tz": "^1.3.7",
"deepmerge": "^4.2.2", "deepmerge": "^4.3.1",
"ejs": "^3.1.8", "ejs": "^3.1.9",
"express": "^4.17.1", "express": "^4.18.2",
"express-rate-limit": "^5.1.3", "express-rate-limit": "^5.1.3",
"fast-json-patch": "^3.0.0-1", "fast-json-patch": "^3.1.1",
"filesize": "^6.1.0", "filesize": "^6.1.0",
"http-proxy-middleware": "^1.0.5", "http-proxy-middleware": "^1.0.5",
"isbot": "^3.6.5", "isbot": "^3.6.10",
"js-cookie": "2.2.1", "js-cookie": "2.2.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"json5": "^2.2.2", "json5": "^2.2.3",
"jsonschema": "1.4.0", "jsonschema": "1.4.1",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"klaro": "^0.7.18", "klaro": "^0.7.18",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lru-cache": "^7.14.1", "lru-cache": "^7.14.1",
"markdown-it": "^13.0.1", "markdown-it": "^13.0.1",
"markdown-it-mathjax3": "^4.3.1", "markdown-it-mathjax3": "^4.3.2",
"mirador": "^3.3.0", "mirador": "^3.3.0",
"mirador-dl-plugin": "^0.13.0", "mirador-dl-plugin": "^0.13.0",
"mirador-share-plugin": "^0.11.0", "mirador-share-plugin": "^0.11.0",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"ng-mocks": "^13.1.1", "ng-mocks": "^14.10.0",
"ng2-file-upload": "1.4.0", "ng2-file-upload": "1.4.0",
"ng2-nouislider": "^1.8.3", "ng2-nouislider": "^1.8.3",
"ngx-infinite-scroll": "^10.0.1", "ngx-infinite-scroll": "^15.0.0",
"ngx-pagination": "5.0.0", "ngx-pagination": "6.0.3",
"ngx-sortablejs": "^11.1.0", "ngx-sortablejs": "^11.1.0",
"ngx-ui-switch": "^13.0.2", "ngx-ui-switch": "^14.0.3",
"nouislider": "^14.6.3", "nouislider": "^14.6.3",
"pem": "1.14.4", "pem": "1.14.7",
"prop-types": "^15.7.2", "prop-types": "^15.8.1",
"react-copy-to-clipboard": "^5.0.1", "react-copy-to-clipboard": "^5.1.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rxjs": "^7.5.5", "rxjs": "^7.8.0",
"sanitize-html": "^2.7.2", "sanitize-html": "^2.10.0",
"sortablejs": "1.13.0", "sortablejs": "1.15.0",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"webfontloader": "1.6.28", "webfontloader": "1.6.28",
"zone.js": "~0.11.5" "zone.js": "~0.11.5"
}, },
"devDependencies": { "devDependencies": {
"@angular-builders/custom-webpack": "~13.1.0", "@angular-builders/custom-webpack": "~15.0.0",
"@angular-devkit/build-angular": "~13.3.10", "@angular-devkit/build-angular": "^15.2.6",
"@angular-eslint/builder": "13.1.0", "@angular-eslint/builder": "15.2.1",
"@angular-eslint/eslint-plugin": "13.1.0", "@angular-eslint/eslint-plugin": "15.2.1",
"@angular-eslint/eslint-plugin-template": "13.1.0", "@angular-eslint/eslint-plugin-template": "15.2.1",
"@angular-eslint/schematics": "13.1.0", "@angular-eslint/schematics": "15.2.1",
"@angular-eslint/template-parser": "13.1.0", "@angular-eslint/template-parser": "15.2.1",
"@angular/cli": "~13.3.10", "@angular/cli": "^15.2.6",
"@angular/compiler-cli": "~13.3.12", "@angular/compiler-cli": "^15.2.8",
"@angular/language-service": "~13.3.12", "@angular/language-service": "^15.2.8",
"@cypress/schematic": "^1.5.0", "@cypress/schematic": "^1.5.0",
"@fortawesome/fontawesome-free": "^6.2.1", "@fortawesome/fontawesome-free": "^6.4.0",
"@ngrx/store-devtools": "^13.0.2", "@ngrx/store-devtools": "^15.4.0",
"@ngtools/webpack": "^13.2.6", "@ngtools/webpack": "^15.2.6",
"@nguniversal/builders": "^13.1.1", "@nguniversal/builders": "^15.2.1",
"@types/deep-freeze": "0.1.2", "@types/deep-freeze": "0.1.2",
"@types/ejs": "^3.1.1", "@types/ejs": "^3.1.2",
"@types/express": "^4.17.9", "@types/express": "^4.17.17",
"@types/jasmine": "~3.6.0", "@types/jasmine": "~3.6.0",
"@types/js-cookie": "2.2.6", "@types/js-cookie": "2.2.6",
"@types/lodash": "^4.14.165", "@types/lodash": "^4.14.194",
"@types/node": "^14.14.9", "@types/node": "^14.14.9",
"@types/sanitize-html": "^2.6.2", "@types/sanitize-html": "^2.9.0",
"@typescript-eslint/eslint-plugin": "5.11.0", "@typescript-eslint/eslint-plugin": "^5.59.1",
"@typescript-eslint/parser": "5.11.0", "@typescript-eslint/parser": "^5.59.1",
"axe-core": "^4.4.3", "axe-core": "^4.7.0",
"compression-webpack-plugin": "^9.2.0", "compression-webpack-plugin": "^9.2.0",
"copy-webpack-plugin": "^6.4.1", "copy-webpack-plugin": "^6.4.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"cypress": "12.9.0", "cypress": "12.10.0",
"cypress-axe": "^1.1.0", "cypress-axe": "^1.4.0",
"deep-freeze": "0.0.1", "deep-freeze": "0.0.1",
"eslint": "^8.2.0", "eslint": "^8.39.0",
"eslint-plugin-deprecation": "^1.3.2", "eslint-plugin-deprecation": "^1.4.1",
"eslint-plugin-import": "^2.25.4", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsdoc": "^39.6.4", "eslint-plugin-jsdoc": "^39.6.4",
"eslint-plugin-jsonc": "^2.6.0", "eslint-plugin-jsonc": "^2.6.0",
"eslint-plugin-lodash": "^7.4.0", "eslint-plugin-lodash": "^7.4.0",
"eslint-plugin-unused-imports": "^2.0.0", "eslint-plugin-unused-imports": "^2.0.0",
"express-static-gzip": "^2.1.5", "express-static-gzip": "^2.1.7",
"jasmine-core": "^3.8.0", "jasmine-core": "^3.8.0",
"jasmine-marbles": "0.9.2", "jasmine-marbles": "0.9.2",
"karma": "^6.3.14", "karma": "^6.4.2",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.2.0",
"karma-coverage-istanbul-reporter": "~3.0.2", "karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.0", "karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0", "karma-jasmine-html-reporter": "^1.5.0",
"karma-mocha-reporter": "2.2.5", "karma-mocha-reporter": "2.2.5",
"ngx-mask": "^13.1.7", "ngx-mask": "^13.1.7",
"nodemon": "^2.0.20", "nodemon": "^2.0.22",
"postcss": "^8.1", "postcss": "^8.4",
"postcss-apply": "0.12.0", "postcss-apply": "0.12.0",
"postcss-import": "^14.0.0", "postcss-import": "^14.0.0",
"postcss-loader": "^4.0.3", "postcss-loader": "^4.0.3",
@@ -194,14 +194,14 @@
"react-dom": "^16.14.0", "react-dom": "^16.14.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs-spy": "^8.0.2", "rxjs-spy": "^8.0.2",
"sass": "~1.33.0", "sass": "~1.62.0",
"sass-loader": "^12.6.0", "sass-loader": "^12.6.0",
"sass-resources-loader": "^2.1.1", "sass-resources-loader": "^2.2.5",
"ts-node": "^8.10.2", "ts-node": "^8.10.2",
"typescript": "~4.5.5", "typescript": "~4.8.4",
"webpack": "^5.76.0", "webpack": "5.76.1",
"webpack-bundle-analyzer": "^4.4.0", "webpack-bundle-analyzer": "^4.8.0",
"webpack-cli": "^4.2.0", "webpack-cli": "^4.2.0",
"webpack-dev-server": "^4.5.0" "webpack-dev-server": "^4.13.3"
} }
} }

View File

@@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs';
@@ -89,7 +89,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
private translateService: TranslateService, private translateService: TranslateService,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private authorizationService: AuthorizationDataService, private authorizationService: AuthorizationDataService,
private formBuilder: FormBuilder, private formBuilder: UntypedFormBuilder,
private router: Router, private router: Router,
private modalService: NgbModal, private modalService: NgbModal,
private paginationService: PaginationService, private paginationService: PaginationService,

View File

@@ -2,7 +2,7 @@ import { Observable, of as observableOf } from 'rxjs';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { UntypedFormControl, UntypedFormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser'; import { BrowserModule, By } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
@@ -116,9 +116,9 @@ describe('EPersonFormComponent', () => {
const controlModel = model; const controlModel = model;
const controlState = { value: controlModel.value, disabled: controlModel.disabled }; const controlState = { value: controlModel.value, disabled: controlModel.disabled };
const controlOptions = this.createAbstractControlOptions(controlModel.validators, controlModel.asyncValidators, controlModel.updateOn); const controlOptions = this.createAbstractControlOptions(controlModel.validators, controlModel.asyncValidators, controlModel.updateOn);
controls[model.id] = new FormControl(controlState, controlOptions); controls[model.id] = new UntypedFormControl(controlState, controlOptions);
}); });
return new FormGroup(controls, options); return new UntypedFormGroup(controls, options);
}, },
createAbstractControlOptions(validatorsConfig = null, asyncValidatorsConfig = null, updateOn = null) { createAbstractControlOptions(validatorsConfig = null, asyncValidatorsConfig = null, updateOn = null) {
return { return {

View File

@@ -1,5 +1,5 @@
import { ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; import { ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { import {
DynamicCheckboxModel, DynamicCheckboxModel,
DynamicFormControlModel, DynamicFormControlModel,
@@ -108,7 +108,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
/** /**
* A FormGroup that combines all inputs * A FormGroup that combines all inputs
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* An EventEmitter that's fired whenever the form is being submitted * An EventEmitter that's fired whenever the form is being submitted

View File

@@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { UntypedFormControl, UntypedFormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser'; import { BrowserModule, By } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@@ -130,9 +130,9 @@ describe('GroupFormComponent', () => {
const controlModel = model; const controlModel = model;
const controlState = { value: controlModel.value, disabled: controlModel.disabled }; const controlState = { value: controlModel.value, disabled: controlModel.disabled };
const controlOptions = this.createAbstractControlOptions(controlModel.validators, controlModel.asyncValidators, controlModel.updateOn); const controlOptions = this.createAbstractControlOptions(controlModel.validators, controlModel.asyncValidators, controlModel.updateOn);
controls[model.id] = new FormControl(controlState, controlOptions); controls[model.id] = new UntypedFormControl(controlState, controlOptions);
}); });
return new FormGroup(controls, options); return new UntypedFormGroup(controls, options);
}, },
createAbstractControlOptions(validatorsConfig = null, asyncValidatorsConfig = null, updateOn = null) { createAbstractControlOptions(validatorsConfig = null, asyncValidatorsConfig = null, updateOn = null) {
return { return {

View File

@@ -1,5 +1,5 @@
import { Component, EventEmitter, HostListener, OnDestroy, OnInit, Output, ChangeDetectorRef } from '@angular/core'; import { Component, EventEmitter, HostListener, OnDestroy, OnInit, Output, ChangeDetectorRef } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { import {
@@ -95,7 +95,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
/** /**
* A FormGroup that combines all inputs * A FormGroup that combines all inputs
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* An EventEmitter that's fired whenever the form is being submitted * An EventEmitter that's fired whenever the form is being submitted

View File

@@ -1,5 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
@@ -141,7 +141,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
public ePersonDataService: EPersonDataService, public ePersonDataService: EPersonDataService,
protected translateService: TranslateService, protected translateService: TranslateService,
protected notificationsService: NotificationsService, protected notificationsService: NotificationsService,
protected formBuilder: FormBuilder, protected formBuilder: UntypedFormBuilder,
protected paginationService: PaginationService, protected paginationService: PaginationService,
private router: Router private router: Router
) { ) {

View File

@@ -1,5 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs'; import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs';
@@ -86,7 +86,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
constructor(public groupDataService: GroupDataService, constructor(public groupDataService: GroupDataService,
private translateService: TranslateService, private translateService: TranslateService,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private formBuilder: FormBuilder, private formBuilder: UntypedFormBuilder,
private paginationService: PaginationService, private paginationService: PaginationService,
private router: Router) { private router: Router) {
this.currentSearchQuery = ''; this.currentSearchQuery = '';

View File

@@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
@@ -99,7 +99,7 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
private dSpaceObjectDataService: DSpaceObjectDataService, private dSpaceObjectDataService: DSpaceObjectDataService,
private translateService: TranslateService, private translateService: TranslateService,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private formBuilder: FormBuilder, private formBuilder: UntypedFormBuilder,
protected routeService: RouteService, protected routeService: RouteService,
private router: Router, private router: Router,
private authorizationService: AuthorizationDataService, private authorizationService: AuthorizationDataService,

View File

@@ -5,7 +5,7 @@ import {
DynamicFormLayout, DynamicFormLayout,
DynamicInputModel DynamicInputModel
} from '@ng-dynamic-forms/core'; } from '@ng-dynamic-forms/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { RegistryService } from '../../../../core/registry/registry.service'; import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
@@ -66,7 +66,7 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
/** /**
* A FormGroup that combines all inputs * A FormGroup that combines all inputs
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* An EventEmitter that's fired whenever the form is being submitted * An EventEmitter that's fired whenever the form is being submitted

View File

@@ -5,7 +5,7 @@ import {
DynamicFormLayout, DynamicFormLayout,
DynamicInputModel DynamicInputModel
} from '@ng-dynamic-forms/core'; } from '@ng-dynamic-forms/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { RegistryService } from '../../../../core/registry/registry.service'; import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
@@ -82,7 +82,7 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
/** /**
* A FormGroup that combines all inputs * A FormGroup that combines all inputs
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* An EventEmitter that's fired whenever the form is being submitted * An EventEmitter that's fired whenever the form is being submitted

View File

@@ -19,7 +19,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-
import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock'; import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock';
import { ThemeService } from '../../../../../shared/theme-support/theme.service'; import { ThemeService } from '../../../../../shared/theme-support/theme.service';
import { AccessStatusDataService } from '../../../../../core/data/access-status-data.service'; import { AccessStatusDataService } from '../../../../../core/data/access-status-data.service';
import { AccessStatusObject } from '../../../../../shared/object-list/access-status-badge/access-status.model'; import { AccessStatusObject } from '../../../../../shared/object-collection/shared/badges/access-status-badge/access-status.model';
import { AuthService } from '../../../../../core/auth/auth.service'; import { AuthService } from '../../../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../../../shared/testing/auth-service.stub'; import { AuthServiceStub } from '../../../../../shared/testing/auth-service.stub';
import { FileService } from '../../../../../core/shared/file.service'; import { FileService } from '../../../../../core/shared/file.service';

View File

@@ -2,6 +2,5 @@
[viewMode]="viewModes.ListElement" [viewMode]="viewModes.ListElement"
[index]="index" [index]="index"
[linkType]="linkType" [linkType]="linkType"
[listID]="listID" [listID]="listID"></ds-listable-object-component-loader>
[hideBadges]="true"></ds-listable-object-component-loader>
<ds-item-admin-search-result-actions-element [item]="dso" [small]="false"></ds-item-admin-search-result-actions-element> <ds-item-admin-search-result-actions-element [item]="dso" [small]="false"></ds-item-admin-search-result-actions-element>

View File

@@ -11,7 +11,7 @@ import { URLCombiner } from '../../../../../core/url-combiner/url-combiner';
import { WorkspaceItemAdminWorkflowActionsComponent } from './workspace-item-admin-workflow-actions.component'; import { WorkspaceItemAdminWorkflowActionsComponent } from './workspace-item-admin-workflow-actions.component';
import { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model'; import { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model';
import { import {
getWorkflowItemDeleteRoute, getWorkspaceItemDeleteRoute,
} from '../../../../../workflowitems-edit-page/workflowitems-edit-page-routing-paths'; } from '../../../../../workflowitems-edit-page/workflowitems-edit-page-routing-paths';
import { Item } from '../../../../../core/shared/item.model'; import { Item } from '../../../../../core/shared/item.model';
import { RemoteData } from '../../../../../core/data/remote-data'; import { RemoteData } from '../../../../../core/data/remote-data';
@@ -83,7 +83,7 @@ describe('WorkspaceItemAdminWorkflowActionsComponent', () => {
it('should render a delete button with the correct link', () => { it('should render a delete button with the correct link', () => {
const button = fixture.debugElement.query(By.css('a.delete-link')); const button = fixture.debugElement.query(By.css('a.delete-link'));
const link = button.nativeElement.href; const link = button.nativeElement.href;
expect(link).toContain(new URLCombiner(getWorkflowItemDeleteRoute(wsi.id)).toString()); expect(link).toContain(new URLCombiner(getWorkspaceItemDeleteRoute(wsi.id)).toString());
}); });
it('should render a policies button with the correct link', () => { it('should render a policies button with the correct link', () => {

View File

@@ -11,7 +11,7 @@ import {
SupervisionOrderGroupSelectorComponent SupervisionOrderGroupSelectorComponent
} from './supervision-order-group-selector/supervision-order-group-selector.component'; } from './supervision-order-group-selector/supervision-order-group-selector.component';
import { import {
getWorkflowItemDeleteRoute getWorkspaceItemDeleteRoute
} from '../../../../../workflowitems-edit-page/workflowitems-edit-page-routing-paths'; } from '../../../../../workflowitems-edit-page/workflowitems-edit-page-routing-paths';
import { ITEM_EDIT_AUTHORIZATIONS_PATH } from '../../../../../item-page/edit-item-page/edit-item-page.routing-paths'; import { ITEM_EDIT_AUTHORIZATIONS_PATH } from '../../../../../item-page/edit-item-page/edit-item-page.routing-paths';
import { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model'; import { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model';
@@ -105,10 +105,10 @@ export class WorkspaceItemAdminWorkflowActionsComponent implements OnInit {
} }
/** /**
* Returns the path to the delete page of this workflow item * Returns the path to the delete page of this workspace item
*/ */
getDeleteRoute(): string { getDeleteRoute(): string {
return getWorkflowItemDeleteRoute(this.wsi.id); return getWorkspaceItemDeleteRoute(this.wsi.id);
} }
/** /**

View File

@@ -209,7 +209,7 @@ import { ThemedPageErrorComponent } from './page-error/themed-page-error.compone
{ {
path: REQUEST_COPY_MODULE_PATH, path: REQUEST_COPY_MODULE_PATH,
loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule), loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule),
canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] canActivate: [EndUserAgreementCurrentUserGuard]
}, },
{ {
path: FORBIDDEN_PATH, path: FORBIDDEN_PATH,

View File

@@ -2,7 +2,7 @@
<div class="container" *ngVar="(bitstreamFormatsRD$ | async) as formatsRD"> <div class="container" *ngVar="(bitstreamFormatsRD$ | async) as formatsRD">
<div class="row" *ngIf="bitstreamRD?.hasSucceeded && formatsRD?.hasSucceeded"> <div class="row" *ngIf="bitstreamRD?.hasSucceeded && formatsRD?.hasSucceeded">
<div class="col-md-2"> <div class="col-md-2">
<ds-thumbnail [thumbnail]="bitstreamRD?.payload"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="bitstreamRD?.payload"></ds-themed-thumbnail>
</div> </div>
<div class="col-md-10"> <div class="col-md-10">
<div class="container"> <div class="container">

View File

@@ -15,7 +15,7 @@ import { INotification, Notification } from '../../shared/notifications/models/n
import { BitstreamFormat } from '../../core/shared/bitstream-format.model'; import { BitstreamFormat } from '../../core/shared/bitstream-format.model';
import { BitstreamFormatSupportLevel } from '../../core/shared/bitstream-format-support-level'; import { BitstreamFormatSupportLevel } from '../../core/shared/bitstream-format-support-level';
import { hasValue } from '../../shared/empty.util'; import { hasValue } from '../../shared/empty.util';
import { FormControl, FormGroup } from '@angular/forms'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { FileSizePipe } from '../../shared/utils/file-size-pipe'; import { FileSizePipe } from '../../shared/utils/file-size-pipe';
import { VarDirective } from '../../shared/utils/var.directive'; import { VarDirective } from '../../shared/utils/var.directive';
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
@@ -84,9 +84,9 @@ describe('EditBitstreamPageComponent', () => {
const controls = {}; const controls = {};
if (hasValue(fModel)) { if (hasValue(fModel)) {
fModel.forEach((controlModel) => { fModel.forEach((controlModel) => {
controls[controlModel.id] = new FormControl((controlModel as any).value); controls[controlModel.id] = new UntypedFormControl((controlModel as any).value);
}); });
return new FormGroup(controls); return new UntypedFormGroup(controls);
} }
return undefined; return undefined;
} }

View File

@@ -23,7 +23,7 @@ import {
DynamicInputModel, DynamicInputModel,
DynamicSelectModel DynamicSelectModel
} from '@ng-dynamic-forms/core'; } from '@ng-dynamic-forms/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model'; import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
@@ -359,7 +359,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
/** /**
* The form group of this form * The form group of this form
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* The ID of the item the bitstream originates from * The ID of the item the bitstream originates from

View File

@@ -12,7 +12,7 @@ import { NotificationType } from '../../../shared/notifications/models/notificat
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { DynamicFormControlModel, DynamicFormService } from '@ng-dynamic-forms/core'; import { DynamicFormControlModel, DynamicFormService } from '@ng-dynamic-forms/core';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
import { FormControl, FormGroup } from '@angular/forms'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { RouterStub } from '../../../shared/testing/router.stub'; import { RouterStub } from '../../../shared/testing/router.stub';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { Collection } from '../../../core/shared/collection.model'; import { Collection } from '../../../core/shared/collection.model';
@@ -98,9 +98,9 @@ describe('CollectionSourceComponent', () => {
const controls = {}; const controls = {};
if (hasValue(fModel)) { if (hasValue(fModel)) {
fModel.forEach((controlModel) => { fModel.forEach((controlModel) => {
controls[controlModel.id] = new FormControl((controlModel as any).value); controls[controlModel.id] = new UntypedFormControl((controlModel as any).value);
}); });
return new FormGroup(controls); return new UntypedFormGroup(controls);
} }
return undefined; return undefined;
} }

View File

@@ -14,7 +14,7 @@ import { Location } from '@angular/common';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service'; import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { hasNoValue, hasValue, isNotEmpty } from '../../../shared/empty.util'; import { hasNoValue, hasValue, isNotEmpty } from '../../../shared/empty.util';
import { ContentSource, ContentSourceHarvestType } from '../../../core/shared/content-source.model'; import { ContentSource, ContentSourceHarvestType } from '../../../core/shared/content-source.model';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
@@ -202,7 +202,7 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
/** /**
* The form group of this form * The form group of this form
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* Subscription to update the current form * Subscription to update the current form

View File

@@ -8,10 +8,10 @@
<span class="fa fa-chevron-right invisible" aria-hidden="true"></span> <span class="fa fa-chevron-right invisible" aria-hidden="true"></span>
</button> </button>
<div class="align-middle pt-2"> <div class="align-middle pt-2">
<a *ngIf="node!==loadingNode" [routerLink]="[]" (click)="getNextPage(node)" <button *ngIf="node!==loadingNode" (click)="getNextPage(node)"
class="btn btn-outline-primary btn-sm" role="button"> class="btn btn-outline-primary btn-sm" role="button">
<i class="fas fa-angle-down"></i> {{ 'communityList.showMore' | translate }} <i class="fas fa-angle-down"></i> {{ 'communityList.showMore' | translate }}
</a> </button>
<ds-themed-loading *ngIf="node===loadingNode && dataSource.loading$ | async" class="ds-themed-loading"></ds-themed-loading> <ds-themed-loading *ngIf="node===loadingNode && dataSource.loading$ | async" class="ds-themed-loading"></ds-themed-loading>
</div> </div>
</div> </div>

View File

@@ -16,6 +16,7 @@ import { of as observableOf } from 'rxjs';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { isEmpty, isNotEmpty } from '../../shared/empty.util'; import { isEmpty, isNotEmpty } from '../../shared/empty.util';
import { FlatNode } from '../flat-node.model'; import { FlatNode } from '../flat-node.model';
import { RouterLinkWithHref } from '@angular/router';
describe('CommunityListComponent', () => { describe('CommunityListComponent', () => {
let component: CommunityListComponent; let component: CommunityListComponent;
@@ -193,7 +194,8 @@ describe('CommunityListComponent', () => {
}, },
}), }),
CdkTreeModule, CdkTreeModule,
RouterTestingModule], RouterTestingModule,
RouterLinkWithHref],
declarations: [CommunityListComponent], declarations: [CommunityListComponent],
providers: [CommunityListComponent, providers: [CommunityListComponent,
{ provide: CommunityListService, useValue: communityListServiceStub },], { provide: CommunityListService, useValue: communityListServiceStub },],
@@ -230,9 +232,14 @@ describe('CommunityListComponent', () => {
expect(showMoreEl).toBeTruthy(); expect(showMoreEl).toBeTruthy();
}); });
it('should not render the show more button as an empty link', () => {
const debugElements = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref));
expect(debugElements).toBeTruthy();
});
describe('when show more of top communities is clicked', () => { describe('when show more of top communities is clicked', () => {
beforeEach(fakeAsync(() => { beforeEach(fakeAsync(() => {
const showMoreLink = fixture.debugElement.query(By.css('.show-more-node a')); const showMoreLink = fixture.debugElement.query(By.css('.show-more-node .btn-outline-primary'));
showMoreLink.triggerEventHandler('click', { showMoreLink.triggerEventHandler('click', {
preventDefault: () => {/**/ preventDefault: () => {/**/
} }
@@ -240,6 +247,7 @@ describe('CommunityListComponent', () => {
tick(); tick();
fixture.detectChanges(); fixture.detectChanges();
})); }));
it('tree contains maximum of currentPage (2) * (2) elementsPerPage of first top communities, or less if there are less communities (3)', () => { it('tree contains maximum of currentPage (2) * (2) elementsPerPage of first top communities, or less if there are less communities (3)', () => {
const expandableNodesFound = fixture.debugElement.queryAll(By.css('.expandable-node a')); const expandableNodesFound = fixture.debugElement.queryAll(By.css('.expandable-node a'));
const childlessNodesFound = fixture.debugElement.queryAll(By.css('.childless-node a')); const childlessNodesFound = fixture.debugElement.queryAll(By.css('.childless-node a'));

View File

@@ -1,4 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { BehaviorSubject, combineLatest as observableCombineLatest } from 'rxjs'; import { BehaviorSubject, combineLatest as observableCombineLatest } from 'rxjs';
@@ -49,19 +50,23 @@ export class CommunityPageSubCollectionListComponent implements OnInit, OnDestro
*/ */
subCollectionsRDObs: BehaviorSubject<RemoteData<PaginatedList<Collection>>> = new BehaviorSubject<RemoteData<PaginatedList<Collection>>>({} as any); subCollectionsRDObs: BehaviorSubject<RemoteData<PaginatedList<Collection>>> = new BehaviorSubject<RemoteData<PaginatedList<Collection>>>({} as any);
constructor(private cds: CollectionDataService, constructor(
private paginationService: PaginationService, protected cds: CollectionDataService,
protected paginationService: PaginationService,
) {} protected route: ActivatedRoute,
) {
}
ngOnInit(): void { ngOnInit(): void {
this.config = new PaginationComponentOptions(); this.config = new PaginationComponentOptions();
this.config.id = this.pageId; this.config.id = this.pageId;
if (hasValue(this.pageSize)) { if (hasValue(this.pageSize)) {
this.config.pageSize = this.pageSize; this.config.pageSize = this.pageSize;
} else {
this.config.pageSize = this.route.snapshot.queryParams[this.pageId + '.rpp'] ?? this.config.pageSize;
} }
this.config.currentPage = 1; this.config.currentPage = this.route.snapshot.queryParams[this.pageId + '.page'] ?? 1;
this.sortConfig = new SortOptions('dc.title', SortDirection.ASC); this.sortConfig = new SortOptions('dc.title', SortDirection[this.route.snapshot.queryParams[this.pageId + '.sd']] ?? SortDirection.ASC);
this.initPage(); this.initPage();
} }

View File

@@ -1,4 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { BehaviorSubject, combineLatest as observableCombineLatest } from 'rxjs'; import { BehaviorSubject, combineLatest as observableCombineLatest } from 'rxjs';
@@ -9,7 +10,6 @@ import { PaginatedList } from '../../core/data/paginated-list.model';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { CommunityDataService } from '../../core/data/community-data.service'; import { CommunityDataService } from '../../core/data/community-data.service';
import { takeUntilCompletedRemoteData } from '../../core/shared/operators';
import { switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
import { PaginationService } from '../../core/pagination/pagination.service'; import { PaginationService } from '../../core/pagination/pagination.service';
import { hasValue } from '../../shared/empty.util'; import { hasValue } from '../../shared/empty.util';
@@ -52,8 +52,10 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy
*/ */
subCommunitiesRDObs: BehaviorSubject<RemoteData<PaginatedList<Community>>> = new BehaviorSubject<RemoteData<PaginatedList<Community>>>({} as any); subCommunitiesRDObs: BehaviorSubject<RemoteData<PaginatedList<Community>>> = new BehaviorSubject<RemoteData<PaginatedList<Community>>>({} as any);
constructor(private cds: CommunityDataService, constructor(
private paginationService: PaginationService protected cds: CommunityDataService,
protected paginationService: PaginationService,
protected route: ActivatedRoute,
) { ) {
} }
@@ -62,9 +64,11 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy
this.config.id = this.pageId; this.config.id = this.pageId;
if (hasValue(this.pageSize)) { if (hasValue(this.pageSize)) {
this.config.pageSize = this.pageSize; this.config.pageSize = this.pageSize;
} else {
this.config.pageSize = this.route.snapshot.queryParams[this.pageId + '.rpp'] ?? this.config.pageSize;
} }
this.config.currentPage = 1; this.config.currentPage = this.route.snapshot.queryParams[this.pageId + '.page'] ?? 1;
this.sortConfig = new SortOptions('dc.title', SortDirection.ASC); this.sortConfig = new SortOptions('dc.title', SortDirection[this.route.snapshot.queryParams[this.pageId + '.sd']] ?? SortDirection.ASC);
this.initPage(); this.initPage();
} }
@@ -86,15 +90,6 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy
).subscribe((results) => { ).subscribe((results) => {
this.subCommunitiesRDObs.next(results); this.subCommunitiesRDObs.next(results);
}); });
this.cds.findByParent(this.community.id, {
currentPage: this.config.currentPage,
elementsPerPage: this.config.pageSize,
sort: { field: this.sortConfig.field, direction: this.sortConfig.direction }
}).pipe(takeUntilCompletedRemoteData()).subscribe((results) => {
this.subCommunitiesRDObs.next(results);
});
} }
ngOnDestroy(): void { ngOnDestroy(): void {

View File

@@ -60,7 +60,7 @@ export class LinkService {
const provider = this.getDataServiceFor(matchingLinkDef.resourceType); const provider = this.getDataServiceFor(matchingLinkDef.resourceType);
if (hasNoValue(provider)) { if (hasNoValue(provider)) {
throw new Error(`The @link() for ${linkToFollow.name} on ${model.constructor.name} models uses the resource type ${matchingLinkDef.resourceType.value.toUpperCase()}, but there is no service with an @dataService(${matchingLinkDef.resourceType.value.toUpperCase()}) annotation in order to retrieve it`); throw new Error(`The @link() for ${String(linkToFollow.name)} on ${model.constructor.name} models uses the resource type ${matchingLinkDef.resourceType.value.toUpperCase()}, but there is no service with an @dataService(${matchingLinkDef.resourceType.value.toUpperCase()}) annotation in order to retrieve it`);
} }
const service: HALDataService<any> = Injector.create({ const service: HALDataService<any> = Injector.create({
@@ -79,12 +79,12 @@ export class LinkService {
return service.findByHref(href, linkToFollow.useCachedVersionIfAvailable, linkToFollow.reRequestOnStale, ...linkToFollow.linksToFollow); return service.findByHref(href, linkToFollow.useCachedVersionIfAvailable, linkToFollow.reRequestOnStale, ...linkToFollow.linksToFollow);
} }
} catch (e) { } catch (e) {
console.error(`Something went wrong when using @dataService(${matchingLinkDef.resourceType.value}) ${hasValue(service) ? '' : '(undefined) '}to resolve link ${linkToFollow.name} at ${href}`); console.error(`Something went wrong when using @dataService(${matchingLinkDef.resourceType.value}) ${hasValue(service) ? '' : '(undefined) '}to resolve link ${String(linkToFollow.name)} at ${href}`);
throw e; throw e;
} }
} }
} else if (!linkToFollow.isOptional) { } else if (!linkToFollow.isOptional) {
throw new Error(`followLink('${linkToFollow.name}') was used as a required link for a ${model.constructor.name}, but there is no property on ${model.constructor.name} models with an @link() for ${linkToFollow.name}`); throw new Error(`followLink('${String(linkToFollow.name)}') was used as a required link for a ${model.constructor.name}, but there is no property on ${model.constructor.name} models with an @link() for ${String(linkToFollow.name)}`);
} }
return EMPTY; return EMPTY;

View File

@@ -73,7 +73,7 @@ export class RemoteDataBuildService {
if (getResourceTypeValueFor((obj as any).type) === PAGINATED_LIST.value) { if (getResourceTypeValueFor((obj as any).type) === PAGINATED_LIST.value) {
return this.buildPaginatedList<T>(obj, ...linksToFollow); return this.buildPaginatedList<T>(obj, ...linksToFollow);
} else if (isNotEmpty(linksToFollow)) { } else if (isNotEmpty(linksToFollow)) {
return [this.linkService.resolveLinks(obj, ...linksToFollow)]; return [this.linkService.resolveLinks(obj as any, ...linksToFollow)];
} }
} }
return [obj]; return [obj];

View File

@@ -160,7 +160,7 @@ import { SubmissionAccessesModel } from './config/models/config-submission-acces
import { RatingAdvancedWorkflowInfo } from './tasks/models/rating-advanced-workflow-info.model'; import { RatingAdvancedWorkflowInfo } from './tasks/models/rating-advanced-workflow-info.model';
import { AdvancedWorkflowInfo } from './tasks/models/advanced-workflow-info.model'; import { AdvancedWorkflowInfo } from './tasks/models/advanced-workflow-info.model';
import { SelectReviewerAdvancedWorkflowInfo } from './tasks/models/select-reviewer-advanced-workflow-info.model'; import { SelectReviewerAdvancedWorkflowInfo } from './tasks/models/select-reviewer-advanced-workflow-info.model';
import { AccessStatusObject } from '../shared/object-list/access-status-badge/access-status.model'; import { AccessStatusObject } from '../shared/object-collection/shared/badges/access-status-badge/access-status.model';
import { AccessStatusDataService } from './data/access-status-data.service'; import { AccessStatusDataService } from './data/access-status-data.service';
import { LinkHeadService } from './services/link-head.service'; import { LinkHeadService } from './services/link-head.service';
import { ResearcherProfileDataService } from './profile/researcher-profile-data.service'; import { ResearcherProfileDataService } from './profile/researcher-profile-data.service';

View File

@@ -3,8 +3,8 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
import { ObjectCacheService } from '../cache/object-cache.service'; import { ObjectCacheService } from '../cache/object-cache.service';
import { HALEndpointService } from '../shared/hal-endpoint.service'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { RequestService } from './request.service'; import { RequestService } from './request.service';
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model'; import { AccessStatusObject } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model';
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type'; import { ACCESS_STATUS } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.resource-type';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { RemoteData } from './remote-data'; import { RemoteData } from './remote-data';
import { Item } from '../shared/item.model'; import { Item } from '../shared/item.model';

View File

@@ -641,6 +641,62 @@ describe('BaseDataService', () => {
}); });
}); });
describe('hasCachedResponse', () => {
it('should return false when the request will be dispatched', (done) => {
const result = service.hasCachedResponse('test-href');
result.subscribe((hasCachedResponse) => {
expect(hasCachedResponse).toBeFalse();
done();
});
});
it('should return true when the request will not be dispatched', (done) => {
(requestService.shouldDispatchRequest as jasmine.Spy).and.returnValue(false);
const result = service.hasCachedResponse('test-href');
result.subscribe((hasCachedResponse) => {
expect(hasCachedResponse).toBeTrue();
done();
});
});
});
describe('hasCachedErrorResponse', () => {
it('should return false when no response is cached', (done) => {
spyOn(service,'hasCachedResponse').and.returnValue(observableOf(false));
const result = service.hasCachedErrorResponse('test-href');
result.subscribe((hasCachedErrorResponse) => {
expect(hasCachedErrorResponse).toBeFalse();
done();
});
});
it('should return false when no error response is cached', (done) => {
spyOn(service,'hasCachedResponse').and.returnValue(observableOf(true));
spyOn(rdbService,'buildSingle').and.returnValue(createSuccessfulRemoteDataObject$({}));
const result = service.hasCachedErrorResponse('test-href');
result.subscribe((hasCachedErrorResponse) => {
expect(hasCachedErrorResponse).toBeFalse();
done();
});
});
it('should return true when an error response is cached', (done) => {
spyOn(service,'hasCachedResponse').and.returnValue(observableOf(true));
spyOn(rdbService,'buildSingle').and.returnValue(createFailedRemoteDataObject$());
const result = service.hasCachedErrorResponse('test-href');
result.subscribe((hasCachedErrorResponse) => {
expect(hasCachedErrorResponse).toBeTrue();
done();
});
});
});
describe('addDependency', () => { describe('addDependency', () => {
let addDependencySpy; let addDependencySpy;

View File

@@ -341,6 +341,48 @@ export class BaseDataService<T extends CacheableObject> implements HALDataServic
} }
} }
/**
* Checks for the provided href whether a response is already cached
* @param href$ The url for which to check whether there is a cached response.
* Can be a string or an Observable<string>
*/
hasCachedResponse(href$: string | Observable<string>): Observable<boolean> {
if (isNotEmpty(href$)) {
if (typeof href$ === 'string') {
href$ = observableOf(href$);
}
return href$.pipe(
isNotEmptyOperator(),
take(1),
map((href: string) => {
const requestId = this.requestService.generateRequestId();
const request = new GetRequest(requestId, href);
return !this.requestService.shouldDispatchRequest(request, true);
}),
);
}
throw new Error(`Can't check whether there is a cached response for an empty href$`);
}
/**
* Checks for the provided href whether an ERROR response is currently cached
* @param href$ The url for which to check whether there is a cached ERROR response.
* Can be a string or an Observable<string>
*/
hasCachedErrorResponse(href$: string | Observable<string>): Observable<boolean> {
return this.hasCachedResponse(href$).pipe(
switchMap((hasCachedResponse) => {
if (hasCachedResponse) {
return this.rdbService.buildSingle(href$).pipe(
getFirstCompletedRemoteData(),
map((rd => rd.hasFailed))
);
}
return observableOf(false);
})
);
}
/** /**
* Return the links to traverse from the root of the api to the * Return the links to traverse from the root of the api to the
* endpoint this DataService represents * endpoint this DataService represents

View File

@@ -5,6 +5,7 @@ import { ExternalSourceEntry } from '../shared/external-source-entry.model';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { GetRequest } from './request.models'; import { GetRequest } from './request.models';
import { testSearchDataImplementation } from './base/search-data.spec'; import { testSearchDataImplementation } from './base/search-data.spec';
import { take } from 'rxjs/operators';
describe('ExternalSourceService', () => { describe('ExternalSourceService', () => {
let service: ExternalSourceDataService; let service: ExternalSourceDataService;
@@ -64,19 +65,42 @@ describe('ExternalSourceService', () => {
}); });
describe('getExternalSourceEntries', () => { describe('getExternalSourceEntries', () => {
let result;
beforeEach(() => { describe('when no error response is cached', () => {
result = service.getExternalSourceEntries('test'); let result;
beforeEach(() => {
spyOn(service, 'hasCachedErrorResponse').and.returnValue(observableOf(false));
result = service.getExternalSourceEntries('test');
});
it('should send a GetRequest', () => {
result.pipe(take(1)).subscribe();
expect(requestService.send).toHaveBeenCalledWith(jasmine.any(GetRequest), true);
});
it('should return the entries', () => {
result.subscribe((resultRD) => {
expect(resultRD.payload.page).toBe(entries);
});
});
}); });
it('should send a GetRequest', () => { describe('when an error response is cached', () => {
expect(requestService.send).toHaveBeenCalledWith(jasmine.any(GetRequest), true); let result;
}); beforeEach(() => {
spyOn(service, 'hasCachedErrorResponse').and.returnValue(observableOf(true));
result = service.getExternalSourceEntries('test');
});
it('should return the entries', () => { it('should send a GetRequest', () => {
result.subscribe((resultRD) => { result.pipe(take(1)).subscribe();
expect(resultRD.payload.page).toBe(entries); expect(requestService.send).toHaveBeenCalledWith(jasmine.any(GetRequest), false);
});
it('should return the entries', () => {
result.subscribe((resultRD) => {
expect(resultRD.payload.page).toBe(entries);
});
}); });
}); });
}); });

View File

@@ -74,7 +74,12 @@ export class ExternalSourceDataService extends IdentifiableDataService<ExternalS
); );
// TODO create a dedicated ExternalSourceEntryDataService and move this entire method to it. Then the "as any"s won't be necessary // TODO create a dedicated ExternalSourceEntryDataService and move this entire method to it. Then the "as any"s won't be necessary
return this.findListByHref(href$, undefined, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow as any) as any;
return this.hasCachedErrorResponse(href$).pipe(
switchMap((hasCachedErrorResponse) => {
return this.findListByHref(href$, undefined, !hasCachedErrorResponse, reRequestOnStale, ...linksToFollow as any);
})
) as any;
} }
/** /**

View File

@@ -28,7 +28,7 @@ describe('LocaleService test suite', () => {
isAuthenticationLoaded: jasmine.createSpy('isAuthenticationLoaded') isAuthenticationLoaded: jasmine.createSpy('isAuthenticationLoaded')
}); });
const langList = ['en', 'it', 'de']; const langList = ['en', 'xx', 'de'];
beforeEach(waitForAsync(() => { beforeEach(waitForAsync(() => {
return TestBed.configureTestingModule({ return TestBed.configureTestingModule({
@@ -82,8 +82,8 @@ describe('LocaleService test suite', () => {
}); });
it('should return language from browser setting', () => { it('should return language from browser setting', () => {
spyOn(translateService, 'getBrowserLang').and.returnValue('it'); spyOn(translateService, 'getBrowserLang').and.returnValue('xx');
expect(service.getCurrentLanguageCode()).toBe('it'); expect(service.getCurrentLanguageCode()).toBe('xx');
}); });
it('should return default language from config', () => { it('should return default language from config', () => {
@@ -114,9 +114,9 @@ describe('LocaleService test suite', () => {
}); });
it('should set the given language', () => { it('should set the given language', () => {
service.setCurrentLanguageCode('it'); service.setCurrentLanguageCode('xx');
expect(translateService.use).toHaveBeenCalledWith('it'); expect(translateService.use).toHaveBeenCalledWith('xx');
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('it'); expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('xx');
}); });
it('should set the current language', () => { it('should set the current language', () => {
@@ -135,7 +135,7 @@ describe('LocaleService test suite', () => {
describe('', () => { describe('', () => {
it('should set quality to current language list', () => { it('should set quality to current language list', () => {
const langListWithQuality = ['en;q=1', 'it;q=0.9', 'de;q=0.8']; const langListWithQuality = ['en;q=1', 'xx;q=0.9', 'de;q=0.8'];
spyOn(service, 'setQuality').and.returnValue(langListWithQuality); spyOn(service, 'setQuality').and.returnValue(langListWithQuality);
service.setQuality(langList, LANG_ORIGIN.BROWSER, false); service.setQuality(langList, LANG_ORIGIN.BROWSER, false);
expect(service.setQuality).toHaveBeenCalledWith(langList, LANG_ORIGIN.BROWSER, false); expect(service.setQuality).toHaveBeenCalledWith(langList, LANG_ORIGIN.BROWSER, false);

View File

@@ -3,17 +3,38 @@
*/ */
export enum Context { export enum Context {
/** Default context */
Any = 'undefined', Any = 'undefined',
/** General item page context */
ItemPage = 'itemPage', ItemPage = 'itemPage',
/** General search page context */
Search = 'search', Search = 'search',
Workflow = 'workflow', Workflow = 'workflow',
Workspace = 'workspace', Workspace = 'workspace',
SupervisedItems = 'supervisedWorkspace', SupervisedItems = 'supervisedWorkspace',
/** Administrative menu context */
AdminMenu = 'adminMenu', AdminMenu = 'adminMenu',
EntitySearchModalWithNameVariants = 'EntitySearchModalWithNameVariants', EntitySearchModalWithNameVariants = 'EntitySearchModalWithNameVariants',
EntitySearchModal = 'EntitySearchModal', EntitySearchModal = 'EntitySearchModal',
/** Administrative search page context */
AdminSearch = 'adminSearch', AdminSearch = 'adminSearch',
AdminWorkflowSearch = 'adminWorkflowSearch', AdminWorkflowSearch = 'adminWorkflowSearch',
SideBarSearchModal = 'sideBarSearchModal', SideBarSearchModal = 'sideBarSearchModal',
SideBarSearchModalCurrent = 'sideBarSearchModalCurrent', SideBarSearchModalCurrent = 'sideBarSearchModalCurrent',
/** The MyDSpace* Context values below are used for badge display in MyDSpace. */
MyDSpaceArchived = 'mydspaceArchived',
MyDSpaceWorkspace = 'mydspaceWorkspace',
MyDSpaceWorkflow = 'mydspaceWorkflow',
MyDSpaceDeclined = 'mydspaceDeclined',
MyDSpaceApproved = 'mydspaceApproved',
MyDSpaceWaitingController = 'mydspaceWaitingController',
MyDSpaceValidation = 'mydspaceValidation',
} }

View File

@@ -21,8 +21,8 @@ import { Version } from './version.model';
import { VERSION } from './version.resource-type'; import { VERSION } from './version.resource-type';
import { BITSTREAM } from './bitstream.resource-type'; import { BITSTREAM } from './bitstream.resource-type';
import { Bitstream } from './bitstream.model'; import { Bitstream } from './bitstream.model';
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type'; import { ACCESS_STATUS } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.resource-type';
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model'; import { AccessStatusObject } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model';
import { HandleObject } from './handle-object.model'; import { HandleObject } from './handle-object.model';
import { IDENTIFIERS } from '../../shared/object-list/identifier-data/identifier-data.resource-type'; import { IDENTIFIERS } from '../../shared/object-list/identifier-data/identifier-data.resource-type';
import { IdentifierData } from '../../shared/object-list/identifier-data/identifier-data.model'; import { IdentifierData } from '../../shared/object-list/identifier-data/identifier-data.model';

View File

@@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { ScriptDataService } from '../core/data/processes/script-data.service'; import { ScriptDataService } from '../core/data/processes/script-data.service';
import { FormControl, FormGroup } from '@angular/forms'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { getFirstCompletedRemoteData } from '../core/shared/operators'; import { getFirstCompletedRemoteData } from '../core/shared/operators';
import { find, map } from 'rxjs/operators'; import { find, map } from 'rxjs/operators';
import { NotificationsService } from '../shared/notifications/notifications.service'; import { NotificationsService } from '../shared/notifications/notifications.service';
@@ -28,7 +28,7 @@ export class CurationFormComponent implements OnInit {
config: Observable<RemoteData<ConfigurationProperty>>; config: Observable<RemoteData<ConfigurationProperty>>;
tasks: string[]; tasks: string[];
form: FormGroup; form: UntypedFormGroup;
@Input() @Input()
dsoHandle: string; dsoHandle: string;
@@ -40,14 +40,15 @@ export class CurationFormComponent implements OnInit {
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private translateService: TranslateService, private translateService: TranslateService,
private handleService: HandleService, private handleService: HandleService,
private router: Router private router: Router,
private cdr: ChangeDetectorRef
) { ) {
} }
ngOnInit(): void { ngOnInit(): void {
this.form = new FormGroup({ this.form = new UntypedFormGroup({
task: new FormControl(''), task: new UntypedFormControl(''),
handle: new FormControl('') handle: new UntypedFormControl('')
}); });
this.config = this.configurationDataService.findByPropertyName(CURATION_CFG); this.config = this.configurationDataService.findByPropertyName(CURATION_CFG);
@@ -59,6 +60,7 @@ export class CurationFormComponent implements OnInit {
.filter((value) => isNotEmpty(value) && value.includes('=')) .filter((value) => isNotEmpty(value) && value.includes('='))
.map((value) => value.split('=')[1].trim()); .map((value) => value.split('=')[1].trim());
this.form.get('task').patchValue(this.tasks[0]); this.form.get('task').patchValue(this.tasks[0]);
this.cdr.detectChanges();
}); });
} }

View File

@@ -7,7 +7,7 @@
[dsDebounce]="300" (onDebounce)="confirm.emit(false)"></textarea> [dsDebounce]="300" (onDebounce)="confirm.emit(false)"></textarea>
<div class="d-flex" *ngIf="mdRepresentation"> <div class="d-flex" *ngIf="mdRepresentation">
<a class="mr-2" target="_blank" [routerLink]="mdRepresentationItemRoute$ | async">{{ mdRepresentationName$ | async }}</a> <a class="mr-2" target="_blank" [routerLink]="mdRepresentationItemRoute$ | async">{{ mdRepresentationName$ | async }}</a>
<ds-type-badge [object]="mdRepresentation"></ds-type-badge> <ds-themed-type-badge [object]="mdRepresentation"></ds-themed-type-badge>
</div> </div>
</div> </div>
<div class="ds-flex-cell ds-lang-cell" role="cell"> <div class="ds-flex-cell ds-lang-cell" role="cell">

View File

@@ -68,7 +68,7 @@ describe('DsoEditMetadataValueComponent', () => {
}); });
it('should not show a badge', () => { it('should not show a badge', () => {
expect(fixture.debugElement.query(By.css('ds-type-badge'))).toBeNull(); expect(fixture.debugElement.query(By.css('ds-themed-type-badge'))).toBeNull();
}); });
describe('when no changes have been made', () => { describe('when no changes have been made', () => {
@@ -134,7 +134,7 @@ describe('DsoEditMetadataValueComponent', () => {
}); });
it('should show a badge', () => { it('should show a badge', () => {
expect(fixture.debugElement.query(By.css('ds-type-badge'))).toBeTruthy(); expect(fixture.debugElement.query(By.css('ds-themed-type-badge'))).toBeTruthy();
}); });
assertButton(EDIT_BTN, true, true); assertButton(EDIT_BTN, true, true);

View File

@@ -17,7 +17,7 @@ import {
} from '../../../core/shared/operators'; } from '../../../core/shared/operators';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { RegistryService } from '../../../core/registry/registry.service'; import { RegistryService } from '../../../core/registry/registry.service';
import { FormControl } from '@angular/forms'; import { UntypedFormControl } from '@angular/forms';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
import { Subscription } from 'rxjs/internal/Subscription'; import { Subscription } from 'rxjs/internal/Subscription';
@@ -70,7 +70,7 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy, AfterV
/** /**
* FormControl for the input * FormControl for the input
*/ */
public input: FormControl = new FormControl(); public input: UntypedFormControl = new UntypedFormControl();
/** /**
* The current query to update mdFieldOptions$ for * The current query to update mdFieldOptions$ for

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate"> class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</a> </a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width"> <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</span> </span>
<div class="card-body"> <div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4"> <ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4> <h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part> </ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate"> class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</a> </a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width"> <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</span> </span>
<div class="card-body"> <div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4"> <ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4> <h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part> </ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate"> class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</a> </a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width"> <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</span> </span>
<div class="card-body"> <div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4"> <ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4> <h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part> </ds-truncatable-part>

View File

@@ -12,7 +12,7 @@
</span> </span>
</div> </div>
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'"> <div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" rel="noopener noreferrer"

View File

@@ -12,7 +12,7 @@
</span> </span>
</div> </div>
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'"> <div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" rel="noopener noreferrer"

View File

@@ -11,7 +11,7 @@
</span> </span>
</div> </div>
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'"> <div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out" [routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out"

View File

@@ -7,7 +7,7 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail [thumbnail]="object?.thumbnail | async"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="object?.thumbnail | async"></ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="object" <ds-generic-item-page-field [item]="object"
[fields]="['publicationvolume.volumeNumber']" [fields]="['publicationvolume.volumeNumber']"

View File

@@ -7,7 +7,7 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail [thumbnail]="object?.thumbnail | async"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="object?.thumbnail | async"></ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="object" <ds-generic-item-page-field [item]="object"
[fields]="['publicationvolume.volumeNumber']" [fields]="['publicationvolume.volumeNumber']"

View File

@@ -7,7 +7,7 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail [thumbnail]="object?.thumbnail | async"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="object?.thumbnail | async"></ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field class="item-page-fields" [item]="object" <ds-generic-item-page-field class="item-page-fields" [item]="object"
[fields]="['creativeworkseries.issn']" [fields]="['creativeworkseries.issn']"

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate"> class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</a> </a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width"> <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</span> </span>
<div class="card-body"> <div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4"> <ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4> <h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part> </ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate"> class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</a> </a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width"> <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</span> </span>
<div class="card-body"> <div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4"> <ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4> <h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part> </ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate"> class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</a> </a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width"> <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div> <div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false"> <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail> </ds-themed-thumbnail>
</div> </div>
</span> </span>
<div class="card-body"> <div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4"> <ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4> <h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part> </ds-truncatable-part>

View File

@@ -18,7 +18,7 @@
</span> </span>
</div> </div>
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'"> <div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" rel="noopener noreferrer"

View File

@@ -18,7 +18,7 @@
</span> </span>
</div> </div>
<div [ngClass]="showThumbnails ? 'col-9 col-md-10' : 'col-12'"> <div [ngClass]="showThumbnails ? 'col-9 col-md-10' : 'col-12'">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" rel="noopener noreferrer"

View File

@@ -19,7 +19,7 @@
</div> </div>
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'"> <div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" rel="noopener noreferrer"
[routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out" [routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out"

View File

@@ -7,12 +7,12 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail [thumbnail]="object?.thumbnail | async" <ds-themed-thumbnail [thumbnail]="object?.thumbnail | async"
[defaultImage]="'assets/images/orgunit-placeholder.svg'" [defaultImage]="'assets/images/orgunit-placeholder.svg'"
[alt]="'thumbnail.orgunit.alt'" [alt]="'thumbnail.orgunit.alt'"
[placeholder]="'thumbnail.orgunit.placeholder'" [placeholder]="'thumbnail.orgunit.placeholder'"
> >
</ds-thumbnail> </ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="object" <ds-generic-item-page-field [item]="object"
[fields]="['organization.foundingDate']" [fields]="['organization.foundingDate']"

View File

@@ -7,11 +7,11 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail [thumbnail]="object?.thumbnail | async" <ds-themed-thumbnail [thumbnail]="object?.thumbnail | async"
[defaultImage]="'assets/images/person-placeholder.svg'" [defaultImage]="'assets/images/person-placeholder.svg'"
[alt]="'thumbnail.person.alt'" [alt]="'thumbnail.person.alt'"
[placeholder]="'thumbnail.person.placeholder'"> [placeholder]="'thumbnail.person.placeholder'">
</ds-thumbnail> </ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="object" <ds-generic-item-page-field [item]="object"
[fields]="['person.email']" [fields]="['person.email']"

View File

@@ -7,12 +7,12 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail <ds-themed-thumbnail
[thumbnail]="object?.thumbnail | async" [thumbnail]="object?.thumbnail | async"
[defaultImage]="'assets/images/project-placeholder.svg'" [defaultImage]="'assets/images/project-placeholder.svg'"
[alt]="'thumbnail.project.alt'" [alt]="'thumbnail.project.alt'"
[placeholder]="'thumbnail.project.placeholder'"> [placeholder]="'thumbnail.project.placeholder'">
</ds-thumbnail> </ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<!--<ds-generic-item-page-field [item]="object"--> <!--<ds-generic-item-page-field [item]="object"-->
<!--[fields]="['project.identifier.status']"--> <!--[fields]="['project.identifier.status']"-->

View File

@@ -1,12 +1,12 @@
<ng-template #descTemplate> <ng-template #descTemplate>
<span class="text-muted"> <span class="text-muted">
<span class="item-list-job-title"> <span class="item-list-job-title">
<span [innerHTML]="metadataRepresentation.firstMetadataValue(['dc.description'])"></span> <span [innerHTML]="mdRepresentation.firstMetadataValue(['dc.description'])"></span>
</span> </span>
</span> </span>
</ng-template> </ng-template>
<ds-truncatable [id]="metadataRepresentation.id"> <ds-truncatable [id]="mdRepresentation.id">
<a [routerLink]="[itemPageRoute]" <a [routerLink]="[itemPageRoute]"
[innerHTML]="metadataRepresentation.getValue()" [innerHTML]="mdRepresentation.getValue()"
[ngbTooltip]="metadataRepresentation.allMetadata(['dc.description']).length > 0 ? descTemplate : null"></a> [ngbTooltip]="mdRepresentation.allMetadata(['dc.description']).length > 0 ? descTemplate : null"></a>
</ds-truncatable> </ds-truncatable>

View File

@@ -34,7 +34,7 @@ describe('OrgUnitItemMetadataListElementComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(OrgUnitItemMetadataListElementComponent); fixture = TestBed.createComponent(OrgUnitItemMetadataListElementComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.metadataRepresentation = mockItemMetadataRepresentation; comp.mdRepresentation = mockItemMetadataRepresentation;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -1,15 +1,15 @@
<ng-template #descTemplate> <ng-template #descTemplate>
<span class="text-muted"> <span class="text-muted">
<span *ngIf="metadataRepresentation.allMetadata(['person.jobTitle']).length > 0" <span *ngIf="mdRepresentation.allMetadata(['person.jobTitle']).length > 0"
class="item-list-job-title"> class="item-list-job-title">
<span *ngFor="let value of metadataRepresentation.allMetadataValues(['person.jobTitle']); let last=last;"> <span *ngFor="let value of mdRepresentation.allMetadataValues(['person.jobTitle']); let last=last;">
<span [innerHTML]="value"><span [innerHTML]="value"></span></span> <span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span> </span>
</span> </span>
</span> </span>
</ng-template> </ng-template>
<ds-truncatable [id]="metadataRepresentation.id"> <ds-truncatable [id]="mdRepresentation.id">
<a [routerLink]="[itemPageRoute]" <a [routerLink]="[itemPageRoute]"
[innerHTML]="metadataRepresentation.getValue()" [innerHTML]="mdRepresentation.getValue()"
[ngbTooltip]="metadataRepresentation.allMetadata(['person.jobTitle']).length > 0 ? descTemplate : null"></a> [ngbTooltip]="mdRepresentation.allMetadata(['person.jobTitle']).length > 0 ? descTemplate : null"></a>
</ds-truncatable> </ds-truncatable>

View File

@@ -36,7 +36,7 @@ describe('PersonItemMetadataListElementComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(PersonItemMetadataListElementComponent); fixture = TestBed.createComponent(PersonItemMetadataListElementComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.metadataRepresentation = mockItemMetadataRepresentation; comp.mdRepresentation = mockItemMetadataRepresentation;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -1,6 +1,6 @@
<div class="d-flex"> <div class="d-flex">
<!-- <div class="person-thumbnail pr-2">--> <!-- <div class="person-thumbnail pr-2">-->
<!-- <ds-thumbnail [thumbnail]="dso?.thumbnail | async" [defaultImage]="'assets/images/orgunit-placeholder.svg'"></ds-thumbnail>--> <!-- <ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [defaultImage]="'assets/images/orgunit-placeholder.svg'"></ds-themed-thumbnail>-->
<!-- </div>--> <!-- </div>-->
<div class="flex-grow-1"> <div class="flex-grow-1">
<ds-org-unit-input-suggestions *ngIf="useNameVariants" [suggestions]="allSuggestions" [(ngModel)]="selectedName" (clickSuggestion)="select($event)" <ds-org-unit-input-suggestions *ngIf="useNameVariants" [suggestions]="allSuggestions" [(ngModel)]="selectedName" (clickSuggestion)="select($event)"

View File

@@ -5,7 +5,7 @@ import { NotificationsServiceStub } from '../../shared/testing/notifications-ser
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { UntypedFormBuilder, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { EPersonDataService } from '../../core/eperson/eperson-data.service'; import { EPersonDataService } from '../../core/eperson/eperson-data.service';
@@ -60,7 +60,7 @@ describe('ForgotPasswordFormComponent', () => {
{provide: ActivatedRoute, useValue: route}, {provide: ActivatedRoute, useValue: route},
{provide: Store, useValue: store}, {provide: Store, useValue: store},
{provide: EPersonDataService, useValue: ePersonDataService}, {provide: EPersonDataService, useValue: ePersonDataService},
{provide: FormBuilder, useValue: new FormBuilder()}, {provide: UntypedFormBuilder, useValue: new UntypedFormBuilder()},
{provide: NotificationsService, useValue: notificationsService}, {provide: NotificationsService, useValue: notificationsService},
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]

View File

@@ -1,7 +1,4 @@
@media screen and (max-width: map-get($grid-breakpoints, md)) { :host {
:host.open { position: relative;
background-color: var(--bs-white); z-index: var(--ds-nav-z-index);
top: 0;
position: sticky;
}
} }

View File

@@ -1,3 +0,0 @@
:host {
z-index: var(--ds-nav-z-index);
}

View File

@@ -11,13 +11,12 @@
line-height: 1.5; line-height: 1.5;
} }
.navbar ::ng-deep { .navbar-toggler {
a { border: none;
color: var(--ds-header-icon-color); color: var(--ds-header-icon-color);
&:hover, &:focus { &:hover, &:focus {
color: var(--ds-header-icon-color-hover); color: var(--ds-header-icon-color-hover);
}
} }
} }

View File

@@ -4,6 +4,6 @@
<ds-view-tracker [object]="site"></ds-view-tracker> <ds-view-tracker [object]="site"></ds-view-tracker>
</ng-container> </ng-container>
<ds-themed-search-form [inPlaceSearch]="false" [searchPlaceholder]="'home.search-form.placeholder' | translate"></ds-themed-search-form> <ds-themed-search-form [inPlaceSearch]="false" [searchPlaceholder]="'home.search-form.placeholder' | translate"></ds-themed-search-form>
<ds-top-level-community-list></ds-top-level-community-list> <ds-themed-top-level-community-list></ds-themed-top-level-community-list>
<ds-recent-item-list *ngIf="recentSubmissionspageSize>0"></ds-recent-item-list> <ds-recent-item-list *ngIf="recentSubmissionspageSize>0"></ds-recent-item-list>
</div> </div>

View File

@@ -12,11 +12,13 @@ import { ThemedHomePageComponent } from './themed-home-page.component';
import { RecentItemListComponent } from './recent-item-list/recent-item-list.component'; import { RecentItemListComponent } from './recent-item-list/recent-item-list.component';
import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module'; import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module';
import { ResearchEntitiesModule } from '../entity-groups/research-entities/research-entities.module'; import { ResearchEntitiesModule } from '../entity-groups/research-entities/research-entities.module';
import { ThemedTopLevelCommunityListComponent } from './top-level-community-list/themed-top-level-community-list.component';
const DECLARATIONS = [ const DECLARATIONS = [
HomePageComponent, HomePageComponent,
ThemedHomePageComponent, ThemedHomePageComponent,
TopLevelCommunityListComponent, TopLevelCommunityListComponent,
ThemedTopLevelCommunityListComponent,
ThemedHomeNewsComponent, ThemedHomeNewsComponent,
HomeNewsComponent, HomeNewsComponent,
RecentItemListComponent RecentItemListComponent

View File

@@ -0,0 +1,25 @@
import { Component } from '@angular/core';
import { TopLevelCommunityListComponent } from './top-level-community-list.component';
import { ThemedComponent } from '../../shared/theme-support/themed.component';
@Component({
selector: 'ds-themed-top-level-community-list',
styleUrls: [],
templateUrl: '../../shared/theme-support/themed.component.html',
})
export class ThemedTopLevelCommunityListComponent extends ThemedComponent<TopLevelCommunityListComponent> {
protected inAndOutputNames: (keyof TopLevelCommunityListComponent & keyof this)[];
protected getComponentName(): string {
return 'TopLevelCommunityListComponent';
}
protected importThemedComponent(themeName: string): Promise<any> {
return import(`../../../themes/${themeName}/app/home-page/top-level-community-list/top-level-community-list.component`);
}
protected importUnthemedComponent(): Promise<any> {
return import(`./top-level-community-list.component`);
}
}

View File

@@ -7,7 +7,7 @@ import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { RouteService } from '../../../core/services/route.service'; import { RouteService } from '../../../core/services/route.service';
import { routeServiceStub } from '../../../shared/testing/route-service.stub'; import { routeServiceStub } from '../../../shared/testing/route-service.stub';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { AuthService } from '../../../core/auth/auth.service'; import { AuthService } from '../../../core/auth/auth.service';
@@ -41,7 +41,7 @@ describe('FeedbackFormComponent', () => {
declarations: [FeedbackFormComponent], declarations: [FeedbackFormComponent],
providers: [ providers: [
{ provide: RouteService, useValue: routeServiceStub }, { provide: RouteService, useValue: routeServiceStub },
{ provide: FormBuilder, useValue: new FormBuilder() }, { provide: UntypedFormBuilder, useValue: new UntypedFormBuilder() },
{ provide: NotificationsService, useValue: notificationService }, { provide: NotificationsService, useValue: notificationService },
{ provide: FeedbackDataService, useValue: feedbackDataServiceStub }, { provide: FeedbackDataService, useValue: feedbackDataServiceStub },
{ provide: AuthService, useValue: authService }, { provide: AuthService, useValue: authService },

View File

@@ -3,7 +3,7 @@ import { NoContent } from '../../../core/shared/NoContent.model';
import { FeedbackDataService } from '../../../core/feedback/feedback-data.service'; import { FeedbackDataService } from '../../../core/feedback/feedback-data.service';
import { Component, Inject, OnInit } from '@angular/core'; import { Component, Inject, OnInit } from '@angular/core';
import { RouteService } from '../../../core/services/route.service'; import { RouteService } from '../../../core/services/route.service';
import { FormBuilder, Validators } from '@angular/forms'; import { UntypedFormBuilder, Validators } from '@angular/forms';
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { AuthService } from '../../../core/auth/auth.service'; import { AuthService } from '../../../core/auth/auth.service';
@@ -37,7 +37,7 @@ export class FeedbackFormComponent implements OnInit {
constructor( constructor(
@Inject(NativeWindowService) protected _window: NativeWindowRef, @Inject(NativeWindowService) protected _window: NativeWindowRef,
public routeService: RouteService, public routeService: RouteService,
private fb: FormBuilder, private fb: UntypedFormBuilder,
protected notificationsService: NotificationsService, protected notificationsService: NotificationsService,
protected translate: TranslateService, protected translate: TranslateService,
private feedbackDataService: FeedbackDataService, private feedbackDataService: FeedbackDataService,

View File

@@ -11,7 +11,7 @@ import { combineLatest as observableCombineLatest, Observable, of as observableO
import { getBitstreamDownloadRoute, getForbiddenRoute } from '../../../app-routing-paths'; import { getBitstreamDownloadRoute, getForbiddenRoute } from '../../../app-routing-paths';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { EPerson } from '../../../core/eperson/models/eperson.model'; import { EPerson } from '../../../core/eperson/models/eperson.model';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { ItemRequestDataService } from '../../../core/data/item-request-data.service'; import { ItemRequestDataService } from '../../../core/data/item-request-data.service';
import { ItemRequest } from '../../../core/shared/item-request.model'; import { ItemRequest } from '../../../core/shared/item-request.model';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
@@ -34,7 +34,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy {
canDownload$: Observable<boolean>; canDownload$: Observable<boolean>;
private subs: Subscription[] = []; private subs: Subscription[] = [];
requestCopyForm: FormGroup; requestCopyForm: UntypedFormGroup;
item: Item; item: Item;
itemName: string; itemName: string;
@@ -49,7 +49,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy {
protected router: Router, protected router: Router,
private authorizationService: AuthorizationDataService, private authorizationService: AuthorizationDataService,
private auth: AuthService, private auth: AuthService,
private formBuilder: FormBuilder, private formBuilder: UntypedFormBuilder,
private itemRequestDataService: ItemRequestDataService, private itemRequestDataService: ItemRequestDataService,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private dsoNameService: DSONameService, private dsoNameService: DSONameService,
@@ -59,15 +59,15 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.requestCopyForm = this.formBuilder.group({ this.requestCopyForm = this.formBuilder.group({
name: new FormControl('', { name: new UntypedFormControl('', {
validators: [Validators.required], validators: [Validators.required],
}), }),
email: new FormControl('', { email: new UntypedFormControl('', {
validators: [Validators.required, validators: [Validators.required,
Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$')] Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$')]
}), }),
allfiles: new FormControl(''), allfiles: new UntypedFormControl(''),
message: new FormControl(''), message: new UntypedFormControl(''),
}); });

View File

@@ -38,7 +38,7 @@ import { IdentifierDataService } from '../../core/data/identifier-data.service';
import { IdentifierDataComponent } from '../../shared/object-list/identifier-data/identifier-data.component'; import { IdentifierDataComponent } from '../../shared/object-list/identifier-data/identifier-data.component';
import { ItemRegisterDoiComponent } from './item-register-doi/item-register-doi.component'; import { ItemRegisterDoiComponent } from './item-register-doi/item-register-doi.component';
import { DsoSharedModule } from '../../dso-shared/dso-shared.module'; import { DsoSharedModule } from '../../dso-shared/dso-shared.module';
import { ItemCurateComponent } from './item-curate/item-curate.component';
/** /**
* Module that contains all components related to the Edit Item page administrator functionality * Module that contains all components related to the Edit Item page administrator functionality
@@ -81,7 +81,8 @@ import { DsoSharedModule } from '../../dso-shared/dso-shared.module';
VirtualMetadataComponent, VirtualMetadataComponent,
ItemAuthorizationsComponent, ItemAuthorizationsComponent,
IdentifierDataComponent, IdentifierDataComponent,
ItemRegisterDoiComponent ItemRegisterDoiComponent,
ItemCurateComponent
], ],
providers: [ providers: [
BundleDataService, BundleDataService,

View File

@@ -41,6 +41,7 @@ import { ItemPageVersionHistoryGuard } from './item-page-version-history.guard';
import { ItemPageCollectionMapperGuard } from './item-page-collection-mapper.guard'; import { ItemPageCollectionMapperGuard } from './item-page-collection-mapper.guard';
import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component'; import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component';
import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard'; import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard';
import { ItemCurateComponent } from './item-curate/item-curate.component';
/** /**
* Routing module that handles the routing for the Edit Item page administrator functionality * Routing module that handles the routing for the Edit Item page administrator functionality
@@ -82,6 +83,11 @@ import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard';
data: { title: 'item.edit.tabs.metadata.title', showBreadcrumbs: true }, data: { title: 'item.edit.tabs.metadata.title', showBreadcrumbs: true },
canActivate: [ItemPageMetadataGuard] canActivate: [ItemPageMetadataGuard]
}, },
{
path: 'curate',
component: ItemCurateComponent,
data: { title: 'item.edit.tabs.curate.title', showBreadcrumbs: true }
},
{ {
path: 'relationships', path: 'relationships',
component: ItemRelationshipsComponent, component: ItemRelationshipsComponent,

View File

@@ -0,0 +1,7 @@
<div class="container mt-3">
<h3>{{'item.edit.curate.title' |translate:{item: (itemName$ |async)} }}</h3>
<ds-curation-form
*ngIf="dsoRD$ | async as dsoRD"
[dsoHandle]="dsoRD?.payload.handle"
></ds-curation-form>
</div>

View File

@@ -0,0 +1,75 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
import { ItemCurateComponent } from './item-curate.component';
import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { ActivatedRoute } from '@angular/router';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { Item } from '../../../core/shared/item.model';
describe('ItemCurateComponent', () => {
let comp: ItemCurateComponent;
let fixture: ComponentFixture<ItemCurateComponent>;
let debugEl: DebugElement;
let routeStub;
let dsoNameService;
const item = Object.assign(new Item(), {
handle: '123456789/1',
metadata: {'dc.title': ['Item Name']}
});
beforeEach(waitForAsync(() => {
routeStub = {
parent: {
data: observableOf({
dso: createSuccessfulRemoteDataObject(item)
})
}
};
dsoNameService = jasmine.createSpyObj('dsoNameService', {
getName: 'Item Name'
});
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [ItemCurateComponent],
providers: [
{provide: ActivatedRoute, useValue: routeStub},
{provide: DSONameService, useValue: dsoNameService}
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ItemCurateComponent);
comp = fixture.componentInstance;
debugEl = fixture.debugElement;
fixture.detectChanges();
});
describe('init', () => {
it('should initialise the comp', () => {
expect(comp).toBeDefined();
expect(debugEl.nativeElement.innerHTML).toContain('ds-curation-form');
});
it('should contain the item information provided in the route', (done) => {
comp.dsoRD$.subscribe((value) => {
expect(value.payload.handle).toEqual('123456789/1');
done();
});
});
it('should contain the item name', (done) => {
comp.itemName$.subscribe((value) => {
expect(value).toEqual('Item Name');
done();
});
});
});
});

View File

@@ -0,0 +1,39 @@
import { Component, OnInit } from '@angular/core';
import { filter, map, take } from 'rxjs/operators';
import { RemoteData } from '../../../core/data/remote-data';
import { Observable } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { hasValue } from '../../../shared/empty.util';
import { Item } from '../../../core/shared/item.model';
/**
* Component for managing a collection's curation tasks
*/
@Component({
selector: 'ds-item-curate',
templateUrl: './item-curate.component.html',
})
export class ItemCurateComponent implements OnInit {
dsoRD$: Observable<RemoteData<Item>>;
itemName$: Observable<string>;
constructor(
private route: ActivatedRoute,
private dsoNameService: DSONameService,
) {}
ngOnInit(): void {
this.dsoRD$ = this.route.parent.data.pipe(
take(1),
map((data) => data.dso),
);
this.itemName$ = this.dsoRD$.pipe(
filter((rd: RemoteData<Item>) => hasValue(rd)),
map((rd: RemoteData<Item>) => {
return this.dsoNameService.getName(rd.payload);
})
);
}
}

View File

@@ -13,7 +13,7 @@
<div class="file-section row mb-3" *ngFor="let file of originals?.page;"> <div class="file-section row mb-3" *ngFor="let file of originals?.page;">
<div class="col-3"> <div class="col-3">
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-themed-thumbnail>
</div> </div>
<div class="col-7"> <div class="col-7">
<dl class="row"> <dl class="row">
@@ -55,7 +55,7 @@
<div class="file-section row" *ngFor="let file of licenses?.page;"> <div class="file-section row" *ngFor="let file of licenses?.page;">
<div class="col-3"> <div class="col-3">
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-themed-thumbnail>
</div> </div>
<div class="col-7"> <div class="col-7">
<dl class="row"> <dl class="row">

View File

@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { UntypedFormControl, UntypedFormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
@@ -26,7 +26,7 @@ describe('OrcidSyncSettingsComponent test suite', () => {
let scheduler: TestScheduler; let scheduler: TestScheduler;
let researcherProfileService: jasmine.SpyObj<ResearcherProfileDataService>; let researcherProfileService: jasmine.SpyObj<ResearcherProfileDataService>;
let notificationsService; let notificationsService;
let formGroup: FormGroup; let formGroup: UntypedFormGroup;
const mockResearcherProfile: ResearcherProfile = Object.assign(new ResearcherProfile(), { const mockResearcherProfile: ResearcherProfile = Object.assign(new ResearcherProfile(), {
id: 'test-id', id: 'test-id',
@@ -186,12 +186,12 @@ describe('OrcidSyncSettingsComponent test suite', () => {
beforeEach(() => { beforeEach(() => {
scheduler = getTestScheduler(); scheduler = getTestScheduler();
notificationsService = (comp as any).notificationsService; notificationsService = (comp as any).notificationsService;
formGroup = new FormGroup({ formGroup = new UntypedFormGroup({
syncMode: new FormControl('MANUAL'), syncMode: new UntypedFormControl('MANUAL'),
syncFundings: new FormControl('ALL'), syncFundings: new UntypedFormControl('ALL'),
syncPublications: new FormControl('ALL'), syncPublications: new UntypedFormControl('ALL'),
syncProfile_BIOGRAPHICAL: new FormControl(true), syncProfile_BIOGRAPHICAL: new UntypedFormControl(true),
syncProfile_IDENTIFIERS: new FormControl(true), syncProfile_IDENTIFIERS: new UntypedFormControl(true),
}); });
spyOn(comp.settingsUpdated, 'emit'); spyOn(comp.settingsUpdated, 'emit');
}); });

View File

@@ -1,5 +1,5 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Operation } from 'fast-json-patch'; import { Operation } from 'fast-json-patch';
@@ -127,7 +127,7 @@ export class OrcidSyncSettingsComponent implements OnInit {
* *
* @param form The form group * @param form The form group
*/ */
onSubmit(form: FormGroup): void { onSubmit(form: UntypedFormGroup): void {
const operations: Operation[] = []; const operations: Operation[] = [];
this.fillOperationsFor(operations, '/orcid/mode', form.value.syncMode); this.fillOperationsFor(operations, '/orcid/mode', form.value.syncMode);
this.fillOperationsFor(operations, '/orcid/publications', form.value.syncPublications); this.fillOperationsFor(operations, '/orcid/publications', form.value.syncPublications);

View File

@@ -8,10 +8,10 @@
</ds-themed-file-download-link> </ds-themed-file-download-link>
<ds-themed-loading *ngIf="isLoading" message="{{'loading.default' | translate}}" [showMessage]="false"></ds-themed-loading> <ds-themed-loading *ngIf="isLoading" message="{{'loading.default' | translate}}" [showMessage]="false"></ds-themed-loading>
<div *ngIf="!isLastPage" class="mt-1" id="view-more"> <div *ngIf="!isLastPage" class="mt-1" id="view-more">
<a class="bitstream-view-more btn btn-outline-secondary btn-sm" [routerLink]="[]" (click)="getNextPage()">{{'item.page.bitstreams.view-more' | translate}}</a> <button class="bitstream-view-more btn btn-outline-secondary btn-sm" (click)="getNextPage()">{{'item.page.bitstreams.view-more' | translate}}</button>
</div> </div>
<div *ngIf="isLastPage && currentPage != 1" class="mt-1" id="collapse"> <div *ngIf="isLastPage && currentPage != 1" class="mt-1" id="collapse">
<a class="bitstream-collapse btn btn-outline-secondary btn-sm" [routerLink]="[]" (click)="currentPage = undefined; getNextPage();">{{'item.page.bitstreams.collapse' | translate}}</a> <button class="bitstream-collapse btn btn-outline-secondary btn-sm" (click)="currentPage = undefined; getNextPage();">{{'item.page.bitstreams.collapse' | translate}}</button>
</div> </div>
</div> </div>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>

View File

@@ -17,7 +17,7 @@
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ng-container *ngIf="!(mediaViewer.image || mediaViewer.video)"> <ng-container *ngIf="!(mediaViewer.image || mediaViewer.video)">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail [thumbnail]="object?.thumbnail | async"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="object?.thumbnail | async"></ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
</ng-container> </ng-container>
<div *ngIf="mediaViewer.image || mediaViewer.video" class="mb-2"> <div *ngIf="mediaViewer.image || mediaViewer.video" class="mb-2">

View File

@@ -18,7 +18,7 @@
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ng-container *ngIf="!(mediaViewer.image || mediaViewer.video)"> <ng-container *ngIf="!(mediaViewer.image || mediaViewer.video)">
<ds-metadata-field-wrapper [hideIfNoTextContent]="false"> <ds-metadata-field-wrapper [hideIfNoTextContent]="false">
<ds-thumbnail [thumbnail]="object?.thumbnail | async"></ds-thumbnail> <ds-themed-thumbnail [thumbnail]="object?.thumbnail | async"></ds-themed-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
</ng-container> </ng-container>
<div *ngIf="mediaViewer.image || mediaViewer.video" class="mb-2"> <div *ngIf="mediaViewer.image || mediaViewer.video" class="mb-2">

View File

@@ -7,12 +7,12 @@
<ds-themed-loading *ngIf="(i + 1) === objects.length && (i > 0) && (!representations || representations?.length === 0)" message="{{'loading.default' | translate}}"></ds-themed-loading> <ds-themed-loading *ngIf="(i + 1) === objects.length && (i > 0) && (!representations || representations?.length === 0)" message="{{'loading.default' | translate}}"></ds-themed-loading>
<div class="d-inline-block w-100 mt-2" *ngIf="(i + 1) === objects.length && representations?.length > 0"> <div class="d-inline-block w-100 mt-2" *ngIf="(i + 1) === objects.length && representations?.length > 0">
<div *ngIf="(objects.length * incrementBy) < total" class="float-left"> <div *ngIf="(objects.length * incrementBy) < total" class="float-left">
<a [routerLink]="[]" (click)="increase()">{{'item.page.related-items.view-more' | <button class="btn btn-link btn-link-inline" (click)="increase()">{{'item.page.related-items.view-more' |
translate:{ amount: (total - (objects.length * incrementBy) < incrementBy) ? total - (objects.length * incrementBy) : incrementBy } }}</a> translate:{ amount: (total - (objects.length * incrementBy) < incrementBy) ? total - (objects.length * incrementBy) : incrementBy } }}</button>
</div> </div>
<div *ngIf="objects.length > 1" class="float-right"> <div *ngIf="objects.length > 1" class="float-right">
<a [routerLink]="[]" (click)="decrease()">{{'item.page.related-items.view-less' | <button class="btn btn-link btn-link-inline" (click)="decrease()">{{'item.page.related-items.view-less' |
translate:{ amount: representations?.length } }}</a> translate:{ amount: representations?.length } }}</button>
</div> </div>
</div> </div>
</ng-container> </ng-container>

View File

@@ -7,12 +7,12 @@
<ds-themed-loading *ngIf="(i + 1) === objects.length && (itemsRD || i > 0) && !(itemsRD?.hasSucceeded && itemsRD?.payload && itemsRD?.payload?.page?.length > 0)" message="{{'loading.default' | translate}}"></ds-themed-loading> <ds-themed-loading *ngIf="(i + 1) === objects.length && (itemsRD || i > 0) && !(itemsRD?.hasSucceeded && itemsRD?.payload && itemsRD?.payload?.page?.length > 0)" message="{{'loading.default' | translate}}"></ds-themed-loading>
<div class="d-inline-block w-100 mt-2" *ngIf="(i + 1) === objects.length && itemsRD?.payload?.page?.length > 0"> <div class="d-inline-block w-100 mt-2" *ngIf="(i + 1) === objects.length && itemsRD?.payload?.page?.length > 0">
<div *ngIf="itemsRD?.payload?.totalPages > objects.length" class="float-left" id="view-more"> <div *ngIf="itemsRD?.payload?.totalPages > objects.length" class="float-left" id="view-more">
<a [routerLink]="[]" (click)="increase()">{{'item.page.related-items.view-more' | <button class="btn btn-link btn-link-inline" (click)="increase()">{{'item.page.related-items.view-more' |
translate:{ amount: (itemsRD?.payload?.totalElements - (incrementBy * objects.length) < incrementBy) ? itemsRD?.payload?.totalElements - (incrementBy * objects.length) : incrementBy } }}</a> translate:{ amount: (itemsRD?.payload?.totalElements - (incrementBy * objects.length) < incrementBy) ? itemsRD?.payload?.totalElements - (incrementBy * objects.length) : incrementBy } }}</button>
</div> </div>
<div *ngIf="objects.length > 1" class="float-right" id="view-less"> <div *ngIf="objects.length > 1" class="float-right" id="view-less">
<a [routerLink]="[]" (click)="decrease()">{{'item.page.related-items.view-less' | <button class="btn btn-link btn-link-inline" (click)="decrease()">{{'item.page.related-items.view-less' |
translate:{ amount: itemsRD?.payload?.page?.length } }}</a> translate:{ amount: itemsRD?.payload?.page?.length } }}</button>
</div> </div>
</div> </div>
</ng-container> </ng-container>

View File

@@ -18,7 +18,7 @@ import { PaginationServiceStub } from '../../shared/testing/pagination-service.s
import { AuthService } from '../../core/auth/auth.service'; import { AuthService } from '../../core/auth/auth.service';
import { VersionDataService } from '../../core/data/version-data.service'; import { VersionDataService } from '../../core/data/version-data.service';
import { ItemDataService } from '../../core/data/item-data.service'; import { ItemDataService } from '../../core/data/item-data.service';
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { UntypedFormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub'; import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
@@ -140,7 +140,7 @@ describe('ItemVersionsComponent', () => {
imports: [TranslateModule.forRoot(), CommonModule, FormsModule, ReactiveFormsModule, BrowserModule, ItemSharedModule], imports: [TranslateModule.forRoot(), CommonModule, FormsModule, ReactiveFormsModule, BrowserModule, ItemSharedModule],
providers: [ providers: [
{provide: PaginationService, useValue: new PaginationServiceStub()}, {provide: PaginationService, useValue: new PaginationServiceStub()},
{provide: FormBuilder, useValue: new FormBuilder()}, {provide: UntypedFormBuilder, useValue: new UntypedFormBuilder()},
{provide: NotificationsService, useValue: new NotificationsServiceStub()}, {provide: NotificationsService, useValue: new NotificationsServiceStub()},
{provide: AuthService, useValue: authenticationServiceSpy}, {provide: AuthService, useValue: authenticationServiceSpy},
{provide: AuthorizationDataService, useValue: authorizationServiceSpy}, {provide: AuthorizationDataService, useValue: authorizationServiceSpy},

View File

@@ -32,7 +32,7 @@ import {
getItemPageRoute, getItemPageRoute,
getItemVersionRoute getItemVersionRoute
} from '../item-page-routing-paths'; } from '../item-page-routing-paths';
import { FormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ItemVersionsSummaryModalComponent } from './item-versions-summary-modal/item-versions-summary-modal.component'; import { ItemVersionsSummaryModalComponent } from './item-versions-summary-modal/item-versions-summary-modal.component';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
@@ -171,7 +171,7 @@ export class ItemVersionsComponent implements OnInit {
private versionService: VersionDataService, private versionService: VersionDataService,
private itemService: ItemDataService, private itemService: ItemDataService,
private paginationService: PaginationService, private paginationService: PaginationService,
private formBuilder: FormBuilder, private formBuilder: UntypedFormBuilder,
private modalService: NgbModal, private modalService: NgbModal,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private translateService: TranslateService, private translateService: TranslateService,

View File

@@ -23,7 +23,6 @@ import { ItemDetailPreviewComponent } from '../shared/object-detail/my-dspace-re
import { ItemDetailPreviewFieldComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component'; import { ItemDetailPreviewFieldComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
import { ItemListPreviewComponent } from '../shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component'; import { ItemListPreviewComponent } from '../shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component';
import { ThemedItemListPreviewComponent } from '../shared/object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component'; import { ThemedItemListPreviewComponent } from '../shared/object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component';
import { MyDSpaceItemStatusComponent } from '../shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component';
import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module'; import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module';
import { MyDSpaceActionsModule } from '../shared/mydspace-actions/mydspace-actions.module'; import { MyDSpaceActionsModule } from '../shared/mydspace-actions/mydspace-actions.module';
import { ClaimedDeclinedTaskSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-task-search-result/claimed-declined-task-search-result-list-element.component'; import { ClaimedDeclinedTaskSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-task-search-result/claimed-declined-task-search-result-list-element.component';
@@ -52,7 +51,6 @@ const DECLARATIONS = [
ItemDetailPreviewFieldComponent, ItemDetailPreviewFieldComponent,
ItemListPreviewComponent, ItemListPreviewComponent,
ThemedItemListPreviewComponent, ThemedItemListPreviewComponent,
MyDSpaceItemStatusComponent,
]; ];
@NgModule({ @NgModule({

View File

@@ -1,11 +1,11 @@
<div class="form-group" *ngIf="script"> <div class="form-group" *ngIf="script?.parameters?.length" data-testID="parameters-select-container">
<label>{{'process.new.select-parameters' | translate}}</label> <label>{{'process.new.select-parameters' | translate}}</label>
<ds-parameter-select <ds-parameter-select
*ngFor="let value of parameterValues; let i = index; let last = last" *ngFor="let value of parameterValues; let i = index; let last = last"
[parameters]="script.parameters" [parameters]="script.parameters"
[parameterValue]="value" [parameterValue]="value"
[removable]="!last" [removable]="!last"
[index]="i" [index]="i"
(removeParameter)="removeParameter(i)" (removeParameter)="removeParameter(i)"
(changeParameter)="updateParameter($event, i)"></ds-parameter-select> (changeParameter)="updateParameter($event, i)"></ds-parameter-select>
</div> </div>

View File

@@ -14,14 +14,14 @@ import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock
describe('ProcessParametersComponent', () => { describe('ProcessParametersComponent', () => {
let component: ProcessParametersComponent; let component: ProcessParametersComponent;
let fixture: ComponentFixture<ProcessParametersComponent>; let fixture: ComponentFixture<ProcessParametersComponent>;
let parameterValues; let mockParameterValues: ProcessParameter[];
let script; let mockScript: Script;
function init() { function initParametersAndScriptMockValues() {
const param1 = new ScriptParameter(); const param1 = new ScriptParameter();
const param2 = new ScriptParameter(); const param2 = new ScriptParameter();
script = Object.assign(new Script(), { parameters: [param1, param2] }); mockScript = Object.assign(new Script(), { parameters: [param1, param2] });
parameterValues = [ mockParameterValues = [
Object.assign(new ProcessParameter(), { name: '-a', value: 'bla' }), Object.assign(new ProcessParameter(), { name: '-a', value: 'bla' }),
Object.assign(new ProcessParameter(), { name: '-b', value: '123' }), Object.assign(new ProcessParameter(), { name: '-b', value: '123' }),
Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }), Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }),
@@ -29,7 +29,6 @@ describe('ProcessParametersComponent', () => {
} }
beforeEach(waitForAsync(() => { beforeEach(waitForAsync(() => {
init();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
FormsModule, FormsModule,
@@ -48,17 +47,34 @@ describe('ProcessParametersComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ProcessParametersComponent); fixture = TestBed.createComponent(ProcessParametersComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.script = script;
component.parameterValues = parameterValues;
fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should render a ParameterSelectComponent for each parameter value of the component', () => { describe('when parameter values and script are initialized', () => {
const selectComponents = fixture.debugElement.queryAll(By.directive(ParameterSelectComponent));
expect(selectComponents.length).toBe(parameterValues.length); beforeEach(() => {
initParametersAndScriptMockValues();
component.parameterValues = mockParameterValues;
component.script = mockScript;
fixture.detectChanges();
});
it(`should render a ${ParameterSelectComponent.name} for each parameter value`, () => {
const selectComponents = fixture.debugElement.queryAll(By.directive(ParameterSelectComponent));
expect(selectComponents.length).toBe(mockParameterValues.length);
});
it('should not render a selector box if the parameter array is empty',() => {
fixture.componentInstance.script.parameters = [];
fixture.detectChanges();
const formGroupComponent = fixture.debugElement.query(By.css('[data-testID=parameters-select-container]'));
expect(formGroupComponent).toBeFalsy();
});
}); });
}); });

View File

@@ -0,0 +1,48 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module';
import { NewProcessComponent } from './new/new-process.component';
import { ScriptsSelectComponent } from './form/scripts-select/scripts-select.component';
import { ScriptHelpComponent } from './form/script-help/script-help.component';
import { ParameterSelectComponent } from './form/process-parameters/parameter-select/parameter-select.component';
import { ProcessParametersComponent } from './form/process-parameters/process-parameters.component';
import { StringValueInputComponent } from './form/process-parameters/parameter-value-input/string-value-input/string-value-input.component';
import { ParameterValueInputComponent } from './form/process-parameters/parameter-value-input/parameter-value-input.component';
import { FileValueInputComponent } from './form/process-parameters/parameter-value-input/file-value-input/file-value-input.component';
import { BooleanValueInputComponent } from './form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component';
import { DateValueInputComponent } from './form/process-parameters/parameter-value-input/date-value-input/date-value-input.component';
import { ProcessOverviewComponent } from './overview/process-overview.component';
import { ProcessDetailComponent } from './detail/process-detail.component';
import { ProcessDetailFieldComponent } from './detail/process-detail-field/process-detail-field.component';
import { ProcessBreadcrumbsService } from './process-breadcrumbs.service';
import { ProcessBreadcrumbResolver } from './process-breadcrumb.resolver';
import { ProcessFormComponent } from './form/process-form.component';
@NgModule({
imports: [
SharedModule,
],
declarations: [
NewProcessComponent,
ScriptsSelectComponent,
ScriptHelpComponent,
ParameterSelectComponent,
ProcessParametersComponent,
StringValueInputComponent,
ParameterValueInputComponent,
FileValueInputComponent,
BooleanValueInputComponent,
DateValueInputComponent,
ProcessOverviewComponent,
ProcessDetailComponent,
ProcessDetailFieldComponent,
ProcessFormComponent
],
providers: [
ProcessBreadcrumbResolver,
ProcessBreadcrumbsService
]
})
export class ProcessPageSharedModule {
}

View File

@@ -1,47 +1,17 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module'; import { SharedModule } from '../shared/shared.module';
import { ProcessPageRoutingModule } from './process-page-routing.module'; import { ProcessPageRoutingModule } from './process-page-routing.module';
import { NewProcessComponent } from './new/new-process.component'; import { ProcessPageSharedModule } from './process-page-shared.module';
import { ScriptsSelectComponent } from './form/scripts-select/scripts-select.component';
import { ScriptHelpComponent } from './form/script-help/script-help.component';
import { ParameterSelectComponent } from './form/process-parameters/parameter-select/parameter-select.component';
import { ProcessParametersComponent } from './form/process-parameters/process-parameters.component';
import { StringValueInputComponent } from './form/process-parameters/parameter-value-input/string-value-input/string-value-input.component';
import { ParameterValueInputComponent } from './form/process-parameters/parameter-value-input/parameter-value-input.component';
import { FileValueInputComponent } from './form/process-parameters/parameter-value-input/file-value-input/file-value-input.component';
import { BooleanValueInputComponent } from './form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component';
import { DateValueInputComponent } from './form/process-parameters/parameter-value-input/date-value-input/date-value-input.component';
import { ProcessOverviewComponent } from './overview/process-overview.component';
import { ProcessDetailComponent } from './detail/process-detail.component';
import { ProcessDetailFieldComponent } from './detail/process-detail-field/process-detail-field.component';
import { ProcessBreadcrumbsService } from './process-breadcrumbs.service';
import { ProcessBreadcrumbResolver } from './process-breadcrumb.resolver';
import { ProcessFormComponent } from './form/process-form.component';
@NgModule({ @NgModule({
imports: [ imports: [
ProcessPageRoutingModule, ProcessPageRoutingModule,
SharedModule, SharedModule,
ProcessPageSharedModule,
], ],
declarations: [ declarations: [
NewProcessComponent,
ScriptsSelectComponent,
ScriptHelpComponent,
ParameterSelectComponent,
ProcessParametersComponent,
StringValueInputComponent,
ParameterValueInputComponent,
FileValueInputComponent,
BooleanValueInputComponent,
DateValueInputComponent,
ProcessOverviewComponent,
ProcessDetailComponent,
ProcessDetailFieldComponent,
ProcessFormComponent
], ],
providers: [ providers: [
ProcessBreadcrumbResolver,
ProcessBreadcrumbsService
] ]
}) })

View File

@@ -5,7 +5,7 @@ import {
DynamicInputModel, DynamicInputModel,
DynamicSelectModel DynamicSelectModel
} from '@ng-dynamic-forms/core'; } from '@ng-dynamic-forms/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { EPerson } from '../../core/eperson/models/eperson.model'; import { EPerson } from '../../core/eperson/models/eperson.model';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { hasValue, isNotEmpty } from '../../shared/empty.util';
@@ -80,7 +80,7 @@ export class ProfilePageMetadataFormComponent implements OnInit {
/** /**
* The form group of this form * The form group of this form
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* Prefix for the form's label messages of this component * Prefix for the form's label messages of this component

View File

@@ -1,7 +1,7 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { FormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { hasValue, isEmpty } from '../../shared/empty.util'; import { hasValue, isEmpty } from '../../shared/empty.util';
import { EPersonDataService } from '../../core/eperson/eperson-data.service'; import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
@@ -51,7 +51,7 @@ export class ProfilePageSecurityFormComponent implements OnInit {
/** /**
* The form group of this form * The form group of this form
*/ */
formGroup: FormGroup; formGroup: UntypedFormGroup;
/** /**
* Indicates whether the "checkPasswordEmpty" needs to be added or not * Indicates whether the "checkPasswordEmpty" needs to be added or not
@@ -127,7 +127,7 @@ export class ProfilePageSecurityFormComponent implements OnInit {
* Check if both password fields are filled in and equal * Check if both password fields are filled in and equal
* @param group The FormGroup to validate * @param group The FormGroup to validate
*/ */
checkPasswordsEqual(group: FormGroup) { checkPasswordsEqual(group: UntypedFormGroup) {
const pass = group.get('password').value; const pass = group.get('password').value;
const repeatPass = group.get('passwordrepeat').value; const repeatPass = group.get('passwordrepeat').value;
@@ -138,7 +138,7 @@ export class ProfilePageSecurityFormComponent implements OnInit {
* Checks if the password is empty * Checks if the password is empty
* @param group The FormGroup to validate * @param group The FormGroup to validate
*/ */
checkPasswordEmpty(group: FormGroup) { checkPasswordEmpty(group: UntypedFormGroup) {
const pass = group.get('password').value; const pass = group.get('password').value;
return isEmpty(pass) ? { emptyPassword: true } : null; return isEmpty(pass) ? { emptyPassword: true } : null;
} }

View File

@@ -4,7 +4,7 @@ import { RestResponse } from '../core/cache/response.models';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { UntypedFormBuilder, ReactiveFormsModule } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { NotificationsService } from '../shared/notifications/notifications.service'; import { NotificationsService } from '../shared/notifications/notifications.service';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@@ -67,7 +67,7 @@ describe('RegisterEmailFormComponent', () => {
{provide: Router, useValue: router}, {provide: Router, useValue: router},
{provide: EpersonRegistrationService, useValue: epersonRegistrationService}, {provide: EpersonRegistrationService, useValue: epersonRegistrationService},
{provide: ConfigurationDataService, useValue: configurationDataService}, {provide: ConfigurationDataService, useValue: configurationDataService},
{provide: FormBuilder, useValue: new FormBuilder()}, {provide: UntypedFormBuilder, useValue: new UntypedFormBuilder()},
{provide: NotificationsService, useValue: notificationsService}, {provide: NotificationsService, useValue: notificationsService},
{provide: CookieService, useValue: new CookieServiceMock()}, {provide: CookieService, useValue: new CookieServiceMock()},
{provide: GoogleRecaptchaService, useValue: googleRecaptchaService}, {provide: GoogleRecaptchaService, useValue: googleRecaptchaService},

Some files were not shown because too many files have changed in this diff Show More