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
# Comment this out to use the latest release
#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:
# Create a matrix of Node versions to test against (in parallel)
matrix:

View File

@@ -274,9 +274,18 @@
}
}
},
"defaultProject": "dspace-angular",
"cli": {
"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
label: Gàidhlig
active: true
- code: it
label: Italiano
active: true
- code: lv
label: Latviešu
active: true
@@ -214,6 +217,9 @@ languages:
- code: tr
label: Türkçe
active: true
- code: vi
label: Tiếng Việt
active: true
- code: kk
label: Қазақ
active: true

View File

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

View File

@@ -2,7 +2,7 @@ import { Observable, of as observableOf } from 'rxjs';
import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
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 { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
@@ -116,9 +116,9 @@ describe('EPersonFormComponent', () => {
const controlModel = model;
const controlState = { value: controlModel.value, disabled: controlModel.disabled };
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) {
return {

View File

@@ -1,5 +1,5 @@
import { ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import {
DynamicCheckboxModel,
DynamicFormControlModel,
@@ -108,7 +108,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
/**
* A FormGroup that combines all inputs
*/
formGroup: FormGroup;
formGroup: UntypedFormGroup;
/**
* 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 { NO_ERRORS_SCHEMA } from '@angular/core';
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 { ActivatedRoute, Router } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@@ -130,9 +130,9 @@ describe('GroupFormComponent', () => {
const controlModel = model;
const controlState = { value: controlModel.value, disabled: controlModel.disabled };
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) {
return {

View File

@@ -1,5 +1,5 @@
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 { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
@@ -95,7 +95,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
/**
* A FormGroup that combines all inputs
*/
formGroup: FormGroup;
formGroup: UntypedFormGroup;
/**
* 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 { FormBuilder } from '@angular/forms';
import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import {
@@ -141,7 +141,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
public ePersonDataService: EPersonDataService,
protected translateService: TranslateService,
protected notificationsService: NotificationsService,
protected formBuilder: FormBuilder,
protected formBuilder: UntypedFormBuilder,
protected paginationService: PaginationService,
private router: Router
) {

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,7 @@ import {
DynamicFormLayout,
DynamicInputModel
} from '@ng-dynamic-forms/core';
import { FormGroup } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { take } from 'rxjs/operators';
@@ -82,7 +82,7 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
/**
* A FormGroup that combines all inputs
*/
formGroup: FormGroup;
formGroup: UntypedFormGroup;
/**
* 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 { ThemeService } from '../../../../../shared/theme-support/theme.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 { AuthServiceStub } from '../../../../../shared/testing/auth-service.stub';
import { FileService } from '../../../../../core/shared/file.service';

View File

@@ -2,6 +2,5 @@
[viewMode]="viewModes.ListElement"
[index]="index"
[linkType]="linkType"
[listID]="listID"
[hideBadges]="true"></ds-listable-object-component-loader>
[listID]="listID"></ds-listable-object-component-loader>
<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 { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model';
import {
getWorkflowItemDeleteRoute,
getWorkspaceItemDeleteRoute,
} from '../../../../../workflowitems-edit-page/workflowitems-edit-page-routing-paths';
import { Item } from '../../../../../core/shared/item.model';
import { RemoteData } from '../../../../../core/data/remote-data';
@@ -83,7 +83,7 @@ describe('WorkspaceItemAdminWorkflowActionsComponent', () => {
it('should render a delete button with the correct link', () => {
const button = fixture.debugElement.query(By.css('a.delete-link'));
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', () => {

View File

@@ -11,7 +11,7 @@ import {
SupervisionOrderGroupSelectorComponent
} from './supervision-order-group-selector/supervision-order-group-selector.component';
import {
getWorkflowItemDeleteRoute
getWorkspaceItemDeleteRoute
} 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 { 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 {
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,
loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule),
canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard]
canActivate: [EndUserAgreementCurrentUserGuard]
},
{
path: FORBIDDEN_PATH,

View File

@@ -2,7 +2,7 @@
<div class="container" *ngVar="(bitstreamFormatsRD$ | async) as formatsRD">
<div class="row" *ngIf="bitstreamRD?.hasSucceeded && formatsRD?.hasSucceeded">
<div class="col-md-2">
<ds-thumbnail [thumbnail]="bitstreamRD?.payload"></ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="bitstreamRD?.payload"></ds-themed-thumbnail>
</div>
<div class="col-md-10">
<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 { BitstreamFormatSupportLevel } from '../../core/shared/bitstream-format-support-level';
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 { VarDirective } from '../../shared/utils/var.directive';
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
@@ -84,9 +84,9 @@ describe('EditBitstreamPageComponent', () => {
const controls = {};
if (hasValue(fModel)) {
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;
}

View File

@@ -23,7 +23,7 @@ import {
DynamicInputModel,
DynamicSelectModel
} from '@ng-dynamic-forms/core';
import { FormGroup } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
import cloneDeep from 'lodash/cloneDeep';
@@ -359,7 +359,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
/**
* The form group of this form
*/
formGroup: FormGroup;
formGroup: UntypedFormGroup;
/**
* 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 { DynamicFormControlModel, DynamicFormService } from '@ng-dynamic-forms/core';
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 { By } from '@angular/platform-browser';
import { Collection } from '../../../core/shared/collection.model';
@@ -98,9 +98,9 @@ describe('CollectionSourceComponent', () => {
const controls = {};
if (hasValue(fModel)) {
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;
}

View File

@@ -14,7 +14,7 @@ import { Location } from '@angular/common';
import { TranslateService } from '@ngx-translate/core';
import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.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 { ContentSource, ContentSourceHarvestType } from '../../../core/shared/content-source.model';
import { Observable, Subscription } from 'rxjs';
@@ -202,7 +202,7 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
/**
* The form group of this form
*/
formGroup: FormGroup;
formGroup: UntypedFormGroup;
/**
* Subscription to update the current form

View File

@@ -8,10 +8,10 @@
<span class="fa fa-chevron-right invisible" aria-hidden="true"></span>
</button>
<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">
<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>
</div>
</div>

View File

@@ -16,6 +16,7 @@ import { of as observableOf } from 'rxjs';
import { By } from '@angular/platform-browser';
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
import { FlatNode } from '../flat-node.model';
import { RouterLinkWithHref } from '@angular/router';
describe('CommunityListComponent', () => {
let component: CommunityListComponent;
@@ -193,7 +194,8 @@ describe('CommunityListComponent', () => {
},
}),
CdkTreeModule,
RouterTestingModule],
RouterTestingModule,
RouterLinkWithHref],
declarations: [CommunityListComponent],
providers: [CommunityListComponent,
{ provide: CommunityListService, useValue: communityListServiceStub },],
@@ -230,9 +232,14 @@ describe('CommunityListComponent', () => {
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', () => {
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', {
preventDefault: () => {/**/
}
@@ -240,6 +247,7 @@ describe('CommunityListComponent', () => {
tick();
fixture.detectChanges();
}));
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 childlessNodesFound = fixture.debugElement.queryAll(By.css('.childless-node a'));

View File

@@ -1,4 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
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);
constructor(private cds: CollectionDataService,
private paginationService: PaginationService,
) {}
constructor(
protected cds: CollectionDataService,
protected paginationService: PaginationService,
protected route: ActivatedRoute,
) {
}
ngOnInit(): void {
this.config = new PaginationComponentOptions();
this.config.id = this.pageId;
if (hasValue(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.sortConfig = new SortOptions('dc.title', SortDirection.ASC);
this.config.currentPage = this.route.snapshot.queryParams[this.pageId + '.page'] ?? 1;
this.sortConfig = new SortOptions('dc.title', SortDirection[this.route.snapshot.queryParams[this.pageId + '.sd']] ?? SortDirection.ASC);
this.initPage();
}

View File

@@ -1,4 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
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 { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { CommunityDataService } from '../../core/data/community-data.service';
import { takeUntilCompletedRemoteData } from '../../core/shared/operators';
import { switchMap } from 'rxjs/operators';
import { PaginationService } from '../../core/pagination/pagination.service';
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);
constructor(private cds: CommunityDataService,
private paginationService: PaginationService
constructor(
protected cds: CommunityDataService,
protected paginationService: PaginationService,
protected route: ActivatedRoute,
) {
}
@@ -62,9 +64,11 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy
this.config.id = this.pageId;
if (hasValue(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.sortConfig = new SortOptions('dc.title', SortDirection.ASC);
this.config.currentPage = this.route.snapshot.queryParams[this.pageId + '.page'] ?? 1;
this.sortConfig = new SortOptions('dc.title', SortDirection[this.route.snapshot.queryParams[this.pageId + '.sd']] ?? SortDirection.ASC);
this.initPage();
}
@@ -86,15 +90,6 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy
).subscribe((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 {

View File

@@ -60,7 +60,7 @@ export class LinkService {
const provider = this.getDataServiceFor(matchingLinkDef.resourceType);
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({
@@ -79,12 +79,12 @@ export class LinkService {
return service.findByHref(href, linkToFollow.useCachedVersionIfAvailable, linkToFollow.reRequestOnStale, ...linkToFollow.linksToFollow);
}
} 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;
}
}
} 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;

View File

@@ -73,7 +73,7 @@ export class RemoteDataBuildService {
if (getResourceTypeValueFor((obj as any).type) === PAGINATED_LIST.value) {
return this.buildPaginatedList<T>(obj, ...linksToFollow);
} else if (isNotEmpty(linksToFollow)) {
return [this.linkService.resolveLinks(obj, ...linksToFollow)];
return [this.linkService.resolveLinks(obj as any, ...linksToFollow)];
}
}
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 { AdvancedWorkflowInfo } from './tasks/models/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 { LinkHeadService } from './services/link-head.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 { HALEndpointService } from '../shared/hal-endpoint.service';
import { RequestService } from './request.service';
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type';
import { AccessStatusObject } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model';
import { ACCESS_STATUS } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.resource-type';
import { Observable } from 'rxjs';
import { RemoteData } from './remote-data';
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', () => {
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
* 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 { GetRequest } from './request.models';
import { testSearchDataImplementation } from './base/search-data.spec';
import { take } from 'rxjs/operators';
describe('ExternalSourceService', () => {
let service: ExternalSourceDataService;
@@ -64,19 +65,42 @@ describe('ExternalSourceService', () => {
});
describe('getExternalSourceEntries', () => {
let result;
beforeEach(() => {
result = service.getExternalSourceEntries('test');
describe('when no error response is cached', () => {
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', () => {
expect(requestService.send).toHaveBeenCalledWith(jasmine.any(GetRequest), true);
});
describe('when an error response is cached', () => {
let result;
beforeEach(() => {
spyOn(service, 'hasCachedErrorResponse').and.returnValue(observableOf(true));
result = service.getExternalSourceEntries('test');
});
it('should return the entries', () => {
result.subscribe((resultRD) => {
expect(resultRD.payload.page).toBe(entries);
it('should send a GetRequest', () => {
result.pipe(take(1)).subscribe();
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
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')
});
const langList = ['en', 'it', 'de'];
const langList = ['en', 'xx', 'de'];
beforeEach(waitForAsync(() => {
return TestBed.configureTestingModule({
@@ -82,8 +82,8 @@ describe('LocaleService test suite', () => {
});
it('should return language from browser setting', () => {
spyOn(translateService, 'getBrowserLang').and.returnValue('it');
expect(service.getCurrentLanguageCode()).toBe('it');
spyOn(translateService, 'getBrowserLang').and.returnValue('xx');
expect(service.getCurrentLanguageCode()).toBe('xx');
});
it('should return default language from config', () => {
@@ -114,9 +114,9 @@ describe('LocaleService test suite', () => {
});
it('should set the given language', () => {
service.setCurrentLanguageCode('it');
expect(translateService.use).toHaveBeenCalledWith('it');
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('it');
service.setCurrentLanguageCode('xx');
expect(translateService.use).toHaveBeenCalledWith('xx');
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('xx');
});
it('should set the current language', () => {
@@ -135,7 +135,7 @@ describe('LocaleService test suite', () => {
describe('', () => {
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);
service.setQuality(langList, LANG_ORIGIN.BROWSER, false);
expect(service.setQuality).toHaveBeenCalledWith(langList, LANG_ORIGIN.BROWSER, false);

View File

@@ -3,17 +3,38 @@
*/
export enum Context {
/** Default context */
Any = 'undefined',
/** General item page context */
ItemPage = 'itemPage',
/** General search page context */
Search = 'search',
Workflow = 'workflow',
Workspace = 'workspace',
SupervisedItems = 'supervisedWorkspace',
/** Administrative menu context */
AdminMenu = 'adminMenu',
EntitySearchModalWithNameVariants = 'EntitySearchModalWithNameVariants',
EntitySearchModal = 'EntitySearchModal',
/** Administrative search page context */
AdminSearch = 'adminSearch',
AdminWorkflowSearch = 'adminWorkflowSearch',
SideBarSearchModal = 'sideBarSearchModal',
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 { BITSTREAM } from './bitstream.resource-type';
import { Bitstream } from './bitstream.model';
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type';
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
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-collection/shared/badges/access-status-badge/access-status.model';
import { HandleObject } from './handle-object.model';
import { IDENTIFIERS } from '../../shared/object-list/identifier-data/identifier-data.resource-type';
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 { FormControl, FormGroup } from '@angular/forms';
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { getFirstCompletedRemoteData } from '../core/shared/operators';
import { find, map } from 'rxjs/operators';
import { NotificationsService } from '../shared/notifications/notifications.service';
@@ -28,7 +28,7 @@ export class CurationFormComponent implements OnInit {
config: Observable<RemoteData<ConfigurationProperty>>;
tasks: string[];
form: FormGroup;
form: UntypedFormGroup;
@Input()
dsoHandle: string;
@@ -40,14 +40,15 @@ export class CurationFormComponent implements OnInit {
private notificationsService: NotificationsService,
private translateService: TranslateService,
private handleService: HandleService,
private router: Router
private router: Router,
private cdr: ChangeDetectorRef
) {
}
ngOnInit(): void {
this.form = new FormGroup({
task: new FormControl(''),
handle: new FormControl('')
this.form = new UntypedFormGroup({
task: new UntypedFormControl(''),
handle: new UntypedFormControl('')
});
this.config = this.configurationDataService.findByPropertyName(CURATION_CFG);
@@ -59,6 +60,7 @@ export class CurationFormComponent implements OnInit {
.filter((value) => isNotEmpty(value) && value.includes('='))
.map((value) => value.split('=')[1].trim());
this.form.get('task').patchValue(this.tasks[0]);
this.cdr.detectChanges();
});
}

View File

@@ -7,7 +7,7 @@
[dsDebounce]="300" (onDebounce)="confirm.emit(false)"></textarea>
<div class="d-flex" *ngIf="mdRepresentation">
<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 class="ds-flex-cell ds-lang-cell" role="cell">

View File

@@ -68,7 +68,7 @@ describe('DsoEditMetadataValueComponent', () => {
});
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', () => {
@@ -134,7 +134,7 @@ describe('DsoEditMetadataValueComponent', () => {
});
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);

View File

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

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</span>
<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">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</span>
<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">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</span>
<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">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part>

View File

@@ -12,7 +12,7 @@
</span>
</div>
<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">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer"

View File

@@ -12,7 +12,7 @@
</span>
</div>
<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">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer"

View File

@@ -11,7 +11,7 @@
</span>
</div>
<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">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out"

View File

@@ -7,7 +7,7 @@
<div class="row">
<div class="col-xs-12 col-md-4">
<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-generic-item-page-field [item]="object"
[fields]="['publicationvolume.volumeNumber']"

View File

@@ -7,7 +7,7 @@
<div class="row">
<div class="col-xs-12 col-md-4">
<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-generic-item-page-field [item]="object"
[fields]="['publicationvolume.volumeNumber']"

View File

@@ -7,7 +7,7 @@
<div class="row">
<div class="col-xs-12 col-md-4">
<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-generic-item-page-field class="item-page-fields" [item]="object"
[fields]="['creativeworkseries.issn']"

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</span>
<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">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</span>
<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">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part>

View File

@@ -8,18 +8,18 @@
rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</span>
<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">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part>

View File

@@ -18,7 +18,7 @@
</span>
</div>
<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">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer"

View File

@@ -18,7 +18,7 @@
</span>
</div>
<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">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer"

View File

@@ -19,7 +19,7 @@
</div>
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
<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'"
rel="noopener noreferrer"
[routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out"

View File

@@ -7,12 +7,12 @@
<div class="row">
<div class="col-xs-12 col-md-4">
<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'"
[alt]="'thumbnail.orgunit.alt'"
[placeholder]="'thumbnail.orgunit.placeholder'"
>
</ds-thumbnail>
</ds-themed-thumbnail>
</ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="object"
[fields]="['organization.foundingDate']"

View File

@@ -7,11 +7,11 @@
<div class="row">
<div class="col-xs-12 col-md-4">
<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'"
[alt]="'thumbnail.person.alt'"
[placeholder]="'thumbnail.person.placeholder'">
</ds-thumbnail>
</ds-themed-thumbnail>
</ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="object"
[fields]="['person.email']"

View File

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

View File

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

View File

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

View File

@@ -1,15 +1,15 @@
<ng-template #descTemplate>
<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">
<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>
</span>
</span>
</ng-template>
<ds-truncatable [id]="metadataRepresentation.id">
<ds-truncatable [id]="mdRepresentation.id">
<a [routerLink]="[itemPageRoute]"
[innerHTML]="metadataRepresentation.getValue()"
[ngbTooltip]="metadataRepresentation.allMetadata(['person.jobTitle']).length > 0 ? descTemplate : null"></a>
[innerHTML]="mdRepresentation.getValue()"
[ngbTooltip]="mdRepresentation.allMetadata(['person.jobTitle']).length > 0 ? descTemplate : null"></a>
</ds-truncatable>

View File

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

View File

@@ -1,6 +1,6 @@
<div class="d-flex">
<!-- <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 class="flex-grow-1">
<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 { RouterTestingModule } from '@angular/router/testing';
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 { Store } from '@ngrx/store';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
@@ -60,7 +60,7 @@ describe('ForgotPasswordFormComponent', () => {
{provide: ActivatedRoute, useValue: route},
{provide: Store, useValue: store},
{provide: EPersonDataService, useValue: ePersonDataService},
{provide: FormBuilder, useValue: new FormBuilder()},
{provide: UntypedFormBuilder, useValue: new UntypedFormBuilder()},
{provide: NotificationsService, useValue: notificationsService},
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,6 @@
<ds-view-tracker [object]="site"></ds-view-tracker>
</ng-container>
<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>
</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 { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-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 = [
HomePageComponent,
ThemedHomePageComponent,
TopLevelCommunityListComponent,
ThemedTopLevelCommunityListComponent,
ThemedHomeNewsComponent,
HomeNewsComponent,
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 { RouteService } from '../../../core/services/route.service';
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 { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { AuthService } from '../../../core/auth/auth.service';
@@ -41,7 +41,7 @@ describe('FeedbackFormComponent', () => {
declarations: [FeedbackFormComponent],
providers: [
{ provide: RouteService, useValue: routeServiceStub },
{ provide: FormBuilder, useValue: new FormBuilder() },
{ provide: UntypedFormBuilder, useValue: new UntypedFormBuilder() },
{ provide: NotificationsService, useValue: notificationService },
{ provide: FeedbackDataService, useValue: feedbackDataServiceStub },
{ 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 { Component, Inject, OnInit } from '@angular/core';
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 { TranslateService } from '@ngx-translate/core';
import { AuthService } from '../../../core/auth/auth.service';
@@ -37,7 +37,7 @@ export class FeedbackFormComponent implements OnInit {
constructor(
@Inject(NativeWindowService) protected _window: NativeWindowRef,
public routeService: RouteService,
private fb: FormBuilder,
private fb: UntypedFormBuilder,
protected notificationsService: NotificationsService,
protected translate: TranslateService,
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 { TranslateService } from '@ngx-translate/core';
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 { ItemRequest } from '../../../core/shared/item-request.model';
import { Item } from '../../../core/shared/item.model';
@@ -34,7 +34,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy {
canDownload$: Observable<boolean>;
private subs: Subscription[] = [];
requestCopyForm: FormGroup;
requestCopyForm: UntypedFormGroup;
item: Item;
itemName: string;
@@ -49,7 +49,7 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy {
protected router: Router,
private authorizationService: AuthorizationDataService,
private auth: AuthService,
private formBuilder: FormBuilder,
private formBuilder: UntypedFormBuilder,
private itemRequestDataService: ItemRequestDataService,
private notificationsService: NotificationsService,
private dsoNameService: DSONameService,
@@ -59,15 +59,15 @@ export class BitstreamRequestACopyPageComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.requestCopyForm = this.formBuilder.group({
name: new FormControl('', {
name: new UntypedFormControl('', {
validators: [Validators.required],
}),
email: new FormControl('', {
email: new UntypedFormControl('', {
validators: [Validators.required,
Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$')]
}),
allfiles: new FormControl(''),
message: new FormControl(''),
allfiles: new UntypedFormControl(''),
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 { ItemRegisterDoiComponent } from './item-register-doi/item-register-doi.component';
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
@@ -81,7 +81,8 @@ import { DsoSharedModule } from '../../dso-shared/dso-shared.module';
VirtualMetadataComponent,
ItemAuthorizationsComponent,
IdentifierDataComponent,
ItemRegisterDoiComponent
ItemRegisterDoiComponent,
ItemCurateComponent
],
providers: [
BundleDataService,

View File

@@ -41,6 +41,7 @@ import { ItemPageVersionHistoryGuard } from './item-page-version-history.guard';
import { ItemPageCollectionMapperGuard } from './item-page-collection-mapper.guard';
import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component';
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
@@ -82,6 +83,11 @@ import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard';
data: { title: 'item.edit.tabs.metadata.title', showBreadcrumbs: true },
canActivate: [ItemPageMetadataGuard]
},
{
path: 'curate',
component: ItemCurateComponent,
data: { title: 'item.edit.tabs.curate.title', showBreadcrumbs: true }
},
{
path: 'relationships',
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="col-3">
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
<ds-themed-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-themed-thumbnail>
</div>
<div class="col-7">
<dl class="row">
@@ -55,7 +55,7 @@
<div class="file-section row" *ngFor="let file of licenses?.page;">
<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 class="col-7">
<dl class="row">

View File

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

View File

@@ -1,5 +1,5 @@
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 { Operation } from 'fast-json-patch';
@@ -127,7 +127,7 @@ export class OrcidSyncSettingsComponent implements OnInit {
*
* @param form The form group
*/
onSubmit(form: FormGroup): void {
onSubmit(form: UntypedFormGroup): void {
const operations: Operation[] = [];
this.fillOperationsFor(operations, '/orcid/mode', form.value.syncMode);
this.fillOperationsFor(operations, '/orcid/publications', form.value.syncPublications);

View File

@@ -8,10 +8,10 @@
</ds-themed-file-download-link>
<ds-themed-loading *ngIf="isLoading" message="{{'loading.default' | translate}}" [showMessage]="false"></ds-themed-loading>
<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 *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>
</ds-metadata-field-wrapper>

View File

@@ -17,7 +17,7 @@
<div class="col-xs-12 col-md-4">
<ng-container *ngIf="!(mediaViewer.image || mediaViewer.video)">
<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>
</ng-container>
<div *ngIf="mediaViewer.image || mediaViewer.video" class="mb-2">

View File

@@ -18,7 +18,7 @@
<div class="col-xs-12 col-md-4">
<ng-container *ngIf="!(mediaViewer.image || mediaViewer.video)">
<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>
</ng-container>
<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>
<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">
<a [routerLink]="[]" (click)="increase()">{{'item.page.related-items.view-more' |
translate:{ amount: (total - (objects.length * incrementBy) < incrementBy) ? total - (objects.length * incrementBy) : incrementBy } }}</a>
<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 } }}</button>
</div>
<div *ngIf="objects.length > 1" class="float-right">
<a [routerLink]="[]" (click)="decrease()">{{'item.page.related-items.view-less' |
translate:{ amount: representations?.length } }}</a>
<button class="btn btn-link btn-link-inline" (click)="decrease()">{{'item.page.related-items.view-less' |
translate:{ amount: representations?.length } }}</button>
</div>
</div>
</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>
<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">
<a [routerLink]="[]" (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>
<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 } }}</button>
</div>
<div *ngIf="objects.length > 1" class="float-right" id="view-less">
<a [routerLink]="[]" (click)="decrease()">{{'item.page.related-items.view-less' |
translate:{ amount: itemsRD?.payload?.page?.length } }}</a>
<button class="btn btn-link btn-link-inline" (click)="decrease()">{{'item.page.related-items.view-less' |
translate:{ amount: itemsRD?.payload?.page?.length } }}</button>
</div>
</div>
</ng-container>

View File

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

View File

@@ -32,7 +32,7 @@ import {
getItemPageRoute,
getItemVersionRoute
} from '../item-page-routing-paths';
import { FormBuilder } from '@angular/forms';
import { UntypedFormBuilder } from '@angular/forms';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ItemVersionsSummaryModalComponent } from './item-versions-summary-modal/item-versions-summary-modal.component';
import { NotificationsService } from '../../shared/notifications/notifications.service';
@@ -171,7 +171,7 @@ export class ItemVersionsComponent implements OnInit {
private versionService: VersionDataService,
private itemService: ItemDataService,
private paginationService: PaginationService,
private formBuilder: FormBuilder,
private formBuilder: UntypedFormBuilder,
private modalService: NgbModal,
private notificationsService: NotificationsService,
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 { 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 { 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 { 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';
@@ -52,7 +51,6 @@ const DECLARATIONS = [
ItemDetailPreviewFieldComponent,
ItemListPreviewComponent,
ThemedItemListPreviewComponent,
MyDSpaceItemStatusComponent,
];
@NgModule({

View File

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

View File

@@ -14,14 +14,14 @@ import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock
describe('ProcessParametersComponent', () => {
let component: ProcessParametersComponent;
let fixture: ComponentFixture<ProcessParametersComponent>;
let parameterValues;
let script;
let mockParameterValues: ProcessParameter[];
let mockScript: Script;
function init() {
function initParametersAndScriptMockValues() {
const param1 = new ScriptParameter();
const param2 = new ScriptParameter();
script = Object.assign(new Script(), { parameters: [param1, param2] });
parameterValues = [
mockScript = Object.assign(new Script(), { parameters: [param1, param2] });
mockParameterValues = [
Object.assign(new ProcessParameter(), { name: '-a', value: 'bla' }),
Object.assign(new ProcessParameter(), { name: '-b', value: '123' }),
Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }),
@@ -29,7 +29,6 @@ describe('ProcessParametersComponent', () => {
}
beforeEach(waitForAsync(() => {
init();
TestBed.configureTestingModule({
imports: [
FormsModule,
@@ -48,17 +47,34 @@ describe('ProcessParametersComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ProcessParametersComponent);
component = fixture.componentInstance;
component.script = script;
component.parameterValues = parameterValues;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should render a ParameterSelectComponent for each parameter value of the component', () => {
const selectComponents = fixture.debugElement.queryAll(By.directive(ParameterSelectComponent));
expect(selectComponents.length).toBe(parameterValues.length);
describe('when parameter values and script are initialized', () => {
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 { SharedModule } from '../shared/shared.module';
import { ProcessPageRoutingModule } from './process-page-routing.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';
import { ProcessPageSharedModule } from './process-page-shared.module';
@NgModule({
imports: [
ProcessPageRoutingModule,
SharedModule,
ProcessPageSharedModule,
],
declarations: [
NewProcessComponent,
ScriptsSelectComponent,
ScriptHelpComponent,
ParameterSelectComponent,
ProcessParametersComponent,
StringValueInputComponent,
ParameterValueInputComponent,
FileValueInputComponent,
BooleanValueInputComponent,
DateValueInputComponent,
ProcessOverviewComponent,
ProcessDetailComponent,
ProcessDetailFieldComponent,
ProcessFormComponent
],
providers: [
ProcessBreadcrumbResolver,
ProcessBreadcrumbsService
]
})

View File

@@ -5,7 +5,7 @@ import {
DynamicInputModel,
DynamicSelectModel
} from '@ng-dynamic-forms/core';
import { FormGroup } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { TranslateService } from '@ngx-translate/core';
import { hasValue, isNotEmpty } from '../../shared/empty.util';
@@ -80,7 +80,7 @@ export class ProfilePageMetadataFormComponent implements OnInit {
/**
* The form group of this form
*/
formGroup: FormGroup;
formGroup: UntypedFormGroup;
/**
* 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 { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/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 { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
@@ -51,7 +51,7 @@ export class ProfilePageSecurityFormComponent implements OnInit {
/**
* The form group of this form
*/
formGroup: FormGroup;
formGroup: UntypedFormGroup;
/**
* 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
* @param group The FormGroup to validate
*/
checkPasswordsEqual(group: FormGroup) {
checkPasswordsEqual(group: UntypedFormGroup) {
const pass = group.get('password').value;
const repeatPass = group.get('passwordrepeat').value;
@@ -138,7 +138,7 @@ export class ProfilePageSecurityFormComponent implements OnInit {
* Checks if the password is empty
* @param group The FormGroup to validate
*/
checkPasswordEmpty(group: FormGroup) {
checkPasswordEmpty(group: UntypedFormGroup) {
const pass = group.get('password').value;
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 { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { UntypedFormBuilder, ReactiveFormsModule } from '@angular/forms';
import { Router } from '@angular/router';
import { NotificationsService } from '../shared/notifications/notifications.service';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@@ -67,7 +67,7 @@ describe('RegisterEmailFormComponent', () => {
{provide: Router, useValue: router},
{provide: EpersonRegistrationService, useValue: epersonRegistrationService},
{provide: ConfigurationDataService, useValue: configurationDataService},
{provide: FormBuilder, useValue: new FormBuilder()},
{provide: UntypedFormBuilder, useValue: new UntypedFormBuilder()},
{provide: NotificationsService, useValue: notificationsService},
{provide: CookieService, useValue: new CookieServiceMock()},
{provide: GoogleRecaptchaService, useValue: googleRecaptchaService},

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