>>;
- pageSize = 5;
originalOptions = Object.assign(new PaginationComponentOptions(), {
id: 'obo',
currentPage: 1,
- pageSize: this.pageSize
+ pageSize: this.appConfig.item.bitstream.pageSize
});
licenseOptions = Object.assign(new PaginationComponentOptions(), {
id: 'lbo',
currentPage: 1,
- pageSize: this.pageSize
+ pageSize: this.appConfig.item.bitstream.pageSize
});
constructor(
bitstreamDataService: BitstreamDataService,
protected notificationsService: NotificationsService,
protected translateService: TranslateService,
- protected paginationService: PaginationService
+ protected paginationService: PaginationService,
+ @Inject(APP_CONFIG) protected appConfig: AppConfig
) {
- super(bitstreamDataService, notificationsService, translateService);
+ super(bitstreamDataService, notificationsService, translateService, appConfig);
}
ngOnInit(): void {
diff --git a/src/app/item-page/item-page-routing.module.ts b/src/app/item-page/item-page-routing.module.ts
index 03c5342eda..0c855ab34d 100644
--- a/src/app/item-page/item-page-routing.module.ts
+++ b/src/app/item-page/item-page-routing.module.ts
@@ -14,9 +14,7 @@ import { ThemedItemPageComponent } from './simple/themed-item-page.component';
import { ThemedFullItemPageComponent } from './full/themed-full-item-page.component';
import { MenuItemType } from '../shared/menu/menu-item-type.model';
import { VersionPageComponent } from './version-page/version-page/version-page.component';
-import {
- BitstreamRequestACopyPageComponent
-} from '../shared/bitstream-request-a-copy-page/bitstream-request-a-copy-page.component';
+import { BitstreamRequestACopyPageComponent } from './bitstreams/request-a-copy/bitstream-request-a-copy-page.component';
import { REQUEST_COPY_MODULE_PATH } from '../app-routing-paths';
import { OrcidPageComponent } from './orcid-page/orcid-page.component';
import { OrcidPageGuard } from './orcid-page/orcid-page.guard';
@@ -69,6 +67,7 @@ import { DSOEditMenuResolver } from '../shared/dso-page/dso-edit-menu.resolver';
id: 'statistics_item_:id',
active: true,
visible: true,
+ index: 2,
model: {
type: MenuItemType.LINK,
text: 'menu.section.statistics',
diff --git a/src/app/item-page/item-page.module.ts b/src/app/item-page/item-page.module.ts
index b34e99d596..5842e9e17e 100644
--- a/src/app/item-page/item-page.module.ts
+++ b/src/app/item-page/item-page.module.ts
@@ -45,6 +45,12 @@ import { OrcidPageComponent } from './orcid-page/orcid-page.component';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import { OrcidSyncSettingsComponent } from './orcid-page/orcid-sync-settings/orcid-sync-settings.component';
import { OrcidQueueComponent } from './orcid-page/orcid-queue/orcid-queue.component';
+import { UploadModule } from '../shared/upload/upload.module';
+import { ItemAlertsComponent } from './alerts/item-alerts.component';
+import { ItemVersionsModule } from './versions/item-versions.module';
+import { BitstreamRequestACopyPageComponent } from './bitstreams/request-a-copy/bitstream-request-a-copy-page.component';
+import { FileSectionComponent } from './simple/field-components/file-section/file-section.component';
+import { ItemSharedModule } from './item-shared.module';
const ENTRY_COMPONENTS = [
@@ -54,6 +60,7 @@ const ENTRY_COMPONENTS = [
];
const DECLARATIONS = [
+ FileSectionComponent,
ThemedFileSectionComponent,
ItemPageComponent,
ThemedItemPageComponent,
@@ -80,7 +87,10 @@ const DECLARATIONS = [
OrcidPageComponent,
OrcidAuthComponent,
OrcidSyncSettingsComponent,
- OrcidQueueComponent
+ OrcidQueueComponent,
+ ItemAlertsComponent,
+ VersionedItemComponent,
+ BitstreamRequestACopyPageComponent,
];
@NgModule({
@@ -89,17 +99,21 @@ const DECLARATIONS = [
SharedModule.withEntryComponents(),
ItemPageRoutingModule,
EditItemPageModule,
+ ItemVersionsModule,
+ ItemSharedModule,
StatisticsModule.forRoot(),
JournalEntitiesModule.withEntryComponents(),
ResearchEntitiesModule.withEntryComponents(),
NgxGalleryModule,
- NgbAccordionModule
+ NgbAccordionModule,
+ UploadModule,
],
declarations: [
...DECLARATIONS,
+
],
exports: [
- ...DECLARATIONS
+ ...DECLARATIONS,
]
})
export class ItemPageModule {
diff --git a/src/app/item-page/item-shared.module.ts b/src/app/item-page/item-shared.module.ts
index b191b6c4b3..c558b11692 100644
--- a/src/app/item-page/item-shared.module.ts
+++ b/src/app/item-page/item-shared.module.ts
@@ -7,10 +7,32 @@ import { TranslateModule } from '@ngx-translate/core';
import { DYNAMIC_FORM_CONTROL_MAP_FN } from '@ng-dynamic-forms/core';
import { dsDynamicFormControlMapFn } from '../shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
import { TabbedRelatedEntitiesSearchComponent } from './simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component';
+import { ItemVersionsDeleteModalComponent } from './versions/item-versions-delete-modal/item-versions-delete-modal.component';
+import { ItemVersionsSummaryModalComponent } from './versions/item-versions-summary-modal/item-versions-summary-modal.component';
+import { MetadataValuesComponent } from './field-components/metadata-values/metadata-values.component';
+import { DsoPageVersionButtonComponent } from '../shared/dso-page/dso-page-version-button/dso-page-version-button.component';
+import { PersonPageClaimButtonComponent } from '../shared/dso-page/person-page-claim-button/person-page-claim-button.component';
+import { GenericItemPageFieldComponent } from './simple/field-components/specific-field/generic/generic-item-page-field.component';
+import { MetadataRepresentationListComponent } from './simple/metadata-representation-list/metadata-representation-list.component';
+import { RelatedItemsComponent } from './simple/related-items/related-items-component';
+import { DsoPageOrcidButtonComponent } from '../shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component';
+
+const ENTRY_COMPONENTS = [
+ ItemVersionsDeleteModalComponent,
+ ItemVersionsSummaryModalComponent,
+];
const COMPONENTS = [
+ ...ENTRY_COMPONENTS,
RelatedEntitiesSearchComponent,
- TabbedRelatedEntitiesSearchComponent
+ TabbedRelatedEntitiesSearchComponent,
+ MetadataValuesComponent,
+ DsoPageVersionButtonComponent,
+ PersonPageClaimButtonComponent,
+ GenericItemPageFieldComponent,
+ MetadataRepresentationListComponent,
+ RelatedItemsComponent,
+ DsoPageOrcidButtonComponent
];
@NgModule({
@@ -30,7 +52,8 @@ const COMPONENTS = [
{
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
useValue: dsDynamicFormControlMapFn
- }
+ },
+ ...ENTRY_COMPONENTS,
]
})
export class ItemSharedModule { }
diff --git a/src/app/item-page/media-viewer/media-viewer-video/caption-info.ts b/src/app/item-page/media-viewer/media-viewer-video/caption-info.ts
new file mode 100644
index 0000000000..43996d096d
--- /dev/null
+++ b/src/app/item-page/media-viewer/media-viewer-video/caption-info.ts
@@ -0,0 +1,11 @@
+/*
+ The class is designed to host information related to Video Captioning support
+ and used in HTML 5 video track
+ src: source vtt file
+ srclang: two letter language code
+ langLabel: language label
+ */
+export class CaptionInfo {
+ constructor(public src: string, public srclang: string, public langLabel: string ) {
+ }
+}
diff --git a/src/app/item-page/media-viewer/media-viewer-video/language-helper.ts b/src/app/item-page/media-viewer/media-viewer-video/language-helper.ts
new file mode 100644
index 0000000000..b27ab9983f
--- /dev/null
+++ b/src/app/item-page/media-viewer/media-viewer-video/language-helper.ts
@@ -0,0 +1,190 @@
+export const languageHelper = {
+ ab: 'Abkhazian',
+ aa: 'Afar',
+ af: 'Afrikaans',
+ ak: 'Akan',
+ sq: 'Albanian',
+ am: 'Amharic',
+ ar: 'Arabic',
+ an: 'Aragonese',
+ hy: 'Armenian',
+ as: 'Assamese',
+ av: 'Avaric',
+ ae: 'Avestan',
+ ay: 'Aymara',
+ az: 'Azerbaijani',
+ bm: 'Bambara',
+ ba: 'Bashkir',
+ eu: 'Basque',
+ be: 'Belarusian',
+ bn: 'Bengali (Bangla)',
+ bh: 'Bihari',
+ bi: 'Bislama',
+ bs: 'Bosnian',
+ br: 'Breton',
+ bg: 'Bulgarian',
+ my: 'Burmese',
+ ca: 'Catalan',
+ ch: 'Chamorro',
+ ce: 'Chechen',
+ ny: 'Chichewa, Chewa, Nyanja',
+ zh: 'Chinese',
+ cv: 'Chuvash',
+ kw: 'Cornish',
+ co: 'Corsican',
+ cr: 'Cree',
+ hr: 'Croatian',
+ cs: 'Czech',
+ da: 'Danish',
+ dv: 'Divehi, Dhivehi, Maldivian',
+ nl: 'Dutch',
+ dz: 'Dzongkha',
+ en: 'English',
+ eo: 'Esperanto',
+ et: 'Estonian',
+ ee: 'Ewe',
+ fo: 'Faroese',
+ fj: 'Fijian',
+ fi: 'Finnish',
+ fr: 'French',
+ ff: 'Fula, Fulah, Pulaar, Pular',
+ gl: 'Galician',
+ gd: 'Gaelic (Scottish)',
+ gv: 'Gaelic (Manx)',
+ ka: 'Georgian',
+ de: 'German',
+ el: 'Greek',
+ gn: 'Guarani',
+ gu: 'Gujarati',
+ ht: 'Haitian Creole',
+ ha: 'Hausa',
+ he: 'Hebrew',
+ hz: 'Herero',
+ hi: 'Hindi',
+ ho: 'Hiri Motu',
+ hu: 'Hungarian',
+ is: 'Icelandic',
+ io: 'Ido',
+ ig: 'Igbo',
+ in: 'Indonesian',
+ ia: 'Interlingua',
+ ie: 'Interlingue',
+ iu: 'Inuktitut',
+ ik: 'Inupiak',
+ ga: 'Irish',
+ it: 'Italian',
+ ja: 'Japanese',
+ jv: 'Javanese',
+ kl: 'Kalaallisut, Greenlandic',
+ kn: 'Kannada',
+ kr: 'Kanuri',
+ ks: 'Kashmiri',
+ kk: 'Kazakh',
+ km: 'Khmer',
+ ki: 'Kikuyu',
+ rw: 'Kinyarwanda (Rwanda)',
+ rn: 'Kirundi',
+ ky: 'Kyrgyz',
+ kv: 'Komi',
+ kg: 'Kongo',
+ ko: 'Korean',
+ ku: 'Kurdish',
+ kj: 'Kwanyama',
+ lo: 'Lao',
+ la: 'Latin',
+ lv: 'Latvian (Lettish)',
+ li: 'Limburgish ( Limburger)',
+ ln: 'Lingala',
+ lt: 'Lithuanian',
+ lu: 'Luga-Katanga',
+ lg: 'Luganda, Ganda',
+ lb: 'Luxembourgish',
+ mk: 'Macedonian',
+ mg: 'Malagasy',
+ ms: 'Malay',
+ ml: 'Malayalam',
+ mt: 'Maltese',
+ mi: 'Maori',
+ mr: 'Marathi',
+ mh: 'Marshallese',
+ mo: 'Moldavian',
+ mn: 'Mongolian',
+ na: 'Nauru',
+ nv: 'Navajo',
+ ng: 'Ndonga',
+ nd: 'Northern Ndebele',
+ ne: 'Nepali',
+ no: 'Norwegian',
+ nb: 'Norwegian bokmål',
+ nn: 'Norwegian nynorsk',
+ oc: 'Occitan',
+ oj: 'Ojibwe',
+ cu: 'Old Church Slavonic, Old Bulgarian',
+ or: 'Oriya',
+ om: 'Oromo (Afaan Oromo)',
+ os: 'Ossetian',
+ pi: 'Pāli',
+ ps: 'Pashto, Pushto',
+ fa: 'Persian (Farsi)',
+ pl: 'Polish',
+ pt: 'Portuguese',
+ pa: 'Punjabi (Eastern)',
+ qu: 'Quechua',
+ rm: 'Romansh',
+ ro: 'Romanian',
+ ru: 'Russian',
+ se: 'Sami',
+ sm: 'Samoan',
+ sg: 'Sango',
+ sa: 'Sanskrit',
+ sr: 'Serbian',
+ sh: 'Serbo-Croatian',
+ st: 'Sesotho',
+ tn: 'Setswana',
+ sn: 'Shona',
+ ii: 'Sichuan Yi, Nuosu',
+ sd: 'Sindhi',
+ si: 'Sinhalese',
+ ss: 'Siswati (Swati)',
+ sk: 'Slovak',
+ sl: 'Slovenian',
+ so: 'Somali',
+ nr: 'Southern Ndebele',
+ es: 'Spanish',
+ su: 'Sundanese',
+ sw: 'Swahili (Kiswahili)',
+ sv: 'Swedish',
+ tl: 'Tagalog',
+ ty: 'Tahitian',
+ tg: 'Tajik',
+ ta: 'Tamil',
+ tt: 'Tatar',
+ te: 'Telugu',
+ th: 'Thai',
+ bo: 'Tibetan',
+ ti: 'Tigrinya',
+ to: 'Tonga',
+ ts: 'Tsonga',
+ tr: 'Turkish',
+ tk: 'Turkmen',
+ tw: 'Twi',
+ ug: 'Uyghur',
+ uk: 'Ukrainian',
+ ur: 'Urdu',
+ uz: 'Uzbek',
+ ve: 'Venda',
+ vi: 'Vietnamese',
+ vo: 'Volapük',
+ wa: 'Wallon',
+ cy: 'Welsh',
+ wo: 'Wolof',
+ fy: 'Western Frisian',
+ xh: 'Xhosa',
+ yi: 'Yiddish',
+ yo: 'Yoruba',
+ za: 'Zhuang, Chuang',
+ zu: 'Zulu'
+};
+
+
+
diff --git a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html
index a4493e36fc..0cc854b272 100644
--- a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html
+++ b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.html
@@ -1,4 +1,5 @@
+>
+
+
+
+
+
+
+
1">
media.format === 'audio' || media.format === 'video'
- );
+ this.filteredMedias = this.medias.filter((media) => media.format === 'audio' || media.format === 'video');
+ }
+
+ /**
+ * This method check if there is caption file for the media
+ * The caption file name is the media name plus "-" following two letter
+ * language code and .vtt suffix
+ *
+ * html5 video only support WEBVTT format
+ *
+ * Two letter language code reference
+ * https://www.w3schools.com/tags/ref_language_codes.asp
+ */
+ getMediaCap(name: string): CaptionInfo[] {
+ let filteredCapMedias: MediaViewerItem[];
+ let capInfos: CaptionInfo[] = [];
+ filteredCapMedias = this.medias
+ .filter((media) => media.mimetype === 'text/vtt')
+ .filter((media) => media.bitstream.name.substring(0, (media.bitstream.name.length - 7) ).toLowerCase() === name.toLowerCase());
+
+ if (filteredCapMedias) {
+ filteredCapMedias
+ .forEach((media, index) => {
+ let srclang: string = media.bitstream.name.slice(-6, -4).toLowerCase();
+ capInfos.push(new CaptionInfo(
+ media.bitstream._links.content.href,
+ srclang,
+ languageHelper[srclang]
+ ));
+ });
+ }
+ return capInfos;
}
/**
diff --git a/src/app/item-page/media-viewer/media-viewer.component.spec.ts b/src/app/item-page/media-viewer/media-viewer.component.spec.ts
index 39a35ebe61..3369574f20 100644
--- a/src/app/item-page/media-viewer/media-viewer.component.spec.ts
+++ b/src/app/item-page/media-viewer/media-viewer.component.spec.ts
@@ -13,7 +13,7 @@ import { BitstreamDataService } from '../../core/data/bitstream-data.service';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MediaViewerItem } from '../../core/shared/media-viewer-item.model';
import { VarDirective } from '../../shared/utils/var.directive';
-import { MetadataFieldWrapperComponent } from '../field-components/metadata-field-wrapper/metadata-field-wrapper.component';
+import { MetadataFieldWrapperComponent } from '../../shared/metadata-field-wrapper/metadata-field-wrapper.component';
import { FileSizePipe } from '../../shared/utils/file-size-pipe';
describe('MediaViewerComponent', () => {
diff --git a/src/app/item-page/media-viewer/media-viewer.component.ts b/src/app/item-page/media-viewer/media-viewer.component.ts
index 3f9de8ed3e..233ae0e6f6 100644
--- a/src/app/item-page/media-viewer/media-viewer.component.ts
+++ b/src/app/item-page/media-viewer/media-viewer.component.ts
@@ -108,6 +108,7 @@ export class MediaViewerComponent implements OnInit {
const mediaItem = new MediaViewerItem();
mediaItem.bitstream = original;
mediaItem.format = format.mimetype.split('/')[0];
+ mediaItem.mimetype = format.mimetype;
mediaItem.thumbnail = thumbnail ? thumbnail._links.content.href : null;
return mediaItem;
}
diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts b/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts
index 2d185aef9c..ebc8096fb5 100644
--- a/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts
+++ b/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts
@@ -13,10 +13,12 @@ import { of as observableOf } from 'rxjs';
import { MockBitstreamFormat1 } from '../../../../shared/mocks/item.mock';
import { FileSizePipe } from '../../../../shared/utils/file-size-pipe';
import { PageInfo } from '../../../../core/shared/page-info.model';
-import { MetadataFieldWrapperComponent } from '../../../field-components/metadata-field-wrapper/metadata-field-wrapper.component';
+import { MetadataFieldWrapperComponent } from '../../../../shared/metadata-field-wrapper/metadata-field-wrapper.component';
import { createPaginatedList } from '../../../../shared/testing/utils.test';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
+import { APP_CONFIG } from 'src/config/app-config.interface';
+import { environment } from 'src/environments/environment';
describe('FileSectionComponent', () => {
let comp: FileSectionComponent;
@@ -65,7 +67,8 @@ describe('FileSectionComponent', () => {
declarations: [FileSectionComponent, VarDirective, FileSizePipe, MetadataFieldWrapperComponent],
providers: [
{ provide: BitstreamDataService, useValue: bitstreamDataService },
- { provide: NotificationsService, useValue: new NotificationsServiceStub() }
+ { provide: NotificationsService, useValue: new NotificationsServiceStub() },
+ { provide: APP_CONFIG, useValue: environment }
],
schemas: [NO_ERRORS_SCHEMA]
diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.ts b/src/app/item-page/simple/field-components/file-section/file-section.component.ts
index d28b579996..08e792fc8b 100644
--- a/src/app/item-page/simple/field-components/file-section/file-section.component.ts
+++ b/src/app/item-page/simple/field-components/file-section/file-section.component.ts
@@ -1,4 +1,4 @@
-import { Component, Input, OnInit } from '@angular/core';
+import { Component, Inject, Input, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
@@ -10,6 +10,7 @@ import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
+import { AppConfig, APP_CONFIG } from 'src/config/app-config.interface';
/**
* This component renders the file section of the item
@@ -35,13 +36,15 @@ export class FileSectionComponent implements OnInit {
isLastPage: boolean;
- pageSize = 5;
+ pageSize: number;
constructor(
protected bitstreamDataService: BitstreamDataService,
protected notificationsService: NotificationsService,
- protected translateService: TranslateService
+ protected translateService: TranslateService,
+ @Inject(APP_CONFIG) protected appConfig: AppConfig
) {
+ this.pageSize = this.appConfig.item.bitstream.pageSize;
}
ngOnInit(): void {
diff --git a/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.spec.ts b/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.spec.ts
index 57f546fbec..176a692f4b 100644
--- a/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.spec.ts
+++ b/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.spec.ts
@@ -36,7 +36,7 @@ import { VersionDataService } from '../../../../core/data/version-data.service';
import { RouterTestingModule } from '@angular/router/testing';
import { WorkspaceitemDataService } from '../../../../core/submission/workspaceitem-data.service';
import { SearchService } from '../../../../core/shared/search/search.service';
-import { ItemVersionsSharedService } from '../../../../shared/item/item-versions/item-versions-shared.service';
+import { ItemVersionsSharedService } from '../../../versions/item-versions-shared.service';
const noMetadata = new MetadataMap();
diff --git a/src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.html b/src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.html
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.html
rename to src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.html
diff --git a/src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.scss b/src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.scss
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.scss
rename to src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.scss
diff --git a/src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.spec.ts b/src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.spec.ts
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.spec.ts
rename to src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.spec.ts
diff --git a/src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.ts b/src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.ts
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component.ts
rename to src/app/item-page/versions/item-versions-delete-modal/item-versions-delete-modal.component.ts
diff --git a/src/app/shared/item/item-versions/item-versions-shared.service.spec.ts b/src/app/item-page/versions/item-versions-shared.service.spec.ts
similarity index 75%
rename from src/app/shared/item/item-versions/item-versions-shared.service.spec.ts
rename to src/app/item-page/versions/item-versions-shared.service.spec.ts
index a9f9596548..d4adbf681f 100644
--- a/src/app/shared/item/item-versions/item-versions-shared.service.spec.ts
+++ b/src/app/item-page/versions/item-versions-shared.service.spec.ts
@@ -2,15 +2,15 @@ import { TestBed } from '@angular/core/testing';
import { ItemVersionsSharedService } from './item-versions-shared.service';
import { ActivatedRoute } from '@angular/router';
-import { VersionDataService } from '../../../core/data/version-data.service';
-import { AuthService } from '../../../core/auth/auth.service';
-import { NotificationsService } from '../../notifications/notifications.service';
+import { VersionDataService } from '../../core/data/version-data.service';
+import { AuthService } from '../../core/auth/auth.service';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
-import { VersionHistoryDataService } from '../../../core/data/version-history-data.service';
-import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service';
-import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service';
-import { createFailedRemoteDataObject, createSuccessfulRemoteDataObject } from '../../remote-data.utils';
-import { Version } from '../../../core/shared/version.model';
+import { VersionHistoryDataService } from '../../core/data/version-history-data.service';
+import { WorkspaceitemDataService } from '../../core/submission/workspaceitem-data.service';
+import { WorkflowItemDataService } from '../../core/submission/workflowitem-data.service';
+import { createFailedRemoteDataObject, createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
+import { Version } from '../../core/shared/version.model';
describe('ItemVersionsSharedService', () => {
let service: ItemVersionsSharedService;
diff --git a/src/app/shared/item/item-versions/item-versions-shared.service.ts b/src/app/item-page/versions/item-versions-shared.service.ts
similarity index 84%
rename from src/app/shared/item/item-versions/item-versions-shared.service.ts
rename to src/app/item-page/versions/item-versions-shared.service.ts
index 996623509c..09104f5ddc 100644
--- a/src/app/shared/item/item-versions/item-versions-shared.service.ts
+++ b/src/app/item-page/versions/item-versions-shared.service.ts
@@ -1,8 +1,8 @@
import { Injectable } from '@angular/core';
-import { NotificationsService } from '../../notifications/notifications.service';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
-import { RemoteData } from '../../../core/data/remote-data';
-import { Version } from '../../../core/shared/version.model';
+import { RemoteData } from '../../core/data/remote-data';
+import { Version } from '../../core/shared/version.model';
@Injectable({
providedIn: 'root'
diff --git a/src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.html b/src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.html
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.html
rename to src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.html
diff --git a/src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.scss b/src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.scss
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.scss
rename to src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.scss
diff --git a/src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.spec.ts b/src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.spec.ts
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.spec.ts
rename to src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.spec.ts
diff --git a/src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.ts b/src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.ts
similarity index 93%
rename from src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.ts
rename to src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.ts
index 23ee62e628..8f2c7bd62e 100644
--- a/src/app/shared/item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component.ts
+++ b/src/app/item-page/versions/item-versions-summary-modal/item-versions-summary-modal.component.ts
@@ -1,7 +1,7 @@
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { BehaviorSubject } from 'rxjs';
-import { ModalBeforeDismiss } from '../../../interfaces/modal-before-dismiss.interface';
+import { ModalBeforeDismiss } from '../../../shared/interfaces/modal-before-dismiss.interface';
@Component({
selector: 'ds-item-versions-summary-modal',
diff --git a/src/app/shared/item/item-versions/item-versions.component.html b/src/app/item-page/versions/item-versions.component.html
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions.component.html
rename to src/app/item-page/versions/item-versions.component.html
diff --git a/src/app/shared/item/item-versions/item-versions.component.scss b/src/app/item-page/versions/item-versions.component.scss
similarity index 100%
rename from src/app/shared/item/item-versions/item-versions.component.scss
rename to src/app/item-page/versions/item-versions.component.scss
diff --git a/src/app/shared/item/item-versions/item-versions.component.spec.ts b/src/app/item-page/versions/item-versions.component.spec.ts
similarity index 87%
rename from src/app/shared/item/item-versions/item-versions.component.spec.ts
rename to src/app/item-page/versions/item-versions.component.spec.ts
index d4dbc336ab..999176d996 100644
--- a/src/app/shared/item/item-versions/item-versions.component.spec.ts
+++ b/src/app/item-page/versions/item-versions.component.spec.ts
@@ -2,33 +2,33 @@ import { ItemVersionsComponent } from './item-versions.component';
import {
ComponentFixture, TestBed, waitForAsync
} from '@angular/core/testing';
-import { VarDirective } from '../../utils/var.directive';
+import { VarDirective } from '../../shared/utils/var.directive';
import { TranslateModule } from '@ngx-translate/core';
import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { Item } from '../../../core/shared/item.model';
-import { Version } from '../../../core/shared/version.model';
-import { VersionHistory } from '../../../core/shared/version-history.model';
-import { VersionHistoryDataService } from '../../../core/data/version-history-data.service';
+import { Item } from '../../core/shared/item.model';
+import { Version } from '../../core/shared/version.model';
+import { VersionHistory } from '../../core/shared/version-history.model';
+import { VersionHistoryDataService } from '../../core/data/version-history-data.service';
import { BrowserModule, By } from '@angular/platform-browser';
-import { createSuccessfulRemoteDataObject$ } from '../../remote-data.utils';
-import { createPaginatedList } from '../../testing/utils.test';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
+import { createPaginatedList } from '../../shared/testing/utils.test';
import { EMPTY, of, of as observableOf } from 'rxjs';
-import { PaginationService } from '../../../core/pagination/pagination.service';
-import { PaginationServiceStub } from '../../testing/pagination-service.stub';
-import { AuthService } from '../../../core/auth/auth.service';
-import { VersionDataService } from '../../../core/data/version-data.service';
-import { ItemDataService } from '../../../core/data/item-data.service';
+import { PaginationService } from '../../core/pagination/pagination.service';
+import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
+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 { NotificationsService } from '../../notifications/notifications.service';
-import { NotificationsServiceStub } from '../../testing/notifications-service.stub';
-import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
-import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
-import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service';
-import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service';
-import { ConfigurationDataService } from '../../../core/data/configuration-data.service';
+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';
+import { FeatureID } from '../../core/data/feature-authorization/feature-id';
+import { WorkspaceitemDataService } from '../../core/submission/workspaceitem-data.service';
+import { WorkflowItemDataService } from '../../core/submission/workflowitem-data.service';
+import { ConfigurationDataService } from '../../core/data/configuration-data.service';
import { Router } from '@angular/router';
-import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { CommonModule } from '@angular/common';
+import { ItemSharedModule } from '../item-shared.module';
describe('ItemVersionsComponent', () => {
let component: ItemVersionsComponent;
@@ -137,7 +137,7 @@ describe('ItemVersionsComponent', () => {
TestBed.configureTestingModule({
declarations: [ItemVersionsComponent, VarDirective],
- imports: [TranslateModule.forRoot(), CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule],
+ imports: [TranslateModule.forRoot(), CommonModule, FormsModule, ReactiveFormsModule, BrowserModule, ItemSharedModule],
providers: [
{provide: PaginationService, useValue: new PaginationServiceStub()},
{provide: FormBuilder, useValue: new FormBuilder()},
diff --git a/src/app/shared/item/item-versions/item-versions.component.ts b/src/app/item-page/versions/item-versions.component.ts
similarity index 91%
rename from src/app/shared/item/item-versions/item-versions.component.ts
rename to src/app/item-page/versions/item-versions.component.ts
index b7b8182658..e0fc623f49 100644
--- a/src/app/shared/item/item-versions/item-versions.component.ts
+++ b/src/app/item-page/versions/item-versions.component.ts
@@ -1,7 +1,7 @@
import { Component, Input, OnInit } from '@angular/core';
-import { Item } from '../../../core/shared/item.model';
-import { Version } from '../../../core/shared/version.model';
-import { RemoteData } from '../../../core/data/remote-data';
+import { Item } from '../../core/shared/item.model';
+import { Version } from '../../core/shared/version.model';
+import { RemoteData } from '../../core/data/remote-data';
import {
BehaviorSubject,
combineLatest,
@@ -9,7 +9,7 @@ import {
of,
Subscription,
} from 'rxjs';
-import { VersionHistory } from '../../../core/shared/version-history.model';
+import { VersionHistory } from '../../core/shared/version-history.model';
import {
getAllSucceededRemoteData,
getAllSucceededRemoteDataPayload,
@@ -17,37 +17,37 @@ import {
getFirstSucceededRemoteData,
getFirstSucceededRemoteDataPayload,
getRemoteDataPayload
-} from '../../../core/shared/operators';
+} from '../../core/shared/operators';
import { map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators';
-import { PaginatedList } from '../../../core/data/paginated-list.model';
-import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model';
-import { VersionHistoryDataService } from '../../../core/data/version-history-data.service';
-import { PaginatedSearchOptions } from '../../search/models/paginated-search-options.model';
-import { AlertType } from '../../alert/aletr-type';
-import { followLink } from '../../utils/follow-link-config.model';
-import { hasValue, hasValueOperator } from '../../empty.util';
-import { PaginationService } from '../../../core/pagination/pagination.service';
+import { PaginatedList } from '../../core/data/paginated-list.model';
+import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
+import { VersionHistoryDataService } from '../../core/data/version-history-data.service';
+import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
+import { AlertType } from '../../shared/alert/aletr-type';
+import { followLink } from '../../shared/utils/follow-link-config.model';
+import { hasValue, hasValueOperator } from '../../shared/empty.util';
+import { PaginationService } from '../../core/pagination/pagination.service';
import {
getItemEditVersionhistoryRoute,
getItemPageRoute,
getItemVersionRoute
-} from '../../../item-page/item-page-routing-paths';
+} from '../item-page-routing-paths';
import { FormBuilder } 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 '../../notifications/notifications.service';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { ItemVersionsDeleteModalComponent } from './item-versions-delete-modal/item-versions-delete-modal.component';
-import { VersionDataService } from '../../../core/data/version-data.service';
-import { ItemDataService } from '../../../core/data/item-data.service';
+import { VersionDataService } from '../../core/data/version-data.service';
+import { ItemDataService } from '../../core/data/item-data.service';
import { Router } from '@angular/router';
-import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
-import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
+import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
+import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { ItemVersionsSharedService } from './item-versions-shared.service';
-import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
-import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service';
-import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service';
-import { ConfigurationDataService } from '../../../core/data/configuration-data.service';
+import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model';
+import { WorkspaceitemDataService } from '../../core/submission/workspaceitem-data.service';
+import { WorkflowItemDataService } from '../../core/submission/workflowitem-data.service';
+import { ConfigurationDataService } from '../../core/data/configuration-data.service';
@Component({
selector: 'ds-item-versions',
diff --git a/src/app/item-page/versions/item-versions.module.ts b/src/app/item-page/versions/item-versions.module.ts
new file mode 100644
index 0000000000..577844488d
--- /dev/null
+++ b/src/app/item-page/versions/item-versions.module.ts
@@ -0,0 +1,32 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+
+import { NgModule } from '@angular/core';
+import { SharedModule } from '../../shared/shared.module';
+import { ItemVersionsComponent } from './item-versions.component';
+import { ItemVersionsNoticeComponent } from './notice/item-versions-notice.component';
+
+const DECLARATIONS = [
+ ItemVersionsComponent,
+ ItemVersionsNoticeComponent,
+];
+
+@NgModule({
+ imports: [
+ SharedModule,
+ ],
+ declarations: [
+ ...DECLARATIONS,
+ ],
+ exports: [
+ ...DECLARATIONS,
+ ],
+})
+export class ItemVersionsModule {
+
+}
diff --git a/src/app/shared/item/item-versions/notice/item-versions-notice.component.html b/src/app/item-page/versions/notice/item-versions-notice.component.html
similarity index 100%
rename from src/app/shared/item/item-versions/notice/item-versions-notice.component.html
rename to src/app/item-page/versions/notice/item-versions-notice.component.html
diff --git a/src/app/shared/item/item-versions/notice/item-versions-notice.component.spec.ts b/src/app/item-page/versions/notice/item-versions-notice.component.spec.ts
similarity index 90%
rename from src/app/shared/item/item-versions/notice/item-versions-notice.component.spec.ts
rename to src/app/item-page/versions/notice/item-versions-notice.component.spec.ts
index 2849ba4909..fb29e54a21 100644
--- a/src/app/shared/item/item-versions/notice/item-versions-notice.component.spec.ts
+++ b/src/app/item-page/versions/notice/item-versions-notice.component.spec.ts
@@ -3,13 +3,13 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { VersionHistory } from '../../../../core/shared/version-history.model';
-import { Version } from '../../../../core/shared/version.model';
-import { Item } from '../../../../core/shared/item.model';
-import { VersionHistoryDataService } from '../../../../core/data/version-history-data.service';
+import { VersionHistory } from '../../../core/shared/version-history.model';
+import { Version } from '../../../core/shared/version.model';
+import { Item } from '../../../core/shared/item.model';
+import { VersionHistoryDataService } from '../../../core/data/version-history-data.service';
import { By } from '@angular/platform-browser';
-import { createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
-import { createPaginatedList } from '../../../testing/utils.test';
+import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
+import { createPaginatedList } from '../../../shared/testing/utils.test';
import { of } from 'rxjs';
import { take } from 'rxjs/operators';
diff --git a/src/app/shared/item/item-versions/notice/item-versions-notice.component.ts b/src/app/item-page/versions/notice/item-versions-notice.component.ts
similarity index 81%
rename from src/app/shared/item/item-versions/notice/item-versions-notice.component.ts
rename to src/app/item-page/versions/notice/item-versions-notice.component.ts
index a292ea65c6..8a8f5ff76f 100644
--- a/src/app/shared/item/item-versions/notice/item-versions-notice.component.ts
+++ b/src/app/item-page/versions/notice/item-versions-notice.component.ts
@@ -1,19 +1,19 @@
import { Component, Input, OnInit } from '@angular/core';
-import { Item } from '../../../../core/shared/item.model';
+import { Item } from '../../../core/shared/item.model';
import { Observable } from 'rxjs';
-import { RemoteData } from '../../../../core/data/remote-data';
-import { VersionHistory } from '../../../../core/shared/version-history.model';
-import { Version } from '../../../../core/shared/version.model';
-import { hasValue, hasValueOperator } from '../../../empty.util';
+import { RemoteData } from '../../../core/data/remote-data';
+import { VersionHistory } from '../../../core/shared/version-history.model';
+import { Version } from '../../../core/shared/version.model';
+import { hasValue, hasValueOperator } from '../../../shared/empty.util';
import {
getAllSucceededRemoteData,
getFirstSucceededRemoteDataPayload,
getRemoteDataPayload
-} from '../../../../core/shared/operators';
+} from '../../../core/shared/operators';
import { map, startWith, switchMap } from 'rxjs/operators';
-import { VersionHistoryDataService } from '../../../../core/data/version-history-data.service';
-import { AlertType } from '../../../alert/aletr-type';
-import { getItemPageRoute } from '../../../../item-page/item-page-routing-paths';
+import { VersionHistoryDataService } from '../../../core/data/version-history-data.service';
+import { AlertType } from '../../../shared/alert/aletr-type';
+import { getItemPageRoute } from '../../item-page-routing-paths';
@Component({
selector: 'ds-item-versions-notice',
diff --git a/src/app/my-dspace-page/collection-selector/collection-selector.component.html b/src/app/my-dspace-page/collection-selector/collection-selector.component.html
index a87118fc4e..6e2a1925c5 100644
--- a/src/app/my-dspace-page/collection-selector/collection-selector.component.html
+++ b/src/app/my-dspace-page/collection-selector/collection-selector.component.html
@@ -5,7 +5,7 @@
-
-
+
+
diff --git a/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts b/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts
index ce54d326fc..af043b447b 100644
--- a/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts
+++ b/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts
@@ -128,10 +128,13 @@ describe('CollectionSelectorComponent', () => {
beforeEach(() => {
scheduler = getTestScheduler();
- fixture = TestBed.createComponent(CollectionSelectorComponent);
+ fixture = TestBed.overrideComponent(CollectionSelectorComponent, {
+ set: {
+ template: ' '
+ }
+ }).createComponent(CollectionSelectorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
-
});
it('should create', () => {
diff --git a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.spec.ts b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.spec.ts
index fb43c253eb..ed61fab1d6 100644
--- a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.spec.ts
+++ b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.spec.ts
@@ -16,10 +16,10 @@ import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { getMockScrollToService } from '../../shared/mocks/scroll-to-service.mock';
-import { UploaderService } from '../../shared/uploader/uploader.service';
+import { DragService } from '../../core/drag.service';
import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
-import { UploaderComponent } from '../../shared/uploader/uploader.component';
+import { UploaderComponent } from '../../shared/upload/uploader/uploader.component';
import { HttpXsrfTokenExtractor } from '@angular/common/http';
import { CookieService } from '../../core/services/cookie.service';
import { CookieServiceMock } from '../../shared/mocks/cookie.service.mock';
@@ -59,7 +59,7 @@ describe('MyDSpaceNewSubmissionComponent test', () => {
NgbModal,
ChangeDetectorRef,
MyDSpaceNewSubmissionComponent,
- UploaderService,
+ DragService,
{ provide: HttpXsrfTokenExtractor, useValue: new HttpXsrfTokenExtractorMock('mock-token') },
{ provide: CookieService, useValue: new CookieServiceMock() },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
diff --git a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts
index b2ba6fe2af..0694fc63bf 100644
--- a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts
+++ b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts
@@ -8,13 +8,13 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AuthService } from '../../core/auth/auth.service';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { UploaderOptions } from '../../shared/uploader/uploader-options.model';
+import { UploaderOptions } from '../../shared/upload/uploader/uploader-options.model';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { hasValue } from '../../shared/empty.util';
import { SearchResult } from '../../shared/search/models/search-result.model';
import { CollectionSelectorComponent } from '../collection-selector/collection-selector.component';
-import { UploaderComponent } from '../../shared/uploader/uploader.component';
-import { UploaderError } from '../../shared/uploader/uploader-error.model';
+import { UploaderComponent } from '../../shared/upload/uploader/uploader.component';
+import { UploaderError } from '../../shared/upload/uploader/uploader-error.model';
import { Router } from '@angular/router';
/**
diff --git a/src/app/my-dspace-page/my-dspace-page.module.ts b/src/app/my-dspace-page/my-dspace-page.module.ts
index 2ccddd87f7..6ad50af96a 100644
--- a/src/app/my-dspace-page/my-dspace-page.module.ts
+++ b/src/app/my-dspace-page/my-dspace-page.module.ts
@@ -14,6 +14,7 @@ import { MyDSpaceNewSubmissionDropdownComponent } from './my-dspace-new-submissi
import { MyDSpaceNewExternalDropdownComponent } from './my-dspace-new-submission/my-dspace-new-external-dropdown/my-dspace-new-external-dropdown.component';
import { ThemedMyDSpacePageComponent } from './themed-my-dspace-page.component';
import { SearchModule } from '../shared/search/search.module';
+import { UploadModule } from '../shared/upload/upload.module';
const DECLARATIONS = [
MyDSpacePageComponent,
@@ -30,7 +31,8 @@ const DECLARATIONS = [
SharedModule,
SearchModule,
MyDspacePageRoutingModule,
- MyDspaceSearchModule.withEntryComponents()
+ MyDspaceSearchModule.withEntryComponents(),
+ UploadModule,
],
declarations: DECLARATIONS,
providers: [
diff --git a/src/app/my-dspace-page/my-dspace-search.module.ts b/src/app/my-dspace-page/my-dspace-search.module.ts
index a0fa76fafa..1ce39991b3 100644
--- a/src/app/my-dspace-page/my-dspace-search.module.ts
+++ b/src/app/my-dspace-page/my-dspace-search.module.ts
@@ -17,9 +17,16 @@ import { PoolSearchResultDetailElementComponent } from '../shared/object-detail/
import { ClaimedApprovedSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-approved-search-result/claimed-approved-search-result-list-element.component';
import { ClaimedDeclinedSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-search-result/claimed-declined-search-result-list-element.component';
import { ResearchEntitiesModule } from '../entity-groups/research-entities/research-entities.module';
+import { ItemSubmitterComponent } from '../shared/object-collection/shared/mydspace-item-submitter/item-submitter.component';
+import { ItemDetailPreviewComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component';
+import { ItemDetailPreviewFieldComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
+import { ItemListPreviewComponent } from '../shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component';
+import { 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';
const ENTRY_COMPONENTS = [
- // put only entry components that use custom decorator
WorkspaceItemSearchResultListElementComponent,
WorkflowItemSearchResultListElementComponent,
ClaimedSearchResultListElementComponent,
@@ -31,7 +38,17 @@ const ENTRY_COMPONENTS = [
WorkflowItemSearchResultDetailElementComponent,
ClaimedTaskSearchResultDetailElementComponent,
PoolSearchResultDetailElementComponent,
- ItemSearchResultListElementSubmissionComponent
+ ItemSearchResultListElementSubmissionComponent,
+];
+
+const DECLARATIONS = [
+ ...ENTRY_COMPONENTS,
+ ItemSubmitterComponent,
+ ItemDetailPreviewComponent,
+ ItemDetailPreviewFieldComponent,
+ ItemListPreviewComponent,
+ ThemedItemListPreviewComponent,
+ MyDSpaceItemStatusComponent,
];
@NgModule({
@@ -39,10 +56,12 @@ const ENTRY_COMPONENTS = [
CommonModule,
SharedModule,
MyDspacePageRoutingModule,
- ResearchEntitiesModule.withEntryComponents()
+ MyDSpaceActionsModule,
+ ResearchEntitiesModule.withEntryComponents(),
+ JournalEntitiesModule.withEntryComponents(),
],
declarations: [
- ...ENTRY_COMPONENTS
+ ...DECLARATIONS,
]
})
diff --git a/src/app/navbar/navbar.component.scss b/src/app/navbar/navbar.component.scss
index fed88c5c68..441ee82c96 100644
--- a/src/app/navbar/navbar.component.scss
+++ b/src/app/navbar/navbar.component.scss
@@ -1,5 +1,5 @@
nav.navbar {
- border-bottom: 1px var(--bs-gray-400) solid;
+ border-bottom: 1px var(--ds-header-navbar-border-bottom-color) solid;
align-items: baseline;
}
diff --git a/src/app/navbar/navbar.module.ts b/src/app/navbar/navbar.module.ts
index af2bf036bd..de3244099d 100644
--- a/src/app/navbar/navbar.module.ts
+++ b/src/app/navbar/navbar.module.ts
@@ -21,6 +21,7 @@ const effects = [
const ENTRY_COMPONENTS = [
// put only entry components that use custom decorator
NavbarSectionComponent,
+ ExpandableNavbarSectionComponent,
ThemedExpandableNavbarSectionComponent,
];
@@ -34,11 +35,9 @@ const ENTRY_COMPONENTS = [
CoreModule.forRoot()
],
declarations: [
+ ...ENTRY_COMPONENTS,
NavbarComponent,
ThemedNavbarComponent,
- NavbarSectionComponent,
- ExpandableNavbarSectionComponent,
- ThemedExpandableNavbarSectionComponent,
],
providers: [],
exports: [
diff --git a/src/app/register-email-form/register-email-form.component.spec.ts b/src/app/register-email-form/register-email-form.component.spec.ts
index bac922c73b..cf3b4b13d2 100644
--- a/src/app/register-email-form/register-email-form.component.spec.ts
+++ b/src/app/register-email-form/register-email-form.component.spec.ts
@@ -95,6 +95,10 @@ describe('RegisterEmailComponent', () => {
comp.form.patchValue({email: 'valid@email.org'});
expect(comp.form.invalid).toBeFalse();
});
+ it('should be valid when uppercase letters are used', () => {
+ comp.form.patchValue({email: 'VALID@email.org'});
+ expect(comp.form.invalid).toBeFalse();
+ });
});
describe('register', () => {
it('should send a registration to the service and on success display a message and return to home', () => {
diff --git a/src/app/register-email-form/register-email-form.component.ts b/src/app/register-email-form/register-email-form.component.ts
index ced87b9e75..561bd53e67 100644
--- a/src/app/register-email-form/register-email-form.component.ts
+++ b/src/app/register-email-form/register-email-form.component.ts
@@ -79,7 +79,9 @@ export class RegisterEmailFormComponent implements OnInit {
this.form = this.formBuilder.group({
email: new FormControl('', {
validators: [Validators.required,
- Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$')
+ // Regex pattern borrowed from HTML5 specs for a valid email address:
+ // https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
+ Validators.pattern('^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$')
],
})
});
diff --git a/src/app/search-page/search-page.module.ts b/src/app/search-page/search-page.module.ts
index 758eca15c0..19fd9bd309 100644
--- a/src/app/search-page/search-page.module.ts
+++ b/src/app/search-page/search-page.module.ts
@@ -7,7 +7,6 @@ import { ConfigurationSearchPageGuard } from './configuration-search-page.guard'
import { SearchTrackerComponent } from './search-tracker.component';
import { StatisticsModule } from '../statistics/statistics.module';
import { SearchPageComponent } from './search-page.component';
-import { SidebarFilterService } from '../shared/sidebar/filter/sidebar-filter.service';
import { SearchFilterService } from '../core/shared/search/search-filter.service';
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module';
@@ -34,7 +33,6 @@ const components = [
declarations: components,
providers: [
SidebarService,
- SidebarFilterService,
SearchFilterService,
ConfigurationSearchPageGuard,
SearchConfigurationService
diff --git a/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts b/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts
new file mode 100644
index 0000000000..27c883099d
--- /dev/null
+++ b/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts
@@ -0,0 +1,33 @@
+import { CollectionDropdownComponent, CollectionListEntry } from './collection-dropdown.component';
+import { ThemedComponent } from '../theme-support/themed.component';
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+
+@Component({
+ selector: 'ds-themed-collection-dropdown',
+ styleUrls: [],
+ templateUrl: '../../shared/theme-support/themed.component.html',
+})
+export class ThemedCollectionDropdownComponent extends ThemedComponent {
+
+ @Input() entityType: string;
+
+ @Output() searchComplete = new EventEmitter();
+
+ @Output() theOnlySelectable = new EventEmitter();
+
+ @Output() selectionChange = new EventEmitter();
+
+ protected inAndOutputNames: (keyof CollectionDropdownComponent & keyof this)[] = ['entityType', 'searchComplete', 'theOnlySelectable', 'selectionChange'];
+
+ protected getComponentName(): string {
+ return 'CollectionDropdownComponent';
+ }
+
+ protected importThemedComponent(themeName: string): Promise {
+ return import(`../../../themes/${themeName}/app/shared/collection-dropdown/collection-dropdown.component`);
+ }
+
+ protected importUnthemedComponent(): Promise {
+ return import(`./collection-dropdown.component`);
+ }
+}
diff --git a/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.ts
index 29be240753..23dfca8616 100644
--- a/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.ts
+++ b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.ts
@@ -17,8 +17,8 @@ import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.mod
import { ResourceType } from '../../../../core/shared/resource-type';
import { hasValue, isNotEmpty } from '../../../empty.util';
import { NotificationsService } from '../../../notifications/notifications.service';
-import { UploaderOptions } from '../../../uploader/uploader-options.model';
-import { UploaderComponent } from '../../../uploader/uploader.component';
+import { UploaderOptions } from '../../../upload/uploader/uploader-options.model';
+import { UploaderComponent } from '../../../upload/uploader/uploader.component';
import { Operation } from 'fast-json-patch';
import { NoContent } from '../../../../core/shared/NoContent.model';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
diff --git a/src/app/shared/comcol/comcol.module.ts b/src/app/shared/comcol/comcol.module.ts
index 094387929a..efbcedf2c6 100644
--- a/src/app/shared/comcol/comcol.module.ts
+++ b/src/app/shared/comcol/comcol.module.ts
@@ -15,6 +15,7 @@ import { ThemedComcolPageBrowseByComponent } from './comcol-page-browse-by/theme
import { ComcolRoleComponent } from './comcol-forms/edit-comcol-page/comcol-role/comcol-role.component';
import { SharedModule } from '../shared.module';
import { FormModule } from '../form/form.module';
+import { UploadModule } from '../upload/upload.module';
const COMPONENTS = [
ComcolPageContentComponent,
@@ -28,9 +29,7 @@ const COMPONENTS = [
ComcolPageBrowseByComponent,
ThemedComcolPageBrowseByComponent,
ComcolRoleComponent,
-
ThemedComcolPageHandleComponent
-
];
@NgModule({
@@ -40,10 +39,12 @@ const COMPONENTS = [
imports: [
CommonModule,
FormModule,
- SharedModule
+ SharedModule,
+ UploadModule,
],
exports: [
- ...COMPONENTS
+ ...COMPONENTS,
+ UploadModule,
]
})
export class ComcolModule { }
diff --git a/src/app/shared/cookies/browser-klaro.service.ts b/src/app/shared/cookies/browser-klaro.service.ts
index 56e371242b..2b09c0bf15 100644
--- a/src/app/shared/cookies/browser-klaro.service.ts
+++ b/src/app/shared/cookies/browser-klaro.service.ts
@@ -1,5 +1,4 @@
-import { Injectable } from '@angular/core';
-import { setup, show } from 'klaro/dist/klaro-no-translations';
+import { Inject, Injectable, InjectionToken } from '@angular/core';
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
import { AuthService } from '../../core/auth/auth.service';
import { TranslateService } from '@ngx-translate/core';
@@ -43,6 +42,17 @@ const cookiePurposeMessagePrefix = 'cookies.consent.purpose.';
*/
const updateDebounce = 300;
+/**
+ * By using this injection token instead of importing directly we can keep Klaro out of the main bundle
+ */
+const LAZY_KLARO = new InjectionToken>(
+ 'Lazily loaded Klaro',
+ {
+ providedIn: 'root',
+ factory: async () => (await import('klaro/dist/klaro-no-translations')),
+ }
+);
+
/**
* Browser implementation for the KlaroService, representing a service for handling Klaro consent preferences and UI
*/
@@ -65,7 +75,9 @@ export class BrowserKlaroService extends KlaroService {
private authService: AuthService,
private ePersonService: EPersonDataService,
private configService: ConfigurationDataService,
- private cookieService: CookieService) {
+ private cookieService: CookieService,
+ @Inject(LAZY_KLARO) private lazyKlaro: Promise,
+ ) {
super();
}
@@ -103,7 +115,6 @@ export class BrowserKlaroService extends KlaroService {
if (hideRegistrationVerification) {
servicesToHideArray.push(CAPTCHA_NAME);
}
- console.log(servicesToHideArray);
return servicesToHideArray;
})
);
@@ -135,8 +146,7 @@ export class BrowserKlaroService extends KlaroService {
this.translateConfiguration();
this.klaroConfig.services = this.filterConfigServices(servicesToHide);
-
- setup(this.klaroConfig);
+ this.lazyKlaro.then(({ setup }) => setup(this.klaroConfig));
});
}
@@ -220,7 +230,7 @@ export class BrowserKlaroService extends KlaroService {
* Show the cookie consent form
*/
showSettings() {
- show(this.klaroConfig);
+ this.lazyKlaro.then(({show}) => show(this.klaroConfig));
}
/**
diff --git a/src/app/shared/dso-page/dso-page.module.ts b/src/app/shared/dso-page/dso-page.module.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts
index ab48d058ca..cc1f9822d6 100644
--- a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts
+++ b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts
@@ -53,8 +53,9 @@ export class AuthorizedCollectionSelectorComponent extends DSOSelectorComponent
* Perform a search for authorized collections with the current query and page
* @param query Query to search objects for
* @param page Page to retrieve
+ * @param useCache Whether or not to use the cache
*/
- search(query: string, page: number): Observable>>> {
+ search(query: string, page: number, useCache: boolean = true): Observable>>> {
let searchListService$: Observable>> = null;
const findOptions: FindListOptions = {
currentPage: page,
@@ -69,7 +70,7 @@ export class AuthorizedCollectionSelectorComponent extends DSOSelectorComponent
findOptions);
} else {
searchListService$ = this.collectionDataService
- .getAuthorizedCollection(query, findOptions, true, false, followLink('parentCommunity'));
+ .getAuthorizedCollection(query, findOptions, useCache, false, followLink('parentCommunity'));
}
return searchListService$.pipe(
getFirstCompletedRemoteData(),
diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html
index 8abb8ad558..c4f5dbc4cd 100644
--- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html
+++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html
@@ -21,12 +21,12 @@
+ (click)="onClick(listEntry)" #listEntryElement>
+ [linkType]=linkTypes.None [context]="getContext(listEntry['id'])">
[]> = new BehaviorSubject(null);
+ listEntries$: BehaviorSubject = new BehaviorSubject(null);
/**
* The current page to load
@@ -116,11 +124,6 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
*/
linkTypes = CollectionElementLinkType;
- /**
- * Track whether the element has the mouse over it
- */
- isMouseOver = false;
-
/**
* Array to track all subscriptions and unsubscribe them onDestroy
* @type {Array}
@@ -182,24 +185,28 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
})
);
})
- ).subscribe((rd) => {
- this.loading = false;
- if (rd.hasSucceeded) {
- const currentEntries = this.listEntries$.getValue();
- if (hasNoValue(currentEntries)) {
- this.listEntries$.next(rd.payload.page);
- } else {
- this.listEntries$.next([...currentEntries, ...rd.payload.page]);
- }
- // Check if there are more pages available after the current one
- this.hasNextPage = rd.payload.totalElements > this.listEntries$.getValue().length;
- } else {
- this.listEntries$.next(null);
- this.hasNextPage = false;
- }
+ ).subscribe((rd: RemoteData>>) => {
+ this.updateList(rd);
}));
}
+ updateList(rd: RemoteData>>) {
+ this.loading = false;
+ const currentEntries = this.listEntries$.getValue();
+ if (rd.hasSucceeded) {
+ if (hasNoValue(currentEntries)) {
+ this.listEntries$.next(rd.payload.page);
+ } else {
+ this.listEntries$.next([...currentEntries, ...rd.payload.page]);
+ }
+ // Check if there are more pages available after the current one
+ this.hasNextPage = rd.payload.totalElements > this.listEntries$.getValue().length;
+ } else {
+ this.listEntries$.next([...(hasNoValue(currentEntries) ? [] : this.listEntries$.getValue()), new ListableNotificationObject(NotificationType.Error, 'dso-selector.results-could-not-be-retrieved', LISTABLE_NOTIFICATION_OBJECT.value)]);
+ this.hasNextPage = false;
+ }
+ }
+
/**
* Get a query to send for retrieving the current DSO
*/
@@ -211,8 +218,9 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
* Perform a search for the current query and page
* @param query Query to search objects for
* @param page Page to retrieve
+ * @param useCache Whether or not to use the cache
*/
- search(query: string, page: number): Observable>>> {
+ search(query: string, page: number, useCache: boolean = true): Observable>>> {
return this.searchService.search(
new PaginatedSearchOptions({
query: query,
@@ -220,7 +228,9 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
pagination: Object.assign({}, this.defaultPagination, {
currentPage: page
})
- })
+ }),
+ null,
+ useCache,
).pipe(
getFirstCompletedRemoteData()
);
@@ -262,7 +272,28 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
}
- getName(searchResult: SearchResult): string {
- return this.dsoNameService.getName(searchResult.indexableObject);
+ /**
+ * Handles the user clicks on the {@link ListableObject}s. When the {@link listableObject} is a
+ * {@link ListableObject} it will retry the error when the user clicks it. Otherwise it will emit the {@link onSelect}.
+ *
+ * @param listableObject The {@link ListableObject} to evaluate
+ */
+ onClick(listableObject: ListableObject): void {
+ if (hasValue((listableObject as SearchResult).indexableObject)) {
+ this.onSelect.emit((listableObject as SearchResult).indexableObject);
+ } else {
+ this.listEntries$.value.pop();
+ this.hasNextPage = true;
+ this.search(this.input.value ? this.input.value : '', this.currentPage$.value, false).pipe(
+ getFirstCompletedRemoteData(),
+ ).subscribe((rd: RemoteData>>) => {
+ this.updateList(rd);
+ });
+ }
+ }
+
+ getName(listableObject: ListableObject): string {
+ return hasValue((listableObject as SearchResult).indexableObject) ?
+ this.dsoNameService.getName((listableObject as SearchResult).indexableObject) : null;
}
}
diff --git a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html
index 84fdd34c01..4a22672988 100644
--- a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html
+++ b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html
@@ -9,7 +9,7 @@
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
index e0e519aaa9..925fabe5e0 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
@@ -79,6 +79,8 @@ import { FormService } from '../../form.service';
import { SubmissionService } from '../../../../submission/submission.service';
import { FormBuilderService } from '../form-builder.service';
import { NgxMaskModule } from 'ngx-mask';
+import { APP_CONFIG } from '../../../../../config/app-config.interface';
+import { environment } from '../../../../../environments/environment';
function getMockDsDynamicTypeBindRelationService(): DsDynamicTypeBindRelationService {
return jasmine.createSpyObj('DsDynamicTypeBindRelationService', {
@@ -230,7 +232,8 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
findById: () => observableOf(createSuccessfulRemoteDataObject(testWSI))
}
},
- { provide: NgZone, useValue: new NgZone({}) }
+ { provide: NgZone, useValue: new NgZone({}) },
+ { provide: APP_CONFIG, useValue: environment }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents().then(() => {
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
index 812735e69c..77ce65675a 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
@@ -4,7 +4,7 @@ import {
Component,
ComponentFactoryResolver,
ContentChildren,
- EventEmitter,
+ EventEmitter, Inject,
Input,
NgZone,
OnChanges,
@@ -118,6 +118,8 @@ import { RelationshipOptions } from '../models/relationship-options.model';
import { FormBuilderService } from '../form-builder.service';
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './ds-dynamic-form-constants';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
+import { APP_CONFIG, AppConfig } from '../../../../../config/app-config.interface';
+import { itemLinksToFollow } from '../../../utils/relation-query.utils';
export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type | null {
switch (model.type) {
@@ -231,6 +233,11 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
private showErrorMessagesPreviousStage: boolean;
+ /**
+ * Determines whether to request embedded thumbnail.
+ */
+ fetchThumbnail: boolean;
+
get componentType(): Type | null {
return dsDynamicFormControlMapFn(this.model);
}
@@ -253,9 +260,11 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
private ref: ChangeDetectorRef,
private formService: FormService,
private formBuilderService: FormBuilderService,
- private submissionService: SubmissionService
+ private submissionService: SubmissionService,
+ @Inject(APP_CONFIG) protected appConfig: AppConfig,
) {
super(ref, componentFactoryResolver, layoutService, validationService, dynamicFormComponentService, relationService);
+ this.fetchThumbnail = this.appConfig.browseBy.showThumbnails;
}
/**
@@ -285,7 +294,6 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
followLink('rightItem'),
followLink('relationshipType')
);
-
relationshipsRD$.pipe(
getFirstSucceededRemoteDataPayload(),
getPaginatedListPayload()
@@ -317,8 +325,10 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
}
if (hasValue(this.value) && this.value.isVirtual) {
- const relationship$ = this.relationshipService.findById(this.value.virtualValue, true, true, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType'))
- .pipe(
+ const relationship$ = this.relationshipService.findById(this.value.virtualValue,
+ true,
+ true,
+ ... itemLinksToFollow(this.fetchThumbnail)).pipe(
getAllSucceededRemoteData(),
getRemoteDataPayload());
this.relationshipValue$ = observableCombineLatest([this.item$.pipe(take(1)), relationship$]).pipe(
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.scss
index 1146e55750..8b13789179 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.scss
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.scss
@@ -1,3 +1 @@
-span.text-contents{
- padding: var(--bs-btn-padding-y) 0;
-}
+
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html
index ff91b18e1c..64ace2296e 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html
@@ -1,12 +1,12 @@
-
+
-
+
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.spec.ts
index d733f503bb..5a53599f91 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.spec.ts
@@ -69,7 +69,7 @@ describe('ExistingRelationListElementComponent', () => {
providers: [
{ provide: SelectableListService, useValue: selectionService },
{ provide: Store, useValue: store },
- { provide: SubmissionService, useClass: SubmissionServiceStub },
+ { provide: SubmissionService, useClass: SubmissionServiceStub }
],
schemas: [NO_ERRORS_SCHEMA]
})
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts
index dd97bb74ab..27029ff2be 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts
@@ -20,7 +20,7 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent } from '../../../../../testing/utils.test';
import { DynamicLookupNameModel } from './dynamic-lookup-name.model';
-import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive';
+import { AuthorityConfidenceStateDirective } from '../../../../directives/authority-confidence-state.directive';
import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe';
import {
mockDynamicFormLayoutService,
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.spec.ts
index 1102ae2e74..cf417145a7 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.spec.ts
@@ -21,11 +21,11 @@ import { DsDynamicOneboxComponent } from './dynamic-onebox.component';
import { DynamicOneboxModel } from './dynamic-onebox.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { createTestComponent } from '../../../../../testing/utils.test';
-import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive';
+import { AuthorityConfidenceStateDirective } from '../../../../directives/authority-confidence-state.directive';
import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createSuccessfulRemoteDataObject$ } from '../../../../../remote-data.utils';
-import { VocabularyTreeviewComponent } from '../../../../../vocabulary-treeview/vocabulary-treeview.component';
+import { VocabularyTreeviewComponent } from '../../../../vocabulary-treeview/vocabulary-treeview.component';
import {
mockDynamicFormLayoutService,
mockDynamicFormValidationService
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts
index 9d2799177c..008328bf73 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts
@@ -30,7 +30,7 @@ import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/
import { PageInfo } from '../../../../../../core/shared/page-info.model';
import { DsDynamicVocabularyComponent } from '../dynamic-vocabulary.component';
import { Vocabulary } from '../../../../../../core/submission/vocabularies/models/vocabulary.model';
-import { VocabularyTreeviewComponent } from '../../../../../vocabulary-treeview/vocabulary-treeview.component';
+import { VocabularyTreeviewComponent } from '../../../../vocabulary-treeview/vocabulary-treeview.component';
import { VocabularyEntryDetail } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
index 83baeaaeaa..733758fd27 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
@@ -16,7 +16,7 @@ import { FormFieldModel } from '../../../models/form-field.model';
import { FormBuilderService } from '../../../form-builder.service';
import { FormService } from '../../../../form.service';
import { FormComponent } from '../../../../form.component';
-import { Chips } from '../../../../../chips/models/chips.model';
+import { Chips } from '../../../../chips/models/chips.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { DsDynamicInputModel } from '../ds-dynamic-input.model';
import { createTestComponent } from '../../../../../testing/utils.test';
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
index fe495419f0..fd111e44c2 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
@@ -19,10 +19,10 @@ import { FormBuilderService } from '../../../form-builder.service';
import { SubmissionFormsModel } from '../../../../../../core/config/models/config-submission-forms.model';
import { FormService } from '../../../../form.service';
import { FormComponent } from '../../../../form.component';
-import { Chips } from '../../../../../chips/models/chips.model';
+import { Chips } from '../../../../chips/models/chips.model';
import { hasValue, isEmpty, isNotEmpty, isNotNull } from '../../../../../empty.util';
import { shrinkInOut } from '../../../../../animations/shrink';
-import { ChipsItem } from '../../../../../chips/models/chips-item.model';
+import { ChipsItem } from '../../../../chips/models/chips-item.model';
import { hasOnlyEmptyProperties } from '../../../../../object.util';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts
index 7b2c416699..162d9c3cec 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts
@@ -13,7 +13,7 @@ import { VocabularyService } from '../../../../../../core/submission/vocabularie
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { DsDynamicTagComponent } from './dynamic-tag.component';
import { DynamicTagModel } from './dynamic-tag.model';
-import { Chips } from '../../../../../chips/models/chips.model';
+import { Chips } from '../../../../chips/models/chips.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent } from '../../../../../testing/utils.test';
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts
index 4978af970b..1c015be747 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts
@@ -9,7 +9,7 @@ import isEqual from 'lodash/isEqual';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { DynamicTagModel } from './dynamic-tag.model';
-import { Chips } from '../../../../../chips/models/chips.model';
+import { Chips } from '../../../../chips/models/chips.model';
import { hasValue, isNotEmpty } from '../../../../../empty.util';
import { environment } from '../../../../../../../environments/environment';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts
index 3c9b575027..cfffc5ddb7 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts
@@ -1,4 +1,6 @@
-import { DsDynamicLookupRelationExternalSourceTabComponent } from './dynamic-lookup-relation-external-source-tab.component';
+import {
+ DsDynamicLookupRelationExternalSourceTabComponent
+} from './dynamic-lookup-relation-external-source-tab.component';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { VarDirective } from '../../../../../utils/var.directive';
import { TranslateModule } from '@ngx-translate/core';
@@ -6,7 +8,7 @@ import { RouterTestingModule } from '@angular/router/testing';
import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
import { PaginatedSearchOptions } from '../../../../../search/models/paginated-search-options.model';
import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service';
-import { of as observableOf } from 'rxjs';
+import { of as observableOf, EMPTY } from 'rxjs';
import {
createFailedRemoteDataObject$,
createPendingRemoteDataObject$,
@@ -22,11 +24,13 @@ import { SelectableListService } from '../../../../../object-list/selectable-lis
import { Item } from '../../../../../../core/shared/item.model';
import { Collection } from '../../../../../../core/shared/collection.model';
import { RelationshipOptions } from '../../../models/relationship-options.model';
-import { ExternalSourceEntryImportModalComponent } from './external-source-entry-import-modal/external-source-entry-import-modal.component';
import { createPaginatedList } from '../../../../../testing/utils.test';
import { PaginationService } from '../../../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub';
import { ItemType } from '../../../../../../core/shared/item-relationships/item-type.model';
+import {
+ ThemedExternalSourceEntryImportModalComponent
+} from './external-source-entry-import-modal/themed-external-source-entry-import-modal.component';
describe('DsDynamicLookupRelationExternalSourceTabComponent', () => {
let component: DsDynamicLookupRelationExternalSourceTabComponent;
@@ -187,12 +191,13 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => {
describe('import', () => {
beforeEach(() => {
- spyOn(modalService, 'open').and.returnValue(Object.assign({ componentInstance: Object.assign({ importedObject: new EventEmitter() }) }));
+ spyOn(modalService, 'open').and.returnValue(Object.assign({ componentInstance: Object.assign({ importedObject: new EventEmitter(), compRef$: EMPTY }) }));
+ component.modalRef = modalService.open(ThemedExternalSourceEntryImportModalComponent, { size: 'lg', container: 'ds-dynamic-lookup-relation-modal' });
component.import(externalEntries[0]);
});
it('should open a new ExternalSourceEntryImportModalComponent', () => {
- expect(modalService.open).toHaveBeenCalledWith(ExternalSourceEntryImportModalComponent, jasmine.any(Object));
+ expect(modalService.open).toHaveBeenCalledWith(ThemedExternalSourceEntryImportModalComponent, jasmine.any(Object));
});
});
});
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts
index e5ea98e537..22fcc4e8bb 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts
@@ -1,4 +1,4 @@
-import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
+import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ComponentRef } from '@angular/core';
import { SEARCH_CONFIG_SERVICE } from '../../../../../../my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service';
import { Router } from '@angular/router';
@@ -16,7 +16,8 @@ import { PaginationComponentOptions } from '../../../../../pagination/pagination
import { RelationshipOptions } from '../../../models/relationship-options.model';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ExternalSourceEntryImportModalComponent } from './external-source-entry-import-modal/external-source-entry-import-modal.component';
-import { hasValue } from '../../../../../empty.util';
+import { ThemedExternalSourceEntryImportModalComponent } from './external-source-entry-import-modal/themed-external-source-entry-import-modal.component';
+import { hasValue, hasValueOperator } from '../../../../../empty.util';
import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service';
import { Item } from '../../../../../../core/shared/item.model';
import { Collection } from '../../../../../../core/shared/collection.model';
@@ -114,9 +115,9 @@ export class DsDynamicLookupRelationExternalSourceTabComponent implements OnInit
modalRef: NgbModalRef;
/**
- * Subscription to the modal's importedObject event-emitter
+ * Array to track all subscriptions and unsubscribe them onDestroy
*/
- importObjectSub: Subscription;
+ protected subs: Subscription[] = [];
/**
* The entity types compatible with the given external source
@@ -161,30 +162,40 @@ export class DsDynamicLookupRelationExternalSourceTabComponent implements OnInit
* @param entry The entry to import
*/
import(entry) {
- this.modalRef = this.modalService.open(ExternalSourceEntryImportModalComponent, {
+ this.modalRef = this.modalService.open(ThemedExternalSourceEntryImportModalComponent, {
size: 'lg',
container: 'ds-dynamic-lookup-relation-modal'
});
- const modalComp = this.modalRef.componentInstance;
- modalComp.externalSourceEntry = entry;
- modalComp.item = this.item;
- modalComp.collection = this.collection;
- modalComp.relationship = this.relationship;
- modalComp.label = this.label;
- modalComp.relatedEntityType = this.relatedEntityType;
- this.importObjectSub = modalComp.importedObject.subscribe((object) => {
+
+ const modalComp$ = this.modalRef.componentInstance.compRef$.pipe(
+ hasValueOperator(),
+ map((compRef: ComponentRef) => compRef.instance)
+ );
+
+ this.subs.push(modalComp$.subscribe((modalComp: ExternalSourceEntryImportModalComponent) => {
+ modalComp.externalSourceEntry = entry;
+ modalComp.item = this.item;
+ // modalComp.collection = this.collection;
+ modalComp.relationship = this.relationship;
+ modalComp.label = this.label;
+ modalComp.relatedEntityType = this.relatedEntityType;
+ }));
+
+ this.subs.push(modalComp$.pipe(
+ switchMap((modalComp: ExternalSourceEntryImportModalComponent) => modalComp.importedObject)
+ ).subscribe((object) => {
this.selectableListService.selectSingle(this.listId, object);
this.importedObject.emit(object);
- });
+ }));
}
/**
* Unsubscribe from open subscriptions
*/
ngOnDestroy(): void {
- if (hasValue(this.importObjectSub)) {
- this.importObjectSub.unsubscribe();
- }
+ this.subs
+ .filter((sub) => hasValue(sub))
+ .forEach((sub) => sub.unsubscribe());
}
/**
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component.ts
new file mode 100644
index 0000000000..26e6097c2d
--- /dev/null
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component.ts
@@ -0,0 +1,22 @@
+import { ExternalSourceEntryImportModalComponent } from './external-source-entry-import-modal.component';
+import { ThemedComponent } from '../../../../../../theme-support/themed.component';
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ds-themed-external-source-entry-import-modal',
+ styleUrls: [],
+ templateUrl: '../../../../../../../shared/theme-support/themed.component.html',
+})
+export class ThemedExternalSourceEntryImportModalComponent extends ThemedComponent {
+ protected getComponentName(): string {
+ return 'ExternalSourceEntryImportModalComponent';
+ }
+
+ protected importThemedComponent(themeName: string): Promise {
+ return import(`../../../../../../../../themes/${themeName}/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component`);
+ }
+
+ protected importUnthemedComponent(): Promise {
+ return import(`./external-source-entry-import-modal.component`);
+ }
+}
diff --git a/src/app/shared/form/builder/parsers/field-parser.ts b/src/app/shared/form/builder/parsers/field-parser.ts
index 86a7d99e41..c64de0e3ff 100644
--- a/src/app/shared/form/builder/parsers/field-parser.ts
+++ b/src/app/shared/form/builder/parsers/field-parser.ts
@@ -1,7 +1,12 @@
-import {Inject, InjectionToken} from '@angular/core';
+import { Inject, InjectionToken } from '@angular/core';
import uniqueId from 'lodash/uniqueId';
-import {DynamicFormControlLayout, DynamicFormControlRelation, MATCH_VISIBLE, OR_OPERATOR} from '@ng-dynamic-forms/core';
+import {
+ DynamicFormControlLayout,
+ DynamicFormControlRelation,
+ MATCH_VISIBLE,
+ OR_OPERATOR
+} from '@ng-dynamic-forms/core';
import { hasValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../empty.util';
import { FormFieldModel } from '../models/form-field.model';
@@ -22,6 +27,12 @@ export const SUBMISSION_ID: InjectionToken = new InjectionToken(
export const CONFIG_DATA: InjectionToken = new InjectionToken('configData');
export const INIT_FORM_VALUES: InjectionToken = new InjectionToken('initFormValues');
export const PARSER_OPTIONS: InjectionToken = new InjectionToken('parserOptions');
+/**
+ * This pattern checks that a regex field uses the common ECMAScript format: `/{pattern}/{flags}`, in which the flags
+ * are part of the regex, or a simpler one with only pattern `/{pattern}/` or `{pattern}`.
+ * The regex itself is encapsulated inside a `RegExp` object, that will validate the pattern syntax.
+ */
+export const REGEX_FIELD_VALIDATOR = new RegExp('(\\/?)(.+)\\1([gimsuy]*)', 'i');
export abstract class FieldParser {
@@ -43,7 +54,7 @@ export abstract class FieldParser {
public abstract modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any;
public parse() {
- if (((this.getInitValueCount() > 1 && !this.configData.repeatable) || (this.configData.repeatable))
+ if (((this.getInitValueCount() > 1 && !this.configData.repeatable) || (this.configData.repeatable))
&& (this.configData.input.type !== ParserType.List)
&& (this.configData.input.type !== ParserType.Tag)
) {
@@ -315,6 +326,7 @@ export abstract class FieldParser {
* fields in type bind, made up of a 'match' outcome (make this field visible), an 'operator'
* (OR) and a 'when' condition (the bindValues array).
* @param configuredTypeBindValues array of types from the submission definition (CONFIG_DATA)
+ * @param typeField
* @private
* @return DynamicFormControlRelation[] array with one relation in it, for type bind matching to show a field
*/
@@ -343,8 +355,21 @@ export abstract class FieldParser {
return hasValue(this.configData.input.regex);
}
+ /**
+ * Adds pattern validation to `controlModel`, it uses the encapsulated `configData` to test the regex,
+ * contained in the input config, against the common `ECMAScript` standard validator {@link REGEX_FIELD_VALIDATOR},
+ * and creates an equivalent `RegExp` object that will be used during form-validation against the user-input.
+ * @param controlModel
+ * @protected
+ */
protected addPatternValidator(controlModel) {
- const regex = new RegExp(this.configData.input.regex);
+ const validatorMatcher = this.configData.input.regex.match(REGEX_FIELD_VALIDATOR);
+ let regex;
+ if (validatorMatcher != null && validatorMatcher.length > 3) {
+ regex = new RegExp(validatorMatcher[2], validatorMatcher[3]);
+ } else {
+ regex = new RegExp(this.configData.input.regex);
+ }
controlModel.validators = Object.assign({}, controlModel.validators, { pattern: regex });
controlModel.errorMessages = Object.assign(
{},
diff --git a/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts b/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts
index e7e68a6461..a4c71d1f42 100644
--- a/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts
+++ b/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts
@@ -4,6 +4,7 @@ import { DynamicQualdropModel } from '../ds-dynamic-form-ui/models/ds-dynamic-qu
import { DynamicOneboxModel } from '../ds-dynamic-form-ui/models/onebox/dynamic-onebox.model';
import { DsDynamicInputModel } from '../ds-dynamic-form-ui/models/ds-dynamic-input.model';
import { ParserOptions } from './parser-options';
+import { FieldParser } from './field-parser';
describe('OneboxFieldParser test suite', () => {
let field1: FormFieldModel;
@@ -101,4 +102,51 @@ describe('OneboxFieldParser test suite', () => {
expect(fieldModel instanceof DynamicOneboxModel).toBe(true);
});
+ describe('should handle a DynamicOneboxModel with regex', () => {
+ let regexField: FormFieldModel;
+ let parser: FieldParser;
+ let fieldModel: any;
+
+ beforeEach(() => {
+ regexField = {
+ input: { type: 'onebox', regex: '/[a-z]+/mi' },
+ label: 'Title',
+ mandatory: 'false',
+ repeatable: false,
+ hints: 'Enter the name of the events, if any.',
+ selectableMetadata: [
+ {
+ metadata: 'title',
+ controlledVocabulary: 'EVENTAuthority',
+ closed: false
+ }
+ ],
+ languageCodes: []
+ } as FormFieldModel;
+
+ parser = new OneboxFieldParser(submissionId, regexField, initFormValues, parserOptions);
+ fieldModel = parser.parse();
+ });
+
+ it('should have initialized pattern validator', () => {
+ expect(fieldModel instanceof DynamicOneboxModel).toBe(true);
+ expect(fieldModel.validators).not.toBeNull();
+ expect(fieldModel.validators.pattern).not.toBeNull();
+ });
+
+ it('should mark valid not case sensitive basic characters regex in multiline', () => {
+ let pattern = fieldModel.validators.pattern as RegExp;
+ expect(pattern.test('HELLO')).toBe(true);
+ expect(pattern.test('hello')).toBe(true);
+ expect(pattern.test('hello\nhello\nhello')).toBe(true);
+ expect(pattern.test('HeLlO')).toBe(true);
+ });
+
+ it('should be invalid for non-basic alphabet characters', () => {
+ let pattern = fieldModel.validators.pattern as RegExp;
+ expect(pattern.test('12345')).toBe(false);
+ expect(pattern.test('àèìòùáéíóú')).toBe(false);
+ });
+ });
+
});
diff --git a/src/app/shared/form/builder/parsers/textarea-field-parser.ts b/src/app/shared/form/builder/parsers/textarea-field-parser.ts
index 740e94721f..548ce567c3 100644
--- a/src/app/shared/form/builder/parsers/textarea-field-parser.ts
+++ b/src/app/shared/form/builder/parsers/textarea-field-parser.ts
@@ -5,6 +5,7 @@ import {
DsDynamicTextAreaModel,
DsDynamicTextAreaModelConfig
} from '../ds-dynamic-form-ui/models/ds-dynamic-textarea.model';
+import { environment } from '../../../../../environments/environment';
export class TextareaFieldParser extends FieldParser {
@@ -20,6 +21,7 @@ export class TextareaFieldParser extends FieldParser {
};
textAreaModelConfig.rows = 10;
+ textAreaModelConfig.spellCheck = environment.form.spellCheck;
this.setValues(textAreaModelConfig, fieldValue);
const textAreaModel = new DsDynamicTextAreaModel(textAreaModelConfig, layout);
diff --git a/src/app/shared/chips/chips.component.html b/src/app/shared/form/chips/chips.component.html
similarity index 100%
rename from src/app/shared/chips/chips.component.html
rename to src/app/shared/form/chips/chips.component.html
diff --git a/src/app/shared/chips/chips.component.scss b/src/app/shared/form/chips/chips.component.scss
similarity index 100%
rename from src/app/shared/chips/chips.component.scss
rename to src/app/shared/form/chips/chips.component.scss
diff --git a/src/app/shared/chips/chips.component.spec.ts b/src/app/shared/form/chips/chips.component.spec.ts
similarity index 92%
rename from src/app/shared/chips/chips.component.spec.ts
rename to src/app/shared/form/chips/chips.component.spec.ts
index 6f9b948002..2b8a469bd1 100644
--- a/src/app/shared/chips/chips.component.spec.ts
+++ b/src/app/shared/form/chips/chips.component.spec.ts
@@ -3,17 +3,16 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/c
import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync, } from '@angular/core/testing';
import { Chips } from './models/chips.model';
-import { UploaderService } from '../uploader/uploader.service';
import { ChipsComponent } from './chips.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { By } from '@angular/platform-browser';
-import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
-import { createTestComponent } from '../testing/utils.test';
-import { AuthorityConfidenceStateDirective } from '../authority-confidence/authority-confidence-state.directive';
+import { FormFieldMetadataValueObject } from '../builder/models/form-field-metadata-value.model';
+import { createTestComponent } from '../../testing/utils.test';
+import { AuthorityConfidenceStateDirective } from '../directives/authority-confidence-state.directive';
import { TranslateModule } from '@ngx-translate/core';
-import { ConfidenceType } from '../../core/shared/confidence-type';
+import { ConfidenceType } from '../../../core/shared/confidence-type';
import { SortablejsModule } from 'ngx-sortablejs';
-import { environment } from '../../../environments/environment';
+import { environment } from '../../../../environments/environment';
describe('ChipsComponent test suite', () => {
@@ -41,7 +40,6 @@ describe('ChipsComponent test suite', () => {
providers: [
ChangeDetectorRef,
ChipsComponent,
- UploaderService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
diff --git a/src/app/shared/chips/chips.component.ts b/src/app/shared/form/chips/chips.component.ts
similarity index 94%
rename from src/app/shared/chips/chips.component.ts
rename to src/app/shared/form/chips/chips.component.ts
index 94dfa00791..5166657582 100644
--- a/src/app/shared/chips/chips.component.ts
+++ b/src/app/shared/form/chips/chips.component.ts
@@ -5,7 +5,7 @@ import isObject from 'lodash/isObject';
import { Chips } from './models/chips.model';
import { ChipsItem } from './models/chips-item.model';
-import { UploaderService } from '../uploader/uploader.service';
+import { DragService } from '../../../core/drag.service';
import { TranslateService } from '@ngx-translate/core';
import { Options } from 'sortablejs';
import { BehaviorSubject } from 'rxjs';
@@ -33,7 +33,7 @@ export class ChipsComponent implements OnChanges {
constructor(
private cdr: ChangeDetectorRef,
- private uploaderService: UploaderService,
+ private dragService: DragService,
private translate: TranslateService) {
this.options = {
@@ -76,12 +76,12 @@ export class ChipsComponent implements OnChanges {
onDragStart(index) {
this.isDragging.next(true);
- this.uploaderService.overrideDragOverPage();
+ this.dragService.overrideDragOverPage();
this.dragged = index;
}
onDragEnd(event) {
- this.uploaderService.allowDragOverPage();
+ this.dragService.allowDragOverPage();
this.dragged = -1;
this.chips.updateOrder();
this.isDragging.next(false);
diff --git a/src/app/shared/chips/models/chips-item.model.spec.ts b/src/app/shared/form/chips/models/chips-item.model.spec.ts
similarity index 94%
rename from src/app/shared/chips/models/chips-item.model.spec.ts
rename to src/app/shared/form/chips/models/chips-item.model.spec.ts
index c85ff83c31..27b4840d46 100644
--- a/src/app/shared/chips/models/chips-item.model.spec.ts
+++ b/src/app/shared/form/chips/models/chips-item.model.spec.ts
@@ -1,5 +1,5 @@
import { ChipsItem, ChipsItemIcon } from './chips-item.model';
-import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
+import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
describe('ChipsItem model test suite', () => {
let item: ChipsItem;
diff --git a/src/app/shared/chips/models/chips-item.model.ts b/src/app/shared/form/chips/models/chips-item.model.ts
similarity index 89%
rename from src/app/shared/chips/models/chips-item.model.ts
rename to src/app/shared/form/chips/models/chips-item.model.ts
index 9afeafd479..277e6477ce 100644
--- a/src/app/shared/chips/models/chips-item.model.ts
+++ b/src/app/shared/form/chips/models/chips-item.model.ts
@@ -1,9 +1,9 @@
import isObject from 'lodash/isObject';
import uniqueId from 'lodash/uniqueId';
-import { hasValue, isNotEmpty } from '../../empty.util';
-import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
-import { ConfidenceType } from '../../../core/shared/confidence-type';
-import { PLACEHOLDER_PARENT_METADATA } from '../../form/builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
+import { hasValue, isNotEmpty } from '../../../empty.util';
+import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
+import { ConfidenceType } from '../../../../core/shared/confidence-type';
+import { PLACEHOLDER_PARENT_METADATA } from '../../builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
export interface ChipsItemIcon {
metadata: string;
diff --git a/src/app/shared/chips/models/chips.model.spec.ts b/src/app/shared/form/chips/models/chips.model.spec.ts
similarity index 96%
rename from src/app/shared/chips/models/chips.model.spec.ts
rename to src/app/shared/form/chips/models/chips.model.spec.ts
index a6cf5faf81..c86ff55c6f 100644
--- a/src/app/shared/chips/models/chips.model.spec.ts
+++ b/src/app/shared/form/chips/models/chips.model.spec.ts
@@ -1,6 +1,6 @@
import { Chips } from './chips.model';
import { ChipsItem } from './chips-item.model';
-import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
+import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
describe('Chips model test suite', () => {
let items: any[];
diff --git a/src/app/shared/chips/models/chips.model.ts b/src/app/shared/form/chips/models/chips.model.ts
similarity index 90%
rename from src/app/shared/chips/models/chips.model.ts
rename to src/app/shared/form/chips/models/chips.model.ts
index 2979c3dc09..daeb363d82 100644
--- a/src/app/shared/chips/models/chips.model.ts
+++ b/src/app/shared/form/chips/models/chips.model.ts
@@ -3,11 +3,11 @@ import isEqual from 'lodash/isEqual';
import isObject from 'lodash/isObject';
import { BehaviorSubject } from 'rxjs';
import { ChipsItem, ChipsItemIcon } from './chips-item.model';
-import { hasValue, isNotEmpty } from '../../empty.util';
-import { MetadataIconConfig } from '../../../../config/submission-config.interface';
-import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
-import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
-import { PLACEHOLDER_PARENT_METADATA } from '../../form/builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
+import { hasValue, isNotEmpty } from '../../../empty.util';
+import { MetadataIconConfig } from '../../../../../config/submission-config.interface';
+import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
+import { VocabularyEntry } from '../../../../core/submission/vocabularies/models/vocabulary-entry.model';
+import { PLACEHOLDER_PARENT_METADATA } from '../../builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
export class Chips {
chipsItems: BehaviorSubject;
diff --git a/src/app/shared/authority-confidence/authority-confidence-state.directive.ts b/src/app/shared/form/directives/authority-confidence-state.directive.ts
similarity index 83%
rename from src/app/shared/authority-confidence/authority-confidence-state.directive.ts
rename to src/app/shared/form/directives/authority-confidence-state.directive.ts
index bf6f949575..49eee5ae8f 100644
--- a/src/app/shared/authority-confidence/authority-confidence-state.directive.ts
+++ b/src/app/shared/form/directives/authority-confidence-state.directive.ts
@@ -1,3 +1,11 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+
import {
AfterViewInit,
Directive,
@@ -13,13 +21,13 @@ import {
import findIndex from 'lodash/findIndex';
-import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
-import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
-import { ConfidenceType } from '../../core/shared/confidence-type';
-import { isNotEmpty, isNull } from '../empty.util';
-import { ConfidenceIconConfig } from '../../../config/submission-config.interface';
-import { environment } from '../../../environments/environment';
-import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
+import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
+import { FormFieldMetadataValueObject } from '../builder/models/form-field-metadata-value.model';
+import { ConfidenceType } from '../../../core/shared/confidence-type';
+import { isNotEmpty, isNull } from '../../empty.util';
+import { ConfidenceIconConfig } from '../../../../config/submission-config.interface';
+import { environment } from '../../../../environments/environment';
+import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**
* Directive to add to the element a bootstrap utility class based on metadata confidence value
diff --git a/src/app/shared/form/form.module.ts b/src/app/shared/form/form.module.ts
index 62ab5bd647..61fc7e3c39 100644
--- a/src/app/shared/form/form.module.ts
+++ b/src/app/shared/form/form.module.ts
@@ -2,10 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormComponent } from './form.component';
import { DsDynamicFormComponent } from './builder/ds-dynamic-form-ui/ds-dynamic-form.component';
-import {
- DsDynamicFormControlContainerComponent,
- dsDynamicFormControlMapFn
-} from './builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
+import { DsDynamicFormControlContainerComponent, dsDynamicFormControlMapFn } from './builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
import { DsDynamicListComponent } from './builder/ds-dynamic-form-ui/models/list/dynamic-list.component';
import { DsDynamicLookupComponent } from './builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component';
import { DsDynamicDisabledComponent } from './builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component';
@@ -24,12 +21,25 @@ import { DsDynamicLookupRelationExternalSourceTabComponent } from './builder/ds-
import { SharedModule } from '../shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { SearchModule } from '../search/search.module';
-import { DYNAMIC_FORM_CONTROL_MAP_FN, DynamicFormsCoreModule } from '@ng-dynamic-forms/core';
+import { DYNAMIC_FORM_CONTROL_MAP_FN, DYNAMIC_MATCHER_PROVIDERS, DynamicFormLayoutService, DynamicFormsCoreModule, DynamicFormService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { ExistingMetadataListElementComponent } from './builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
import { ExistingRelationListElementComponent } from './builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component';
import { ExternalSourceEntryImportModalComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component';
import { CustomSwitchComponent } from './builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component';
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
+import { ChipsComponent } from './chips/chips.component';
+import { NumberPickerComponent } from './number-picker/number-picker.component';
+import { AuthorityConfidenceStateDirective } from './directives/authority-confidence-state.directive';
+import { SortablejsModule } from 'ngx-sortablejs';
+import { VocabularyTreeviewComponent } from './vocabulary-treeview/vocabulary-treeview.component';
+import { VocabularyTreeviewService } from './vocabulary-treeview/vocabulary-treeview.service';
+import { FormBuilderService } from './builder/form-builder.service';
+import { DsDynamicTypeBindRelationService } from './builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service';
+import { FormService } from './form.service';
+import { NgxMaskModule } from 'ngx-mask';
+import { ThemedExternalSourceEntryImportModalComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component';
+import { NgbDatepickerModule, NgbTimepickerModule } from '@ng-bootstrap/ng-bootstrap';
+import { CdkTreeModule } from '@angular/cdk/tree';
const COMPONENTS = [
CustomSwitchComponent,
@@ -53,12 +63,21 @@ const COMPONENTS = [
ExistingMetadataListElementComponent,
ExistingRelationListElementComponent,
ExternalSourceEntryImportModalComponent,
- FormComponent
+ FormComponent,
+ ChipsComponent,
+ NumberPickerComponent,
+ VocabularyTreeviewComponent,
+ ThemedExternalSourceEntryImportModalComponent
+];
+
+const DIRECTIVES = [
+ AuthorityConfidenceStateDirective,
];
@NgModule({
declarations: [
- ...COMPONENTS
+ ...COMPONENTS,
+ ...DIRECTIVES,
],
imports: [
CommonModule,
@@ -66,16 +85,30 @@ const COMPONENTS = [
DynamicFormsNGBootstrapUIModule,
SearchModule,
SharedModule,
- TranslateModule
+ TranslateModule,
+ SortablejsModule,
+ NgxMaskModule.forRoot(),
+ NgbDatepickerModule,
+ NgbTimepickerModule,
+ CdkTreeModule,
],
exports: [
- ...COMPONENTS
+ ...COMPONENTS,
+ ...DIRECTIVES,
],
providers: [
{
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
useValue: dsDynamicFormControlMapFn
- }
+ },
+ ...DYNAMIC_MATCHER_PROVIDERS,
+ VocabularyTreeviewService,
+ DynamicFormLayoutService,
+ DynamicFormService,
+ DynamicFormValidationService,
+ FormBuilderService,
+ DsDynamicTypeBindRelationService,
+ FormService,
]
})
export class FormModule {
diff --git a/src/app/shared/number-picker/number-picker.component.html b/src/app/shared/form/number-picker/number-picker.component.html
similarity index 100%
rename from src/app/shared/number-picker/number-picker.component.html
rename to src/app/shared/form/number-picker/number-picker.component.html
diff --git a/src/app/shared/number-picker/number-picker.component.scss b/src/app/shared/form/number-picker/number-picker.component.scss
similarity index 100%
rename from src/app/shared/number-picker/number-picker.component.scss
rename to src/app/shared/form/number-picker/number-picker.component.scss
diff --git a/src/app/shared/number-picker/number-picker.component.spec.ts b/src/app/shared/form/number-picker/number-picker.component.spec.ts
similarity index 96%
rename from src/app/shared/number-picker/number-picker.component.spec.ts
rename to src/app/shared/form/number-picker/number-picker.component.spec.ts
index 0cc073644e..d4484dbfa3 100644
--- a/src/app/shared/number-picker/number-picker.component.spec.ts
+++ b/src/app/shared/form/number-picker/number-picker.component.spec.ts
@@ -2,12 +2,11 @@
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, inject, TestBed, waitForAsync, } from '@angular/core/testing';
-import { UploaderService } from '../uploader/uploader.service';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { By } from '@angular/platform-browser';
import { NumberPickerComponent } from './number-picker.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { createTestComponent } from '../testing/utils.test';
+import { createTestComponent } from '../../testing/utils.test';
describe('NumberPickerComponent test suite', () => {
@@ -33,7 +32,6 @@ describe('NumberPickerComponent test suite', () => {
providers: [
ChangeDetectorRef,
NumberPickerComponent,
- UploaderService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
diff --git a/src/app/shared/number-picker/number-picker.component.ts b/src/app/shared/form/number-picker/number-picker.component.ts
similarity index 98%
rename from src/app/shared/number-picker/number-picker.component.ts
rename to src/app/shared/form/number-picker/number-picker.component.ts
index 465e905713..0df1e050cd 100644
--- a/src/app/shared/number-picker/number-picker.component.ts
+++ b/src/app/shared/form/number-picker/number-picker.component.ts
@@ -1,6 +1,6 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, SimpleChanges, } from '@angular/core';
import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms';
-import { isEmpty } from '../empty.util';
+import { isEmpty } from '../../empty.util';
@Component({
selector: 'ds-number-picker',
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-tree-flat-data-source.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-tree-flat-data-source.ts
similarity index 100%
rename from src/app/shared/vocabulary-treeview/vocabulary-tree-flat-data-source.ts
rename to src/app/shared/form/vocabulary-treeview/vocabulary-tree-flat-data-source.ts
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-tree-flattener.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-tree-flattener.ts
similarity index 100%
rename from src/app/shared/vocabulary-treeview/vocabulary-tree-flattener.ts
rename to src/app/shared/form/vocabulary-treeview/vocabulary-tree-flattener.ts
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview-node.model.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview-node.model.ts
similarity index 88%
rename from src/app/shared/vocabulary-treeview/vocabulary-treeview-node.model.ts
rename to src/app/shared/form/vocabulary-treeview/vocabulary-treeview-node.model.ts
index 63039e6c75..c167328cab 100644
--- a/src/app/shared/vocabulary-treeview/vocabulary-treeview-node.model.ts
+++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview-node.model.ts
@@ -1,7 +1,7 @@
/* eslint-disable max-classes-per-file */
import { BehaviorSubject } from 'rxjs';
-import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
-import { PageInfo } from '../../core/shared/page-info.model';
+import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
+import { PageInfo } from '../../../core/shared/page-info.model';
export const LOAD_MORE = 'LOAD_MORE';
export const LOAD_MORE_ROOT = 'LOAD_MORE_ROOT';
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html
similarity index 100%
rename from src/app/shared/vocabulary-treeview/vocabulary-treeview.component.html
rename to src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.scss b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.scss
similarity index 100%
rename from src/app/shared/vocabulary-treeview/vocabulary-treeview.component.scss
rename to src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.scss
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.spec.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.spec.ts
similarity index 91%
rename from src/app/shared/vocabulary-treeview/vocabulary-treeview.component.spec.ts
rename to src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.spec.ts
index 1bdf4b9df7..cf8fbd8c49 100644
--- a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.spec.ts
+++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.spec.ts
@@ -8,18 +8,18 @@ import { TranslateModule } from '@ngx-translate/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { provideMockStore } from '@ngrx/store/testing';
-import { createTestComponent } from '../testing/utils.test';
+import { createTestComponent } from '../../testing/utils.test';
import { VocabularyTreeviewComponent } from './vocabulary-treeview.component';
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
-import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
+import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { TreeviewFlatNode } from './vocabulary-treeview-node.model';
-import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
-import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
-import { PageInfo } from '../../core/shared/page-info.model';
-import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
-import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
-import { authReducer } from '../../core/auth/auth.reducer';
-import { storeModuleConfig } from '../../app.reducer';
+import { FormFieldMetadataValueObject } from '../builder/models/form-field-metadata-value.model';
+import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
+import { PageInfo } from '../../../core/shared/page-info.model';
+import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
+import { AuthTokenInfo } from '../../../core/auth/models/auth-token-info.model';
+import { authReducer } from '../../../core/auth/auth.reducer';
+import { storeModuleConfig } from '../../../app.reducer';
describe('VocabularyTreeviewComponent test suite', () => {
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts
similarity index 93%
rename from src/app/shared/vocabulary-treeview/vocabulary-treeview.component.ts
rename to src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts
index 9850947f60..408d656f42 100644
--- a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.ts
+++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts
@@ -7,17 +7,17 @@ import { Observable, Subscription } from 'rxjs';
import { select, Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
-import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
-import { hasValue, isEmpty, isNotEmpty } from '../empty.util';
-import { isAuthenticated } from '../../core/auth/selectors';
+import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
+import { hasValue, isEmpty, isNotEmpty } from '../../empty.util';
+import { isAuthenticated } from '../../../core/auth/selectors';
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
import { LOAD_MORE, LOAD_MORE_ROOT, TreeviewFlatNode, TreeviewNode } from './vocabulary-treeview-node.model';
-import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
-import { PageInfo } from '../../core/shared/page-info.model';
-import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
+import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
+import { PageInfo } from '../../../core/shared/page-info.model';
+import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { VocabularyTreeFlattener } from './vocabulary-tree-flattener';
import { VocabularyTreeFlatDataSource } from './vocabulary-tree-flat-data-source';
-import { CoreState } from '../../core/core-state.model';
+import { CoreState } from '../../../core/core-state.model';
/**
* Component that show a hierarchical vocabulary in a tree view
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview.service.spec.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.spec.ts
similarity index 94%
rename from src/app/shared/vocabulary-treeview/vocabulary-treeview.service.spec.ts
rename to src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.spec.ts
index c1c64c80bd..752ef10fee 100644
--- a/src/app/shared/vocabulary-treeview/vocabulary-treeview.service.spec.ts
+++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.spec.ts
@@ -5,15 +5,15 @@ import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-transla
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
-import { VocabularyService } from '../../core/submission/vocabularies/vocabulary.service';
-import { TranslateLoaderMock } from '../mocks/translate-loader.mock';
-import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
+import { VocabularyService } from '../../../core/submission/vocabularies/vocabulary.service';
+import { TranslateLoaderMock } from '../../mocks/translate-loader.mock';
+import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
import { LOAD_MORE_NODE, LOAD_MORE_ROOT_NODE, TreeviewFlatNode, TreeviewNode } from './vocabulary-treeview-node.model';
-import { PageInfo } from '../../core/shared/page-info.model';
-import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
-import { buildPaginatedList } from '../../core/data/paginated-list.model';
-import { createSuccessfulRemoteDataObject } from '../remote-data.utils';
-import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
+import { PageInfo } from '../../../core/shared/page-info.model';
+import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
+import { buildPaginatedList } from '../../../core/data/paginated-list.model';
+import { createSuccessfulRemoteDataObject } from '../../remote-data.utils';
+import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { expand, map, switchMap } from 'rxjs/operators';
import { from as observableFrom } from 'rxjs';
diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview.service.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.ts
similarity index 94%
rename from src/app/shared/vocabulary-treeview/vocabulary-treeview.service.ts
rename to src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.ts
index f04cd1bc28..8804716927 100644
--- a/src/app/shared/vocabulary-treeview/vocabulary-treeview.service.ts
+++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.ts
@@ -10,17 +10,17 @@ import {
TreeviewFlatNode,
TreeviewNode
} from './vocabulary-treeview-node.model';
-import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
-import { VocabularyService } from '../../core/submission/vocabularies/vocabulary.service';
-import { PageInfo } from '../../core/shared/page-info.model';
-import { isEmpty, isNotEmpty } from '../empty.util';
-import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
+import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
+import { VocabularyService } from '../../../core/submission/vocabularies/vocabulary.service';
+import { PageInfo } from '../../../core/shared/page-info.model';
+import { isEmpty, isNotEmpty } from '../../empty.util';
+import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
import {
getFirstSucceededRemoteDataPayload,
getFirstSucceededRemoteListPayload
-} from '../../core/shared/operators';
-import { PaginatedList } from '../../core/data/paginated-list.model';
-import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
+} from '../../../core/shared/operators';
+import { PaginatedList } from '../../../core/data/paginated-list.model';
+import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**
* A service that provides methods to deal with vocabulary tree
diff --git a/src/app/shared/menu/menu.module.ts b/src/app/shared/menu/menu.module.ts
index 1d186a9b7d..c007af517d 100644
--- a/src/app/shared/menu/menu.module.ts
+++ b/src/app/shared/menu/menu.module.ts
@@ -12,8 +12,11 @@ import { ExternalLinkMenuItemComponent } from './menu-item/external-link-menu-it
const COMPONENTS = [
MenuSectionComponent,
MenuComponent,
- LinkMenuItemComponent,
+];
+
+const ENTRY_COMPONENTS = [
TextMenuItemComponent,
+ LinkMenuItemComponent,
OnClickMenuItemComponent,
ExternalLinkMenuItemComponent,
];
@@ -32,10 +35,12 @@ const PROVIDERS = [
...MODULES
],
declarations: [
- ...COMPONENTS
+ ...COMPONENTS,
+ ...ENTRY_COMPONENTS,
],
providers: [
- ...PROVIDERS
+ ...PROVIDERS,
+ ...ENTRY_COMPONENTS,
],
exports: [
...COMPONENTS
diff --git a/src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.html b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.html
similarity index 100%
rename from src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.html
rename to src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.html
diff --git a/src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.scss b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.scss
similarity index 100%
rename from src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.scss
rename to src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.scss
diff --git a/src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts
similarity index 100%
rename from src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts
rename to src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts
diff --git a/src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.ts b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.ts
similarity index 100%
rename from src/app/item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.ts
rename to src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.ts
diff --git a/src/app/shared/mocks/dso-name.service.mock.ts b/src/app/shared/mocks/dso-name.service.mock.ts
index f4947cc860..cf3cf5466b 100644
--- a/src/app/shared/mocks/dso-name.service.mock.ts
+++ b/src/app/shared/mocks/dso-name.service.mock.ts
@@ -6,4 +6,23 @@ export class DSONameServiceMock {
public getName(dso: DSpaceObject) {
return UNDEFINED_NAME;
}
+
+ public getHitHighlights(object: any, dso: DSpaceObject) {
+ if (object.hitHighlights && object.hitHighlights['dc.title']) {
+ return object.hitHighlights['dc.title'][0].value;
+ } else if (object.hitHighlights && object.hitHighlights['organization.legalName']) {
+ return object.hitHighlights['organization.legalName'][0].value;
+ } else if (object.hitHighlights && (object.hitHighlights['person.familyName'] || object.hitHighlights['person.givenName'])) {
+ if (object.hitHighlights['person.familyName'] && object.hitHighlights['person.givenName']) {
+ return `${object.hitHighlights['person.familyName'][0].value}, ${object.hitHighlights['person.givenName'][0].value}`;
+ }
+ if (object.hitHighlights['person.familyName']) {
+ return `${object.hitHighlights['person.familyName'][0].value}`;
+ }
+ if (object.hitHighlights['person.givenName']) {
+ return `${object.hitHighlights['person.givenName'][0].value}`;
+ }
+ }
+ return UNDEFINED_NAME;
+ }
}
diff --git a/src/app/shared/mydspace-actions/mydspace-actions.module.ts b/src/app/shared/mydspace-actions/mydspace-actions.module.ts
new file mode 100644
index 0000000000..68e3a8fb58
--- /dev/null
+++ b/src/app/shared/mydspace-actions/mydspace-actions.module.ts
@@ -0,0 +1,59 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SharedModule } from '../shared.module';
+import { ClaimedTaskActionsApproveComponent } from './claimed-task/approve/claimed-task-actions-approve.component';
+import { ClaimedTaskActionsRejectComponent } from './claimed-task/reject/claimed-task-actions-reject.component';
+import { ClaimedTaskActionsReturnToPoolComponent } from './claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
+import { ClaimedTaskActionsEditMetadataComponent } from './claimed-task/edit-metadata/claimed-task-actions-edit-metadata.component';
+import { ClaimedTaskActionsComponent } from './claimed-task/claimed-task-actions.component';
+import { ClaimedTaskActionsLoaderComponent } from './claimed-task/switcher/claimed-task-actions-loader.component';
+import { ItemActionsComponent } from './item/item-actions.component';
+import { PoolTaskActionsComponent } from './pool-task/pool-task-actions.component';
+import { WorkflowitemActionsComponent } from './workflowitem/workflowitem-actions.component';
+import { WorkspaceitemActionsComponent } from './workspaceitem/workspaceitem-actions.component';
+
+const ENTRY_COMPONENTS = [
+ ClaimedTaskActionsApproveComponent,
+ ClaimedTaskActionsRejectComponent,
+ ClaimedTaskActionsReturnToPoolComponent,
+ ClaimedTaskActionsEditMetadataComponent,
+];
+
+const DECLARATIONS = [
+ ...ENTRY_COMPONENTS,
+ ClaimedTaskActionsComponent,
+ ClaimedTaskActionsLoaderComponent,
+ ItemActionsComponent,
+ PoolTaskActionsComponent,
+ WorkflowitemActionsComponent,
+ WorkspaceitemActionsComponent,
+];
+
+/**
+ * This module contains Item actions used in MyDSpace
+ */
+@NgModule({
+ imports: [
+ CommonModule,
+ SharedModule,
+ ],
+ declarations: [
+ ...DECLARATIONS,
+ ],
+ providers: [
+ ...ENTRY_COMPONENTS,
+ ],
+ exports: [
+ ...DECLARATIONS,
+ ],
+})
+export class MyDSpaceActionsModule {
+
+}
diff --git a/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts
index 44e6a44b70..59fc29424d 100644
--- a/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts
+++ b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts
@@ -55,34 +55,34 @@ describe('MyDSpaceItemStatusComponent', () => {
component.status = MyDspaceItemStatusType.VALIDATION;
fixture.detectChanges();
expect(component.badgeContent).toBe(MyDspaceItemStatusType.VALIDATION);
- expect(component.badgeClass).toBe('text-light badge badge-warning');
+ expect(component.badgeClass).toBe('text-light badge badge-validation');
});
it('should init badge content and class', () => {
component.status = MyDspaceItemStatusType.WAITING_CONTROLLER;
fixture.detectChanges();
expect(component.badgeContent).toBe(MyDspaceItemStatusType.WAITING_CONTROLLER);
- expect(component.badgeClass).toBe('text-light badge badge-info');
+ expect(component.badgeClass).toBe('text-light badge badge-waiting-controller');
});
it('should init badge content and class', () => {
component.status = MyDspaceItemStatusType.WORKSPACE;
fixture.detectChanges();
expect(component.badgeContent).toBe(MyDspaceItemStatusType.WORKSPACE);
- expect(component.badgeClass).toBe('text-light badge badge-primary');
+ expect(component.badgeClass).toBe('text-light badge badge-workspace');
});
it('should init badge content and class', () => {
component.status = MyDspaceItemStatusType.ARCHIVED;
fixture.detectChanges();
expect(component.badgeContent).toBe(MyDspaceItemStatusType.ARCHIVED);
- expect(component.badgeClass).toBe('text-light badge badge-success');
+ expect(component.badgeClass).toBe('text-light badge badge-archived');
});
it('should init badge content and class', () => {
component.status = MyDspaceItemStatusType.WORKFLOW;
fixture.detectChanges();
expect(component.badgeContent).toBe(MyDspaceItemStatusType.WORKFLOW);
- expect(component.badgeClass).toBe('text-light badge badge-info');
+ expect(component.badgeClass).toBe('text-light badge badge-workflow');
});
});
diff --git a/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts
index 917dd45acc..83b2656fbd 100644
--- a/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts
+++ b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts
@@ -34,19 +34,19 @@ export class MyDSpaceItemStatusComponent implements OnInit {
this.badgeClass = 'text-light badge ';
switch (this.status) {
case MyDspaceItemStatusType.VALIDATION:
- this.badgeClass += 'badge-warning';
+ this.badgeClass += 'badge-validation';
break;
case MyDspaceItemStatusType.WAITING_CONTROLLER:
- this.badgeClass += 'badge-info';
+ this.badgeClass += 'badge-waiting-controller';
break;
case MyDspaceItemStatusType.WORKSPACE:
- this.badgeClass += 'badge-primary';
+ this.badgeClass += 'badge-workspace';
break;
case MyDspaceItemStatusType.ARCHIVED:
- this.badgeClass += 'badge-success';
+ this.badgeClass += 'badge-archived';
break;
case MyDspaceItemStatusType.WORKFLOW:
- this.badgeClass += 'badge-info';
+ this.badgeClass += 'badge-workflow';
break;
}
}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
index 57b863a1b1..dc42b033d8 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
@@ -28,13 +28,19 @@ import { ItemSearchResultGridElementComponent } from './item-search-result-grid-
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
+const dcTitle = 'This is just another title ';
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
+ hitHighlights: {
+ 'dc.title': [{
+ value: dcTitle
+ }],
+ },
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
- value: 'This is just another title'
+ value: dcTitle
}
],
'dc.contributor.author': [
@@ -57,6 +63,114 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
]
}
});
+const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'person.familyName': [{
+ value: 'Michel '
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
+ entityType: 'Person',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'Person'
+ }
+ ],
+ 'person.familyName': [
+ {
+ value: 'Michel'
+ }
+ ]
+ }
+ })
+});
+const mockOrgUnit: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'organization.legalName': [{
+ value: 'Science '
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
+ entityType: 'OrgUnit',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'organization.legalName': [
+ {
+ value: 'Science'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'OrgUnit'
+ }
+ ]
+ }
+ })
+});
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
@@ -154,6 +268,41 @@ export function getEntityGridElementTestComponent(component, searchResultWithMet
expect(itemAuthorField).toBeNull();
});
});
+
+ describe('When the item has title', () => {
+ beforeEach(() => {
+ comp.object = mockItemWithMetadata;
+ fixture.detectChanges();
+ });
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.card-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual(dcTitle);
+ });
+ });
+
+ describe('When the item is Person and has title', () => {
+ beforeEach(() => {
+ comp.object = mockPerson;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.card-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Michel ');
+ });
+ });
+
+ describe('When the item is orgUnit and has title', () => {
+ beforeEach(() => {
+ comp.object = mockOrgUnit;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.card-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Science ');
+ });
+ });
});
};
}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
index b5f9c016e4..303e4681a2 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
@@ -42,6 +42,6 @@ export class ItemSearchResultGridElementComponent extends SearchResultGridElemen
ngOnInit(): void {
super.ngOnInit();
this.itemPageRoute = getItemPageRoute(this.dso);
- this.dsoTitle = this.dsoNameService.getName(this.dso);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
}
}
diff --git a/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.html b/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.html
new file mode 100644
index 0000000000..d29199bae3
--- /dev/null
+++ b/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.html
@@ -0,0 +1 @@
+{{ object?.message | translate }}
diff --git a/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.scss b/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.spec.ts b/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.spec.ts
new file mode 100644
index 0000000000..3cf05f7fec
--- /dev/null
+++ b/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.spec.ts
@@ -0,0 +1,43 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ListableNotificationObjectComponent } from './listable-notification-object.component';
+import { NotificationType } from '../../notifications/models/notification-type';
+import { ListableNotificationObject } from './listable-notification-object.model';
+import { By } from '@angular/platform-browser';
+import { TranslateModule } from '@ngx-translate/core';
+
+describe('ListableNotificationObjectComponent', () => {
+ let component: ListableNotificationObjectComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [
+ TranslateModule.forRoot(),
+ ],
+ declarations: [
+ ListableNotificationObjectComponent,
+ ],
+ }).compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ListableNotificationObjectComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ describe('ui', () => {
+ it('should display the given error message', () => {
+ component.object = new ListableNotificationObject(NotificationType.Error, 'test error message');
+ fixture.detectChanges();
+
+ const listableNotificationObject: Element = fixture.debugElement.query(By.css('.alert')).nativeElement;
+ expect(listableNotificationObject.className).toContain(NotificationType.Error);
+ expect(listableNotificationObject.innerHTML).toBe('test error message');
+ });
+ });
+
+ afterEach(() => {
+ fixture.debugElement.nativeElement.remove();
+ });
+});
diff --git a/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.ts b/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.ts
new file mode 100644
index 0000000000..ca23ee76a2
--- /dev/null
+++ b/src/app/shared/object-list/listable-notification-object/listable-notification-object.component.ts
@@ -0,0 +1,21 @@
+import { Component } from '@angular/core';
+import {
+ AbstractListableElementComponent
+} from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
+import { ListableNotificationObject } from './listable-notification-object.model';
+import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator';
+import { ViewMode } from '../../../core/shared/view-mode.model';
+import { LISTABLE_NOTIFICATION_OBJECT } from './listable-notification-object.resource-type';
+
+/**
+ * The component for displaying a notifications inside an object list
+ */
+@listableObjectComponent(ListableNotificationObject, ViewMode.ListElement)
+@listableObjectComponent(LISTABLE_NOTIFICATION_OBJECT.value, ViewMode.ListElement)
+@Component({
+ selector: 'ds-listable-notification-object',
+ templateUrl: './listable-notification-object.component.html',
+ styleUrls: ['./listable-notification-object.component.scss'],
+})
+export class ListableNotificationObjectComponent extends AbstractListableElementComponent {
+}
diff --git a/src/app/shared/object-list/listable-notification-object/listable-notification-object.model.ts b/src/app/shared/object-list/listable-notification-object/listable-notification-object.model.ts
new file mode 100644
index 0000000000..163d9096a2
--- /dev/null
+++ b/src/app/shared/object-list/listable-notification-object/listable-notification-object.model.ts
@@ -0,0 +1,36 @@
+import { ListableObject } from '../../object-collection/shared/listable-object.model';
+import { typedObject } from '../../../core/cache/builders/build-decorators';
+import { TypedObject } from '../../../core/cache/typed-object.model';
+import { LISTABLE_NOTIFICATION_OBJECT } from './listable-notification-object.resource-type';
+import { GenericConstructor } from '../../../core/shared/generic-constructor';
+import { NotificationType } from '../../notifications/models/notification-type';
+import { ResourceType } from '../../../core/shared/resource-type';
+
+/**
+ * Object representing a notification message inside a list of objects
+ */
+@typedObject
+export class ListableNotificationObject extends ListableObject implements TypedObject {
+
+ static type: ResourceType = LISTABLE_NOTIFICATION_OBJECT;
+ type: ResourceType = LISTABLE_NOTIFICATION_OBJECT;
+
+ protected renderTypes: string[];
+
+ constructor(
+ public notificationType: NotificationType = NotificationType.Error,
+ public message: string = 'listable-notification-object.default-message',
+ ...renderTypes: string[]
+ ) {
+ super();
+ this.renderTypes = renderTypes;
+ }
+
+ /**
+ * Method that returns as which type of object this object should be rendered.
+ */
+ getRenderTypes(): (string | GenericConstructor)[] {
+ return [...this.renderTypes, this.constructor as GenericConstructor];
+ }
+
+}
diff --git a/src/app/shared/object-list/listable-notification-object/listable-notification-object.resource-type.ts b/src/app/shared/object-list/listable-notification-object/listable-notification-object.resource-type.ts
new file mode 100644
index 0000000000..ed458126bb
--- /dev/null
+++ b/src/app/shared/object-list/listable-notification-object/listable-notification-object.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from '../../../core/shared/resource-type';
+
+/**
+ * The resource type for {@link ListableNotificationObject}
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const LISTABLE_NOTIFICATION_OBJECT = new ResourceType('listable-notification-object');
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
index 04f1e24d7b..6b40678ded 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
@@ -55,7 +55,7 @@ export class ItemListPreviewComponent implements OnInit {
ngOnInit(): void {
this.showThumbnails = this.appConfig.browseBy.showThumbnails;
- this.dsoTitle = this.dsoNameService.getName(this.item);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.item);
}
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
index d1e6c27ba4..7665b7d64e 100644
--- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
+++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
@@ -13,8 +13,13 @@ import { APP_CONFIG } from '../../../../../../../config/app-config.interface';
let publicationListElementComponent: ItemSearchResultListElementComponent;
let fixture: ComponentFixture;
-
+const dcTitle = 'This is just another title ';
const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'dc.title': [{
+ value: dcTitle
+ }],
+ },
indexableObject:
Object.assign(new Item(), {
bundles: observableOf({}),
@@ -22,7 +27,7 @@ const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResul
'dc.title': [
{
language: 'en_US',
- value: 'This is just another title'
+ value: dcTitle
}
],
'dc.contributor.author': [
@@ -59,7 +64,114 @@ const mockItemWithoutMetadata: ItemSearchResult = Object.assign(new ItemSearchRe
metadata: {}
})
});
-
+const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'person.familyName': [{
+ value: 'Michel '
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: observableOf({}),
+ entityType: 'Person',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'person.familyName': [
+ {
+ value: 'Michel'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'Person'
+ }
+ ]
+ }
+ })
+});
+const mockOrgUnit: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'organization.legalName': [{
+ value: 'Science '
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: observableOf({}),
+ entityType: 'OrgUnit',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'organization.legalName': [
+ {
+ value: 'Science'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'OrgUnit'
+ }
+ ]
+ }
+ })
+});
const environmentUseThumbs = {
browseBy: {
showThumbnails: true
@@ -205,6 +317,42 @@ describe('ItemSearchResultListElementComponent', () => {
});
});
+ describe('When the item has title', () => {
+ beforeEach(() => {
+ publicationListElementComponent.object = mockItemWithMetadata;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.item-list-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual(dcTitle);
+ });
+ });
+
+ describe('When the item is Person and has title', () => {
+ beforeEach(() => {
+ publicationListElementComponent.object = mockPerson;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.item-list-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Michel ');
+ });
+ });
+
+ describe('When the item is orgUnit and has title', () => {
+ beforeEach(() => {
+ publicationListElementComponent.object = mockOrgUnit;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.item-list-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Science ');
+ });
+ });
+
describe('When the item has no title', () => {
beforeEach(() => {
publicationListElementComponent.object = mockItemWithoutMetadata;
diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
index 72120a6b68..e56b7e970a 100644
--- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
+++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
@@ -33,7 +33,7 @@ export class SearchResultListElementComponent, K exten
ngOnInit(): void {
if (hasValue(this.object)) {
this.dso = this.object.indexableObject;
- this.dsoTitle = this.dsoNameService.getName(this.dso);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
}
}
diff --git a/src/app/shared/search-form/scope-selector-modal/scope-selector-modal.component.html b/src/app/shared/search-form/scope-selector-modal/scope-selector-modal.component.html
index bf5c15e963..e7165a9213 100644
--- a/src/app/shared/search-form/scope-selector-modal/scope-selector-modal.component.html
+++ b/src/app/shared/search-form/scope-selector-modal/scope-selector-modal.component.html
@@ -9,7 +9,7 @@
diff --git a/src/app/shared/search/search.module.ts b/src/app/shared/search/search.module.ts
index 426ed82aef..713b9925a6 100644
--- a/src/app/shared/search/search.module.ts
+++ b/src/app/shared/search/search.module.ts
@@ -31,6 +31,7 @@ import { SearchComponent } from './search.component';
import { ThemedSearchComponent } from './themed-search.component';
import { ThemedSearchResultsComponent } from './search-results/themed-search-results.component';
import { ThemedSearchSettingsComponent } from './search-settings/themed-search-settings.component';
+import { NouisliderModule } from 'ng2-nouislider';
const COMPONENTS = [
SearchComponent,
@@ -91,7 +92,8 @@ export const MODELS = [
missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MissingTranslationHelper },
useDefaultLang: true
}),
- SharedModule.withEntryComponents()
+ SharedModule.withEntryComponents(),
+ NouisliderModule,
],
exports: [
...COMPONENTS
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index a97f112e31..095af56c56 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -2,22 +2,15 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { CdkTreeModule } from '@angular/cdk/tree';
import { DragDropModule } from '@angular/cdk/drag-drop';
-
-import { NouisliderModule } from 'ng2-nouislider';
import {
- NgbDatepickerModule,
NgbDropdownModule,
NgbNavModule,
NgbPaginationModule,
- NgbTimepickerModule,
NgbTooltipModule,
NgbTypeaheadModule,
} from '@ng-bootstrap/ng-bootstrap';
import { MissingTranslationHandler, TranslateModule } from '@ngx-translate/core';
-import { NgxPaginationModule } from 'ngx-pagination';
-import { FileUploadModule } from 'ng2-file-upload';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { ConfirmationModalComponent } from './confirmation-modal/confirmation-modal.component';
import {
@@ -29,7 +22,6 @@ import {
import {
ImportBatchSelectorComponent
} from './dso-selector/modal-wrappers/import-batch-selector/import-batch-selector.component';
-import { FileDropzoneNoUploaderComponent } from './file-dropzone-no-uploader/file-dropzone-no-uploader.component';
import { ItemListElementComponent } from './object-list/item-list-element/item-types/item/item-list-element.component';
import { EnumKeysPipe } from './utils/enum-keys-pipe';
import { FileSizePipe } from './utils/file-size-pipe';
@@ -72,33 +64,12 @@ import { TruncatePipe } from './utils/truncate.pipe';
import { TruncatableComponent } from './truncatable/truncatable.component';
import { TruncatableService } from './truncatable/truncatable.service';
import { TruncatablePartComponent } from './truncatable/truncatable-part/truncatable-part.component';
-import { UploaderComponent } from './uploader/uploader.component';
-import { ChipsComponent } from './chips/chips.component';
-import { NumberPickerComponent } from './number-picker/number-picker.component';
import { MockAdminGuard } from './mocks/admin-guard.service.mock';
import { AlertComponent } from './alert/alert.component';
import {
SearchResultDetailElementComponent
} from './object-detail/my-dspace-result-detail-element/search-result-detail-element.component';
-import { ClaimedTaskActionsComponent } from './mydspace-actions/claimed-task/claimed-task-actions.component';
-import { PoolTaskActionsComponent } from './mydspace-actions/pool-task/pool-task-actions.component';
import { ObjectDetailComponent } from './object-detail/object-detail.component';
-import {
- ItemDetailPreviewComponent
-} from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component';
-import {
- MyDSpaceItemStatusComponent
-} from './object-collection/shared/mydspace-item-status/my-dspace-item-status.component';
-import { WorkspaceitemActionsComponent } from './mydspace-actions/workspaceitem/workspaceitem-actions.component';
-import { WorkflowitemActionsComponent } from './mydspace-actions/workflowitem/workflowitem-actions.component';
-import { ItemSubmitterComponent } from './object-collection/shared/mydspace-item-submitter/item-submitter.component';
-import { ItemActionsComponent } from './mydspace-actions/item/item-actions.component';
-import {
- ClaimedTaskActionsApproveComponent
-} from './mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component';
-import {
- ClaimedTaskActionsRejectComponent
-} from './mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component';
import { ObjNgFor } from './utils/object-ngfor.pipe';
import { BrowseByComponent } from './browse-by/browse-by.component';
import {
@@ -110,7 +81,6 @@ import { EmphasizePipe } from './utils/emphasize.pipe';
import { InputSuggestionsComponent } from './input-suggestions/input-suggestions.component';
import { CapitalizePipe } from './utils/capitalize.pipe';
import { ObjectKeysPipe } from './utils/object-keys-pipe';
-import { AuthorityConfidenceStateDirective } from './authority-confidence/authority-confidence-state.directive';
import { LangSwitchComponent } from './lang-switch/lang-switch.component';
import {
PlainTextMetadataListElementComponent
@@ -169,21 +139,8 @@ import {
import {
ThemedEditCollectionSelectorComponent
} from './dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component';
-import {
- ItemListPreviewComponent
-} from './object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component';
-import {
- MetadataFieldWrapperComponent
-} from '../item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component';
-import { MetadataValuesComponent } from '../item-page/field-components/metadata-values/metadata-values.component';
import { RoleDirective } from './roles/role.directive';
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
-import {
- ClaimedTaskActionsReturnToPoolComponent
-} from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
-import {
- ItemDetailPreviewFieldComponent
-} from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
import {
CollectionSearchResultGridElementComponent
} from './object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component';
@@ -222,42 +179,28 @@ import {
} from './object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component';
import { PageWithSidebarComponent } from './sidebar/page-with-sidebar.component';
import { SidebarDropdownComponent } from './sidebar/sidebar-dropdown.component';
-import { SidebarFilterComponent } from './sidebar/filter/sidebar-filter.component';
-import { SidebarFilterSelectedOptionComponent } from './sidebar/filter/sidebar-filter-selected-option.component';
import {
SelectableListItemControlComponent
} from './object-collection/shared/selectable-list-item-control/selectable-list-item-control.component';
import {
ImportableListItemControlComponent
} from './object-collection/shared/importable-list-item-control/importable-list-item-control.component';
-import { ItemVersionsComponent } from './item/item-versions/item-versions.component';
-import { SortablejsModule } from 'ngx-sortablejs';
import { LogInContainerComponent } from './log-in/container/log-in-container.component';
import { LogInShibbolethComponent } from './log-in/methods/shibboleth/log-in-shibboleth.component';
import { LogInPasswordComponent } from './log-in/methods/password/log-in-password.component';
import { LogInComponent } from './log-in/log-in.component';
-import { BundleListElementComponent } from './object-list/bundle-list-element/bundle-list-element.component';
import { MissingTranslationHelper } from './translate/missing-translation.helper';
-import { ItemVersionsNoticeComponent } from './item/item-versions/notice/item-versions-notice.component';
import { FileValidator } from './utils/require-file.validator';
import { FileValueAccessorDirective } from './utils/file-value-accessor.directive';
-import { FileSectionComponent } from '../item-page/simple/field-components/file-section/file-section.component';
import {
ModifyItemOverviewComponent
} from '../item-page/edit-item-page/modify-item-overview/modify-item-overview.component';
-import {
- ClaimedTaskActionsLoaderComponent
-} from './mydspace-actions/claimed-task/switcher/claimed-task-actions-loader.component';
import { ClaimedTaskActionsDirective } from './mydspace-actions/claimed-task/switcher/claimed-task-actions.directive';
-import {
- ClaimedTaskActionsEditMetadataComponent
-} from './mydspace-actions/claimed-task/edit-metadata/claimed-task-actions-edit-metadata.component';
import { ImpersonateNavbarComponent } from './impersonate-navbar/impersonate-navbar.component';
import { NgForTrackByIdDirective } from './ng-for-track-by-id.directive';
import { FileDownloadLinkComponent } from './file-download-link/file-download-link.component';
import { CollectionDropdownComponent } from './collection-dropdown/collection-dropdown.component';
import { EntityDropdownComponent } from './entity-dropdown/entity-dropdown.component';
-import { VocabularyTreeviewComponent } from './vocabulary-treeview/vocabulary-treeview.component';
import { CurationFormComponent } from '../curation-form/curation-form.component';
import {
PublicationSidebarSearchListElementComponent
@@ -278,38 +221,15 @@ import { HoverClassDirective } from './hover-class.directive';
import {
ValidationSuggestionsComponent
} from './input-suggestions/validation-suggestions/validation-suggestions.component';
-import { ItemAlertsComponent } from './item/item-alerts/item-alerts.component';
import {
ItemSearchResultGridElementComponent
} from './object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
-import { BitstreamDownloadPageComponent } from './bitstream-download-page/bitstream-download-page.component';
-import {
- GenericItemPageFieldComponent
-} from '../item-page/simple/field-components/specific-field/generic/generic-item-page-field.component';
-import {
- MetadataRepresentationListComponent
-} from '../item-page/simple/metadata-representation-list/metadata-representation-list.component';
-import { RelatedItemsComponent } from '../item-page/simple/related-items/related-items-component';
-import { LinkMenuItemComponent } from './menu/menu-item/link-menu-item.component';
-import { OnClickMenuItemComponent } from './menu/menu-item/onclick-menu-item.component';
-import { TextMenuItemComponent } from './menu/menu-item/text-menu-item.component';
import { SearchNavbarComponent } from '../search-navbar/search-navbar.component';
import { ThemedSearchNavbarComponent } from '../search-navbar/themed-search-navbar.component';
-import {
- ItemVersionsSummaryModalComponent
-} from './item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component';
-import {
- ItemVersionsDeleteModalComponent
-} from './item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component';
import { ScopeSelectorModalComponent } from './search-form/scope-selector-modal/scope-selector-modal.component';
-import {
- BitstreamRequestACopyPageComponent
-} from './bitstream-request-a-copy-page/bitstream-request-a-copy-page.component';
import { DsSelectComponent } from './ds-select/ds-select.component';
import { LogInOidcComponent } from './log-in/methods/oidc/log-in-oidc.component';
-import { ThemedItemListPreviewComponent } from './object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component';
import { RSSComponent } from './rss-feed/rss.component';
-import { ExternalLinkMenuItemComponent } from './menu/menu-item/external-link-menu-item.component';
import { LogInOrcidComponent } from './log-in/methods/orcid/log-in-orcid.component';
import { BrowserOnlyPipe } from './utils/browser-only.pipe';
import { ThemedLoadingComponent } from './loading/themed-loading.component';
@@ -326,27 +246,27 @@ import {
DsoEditMenuExpandableSectionComponent
} from './dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component';
import { GoogleRecaptchaModule } from '../core/google-recaptcha/google-recaptcha.module';
+import { MenuModule } from './menu/menu.module';
+import {
+ ListableNotificationObjectComponent
+} from './object-list/listable-notification-object/listable-notification-object.component';
+import { ThemedCollectionDropdownComponent } from './collection-dropdown/themed-collection-dropdown.component';
+import { MetadataFieldWrapperComponent } from './metadata-field-wrapper/metadata-field-wrapper.component';
const MODULES = [
CommonModule,
- SortablejsModule,
- FileUploadModule,
FormsModule,
InfiniteScrollModule,
NgbNavModule,
- NgbDatepickerModule,
- NgbTimepickerModule,
NgbTypeaheadModule,
- NgxPaginationModule,
NgbPaginationModule,
NgbDropdownModule,
NgbTooltipModule,
ReactiveFormsModule,
RouterModule,
- NouisliderModule,
DragDropModule,
- CdkTreeModule,
GoogleRecaptchaModule,
+ MenuModule,
];
const ROOT_MODULES = [
@@ -378,16 +298,13 @@ const COMPONENTS = [
AuthNavMenuComponent,
ThemedAuthNavMenuComponent,
UserMenuComponent,
- ChipsComponent,
DsSelectComponent,
ErrorComponent,
- FileSectionComponent,
LangSwitchComponent,
LoadingComponent,
ThemedLoadingComponent,
LogInComponent,
LogOutComponent,
- NumberPickerComponent,
ObjectListComponent,
ThemedObjectListComponent,
ObjectDetailComponent,
@@ -399,27 +316,7 @@ const COMPONENTS = [
SearchFormComponent,
PageWithSidebarComponent,
SidebarDropdownComponent,
- SidebarFilterComponent,
- SidebarFilterSelectedOptionComponent,
ThumbnailComponent,
- UploaderComponent,
- FileDropzoneNoUploaderComponent,
- ItemListPreviewComponent,
- ThemedItemListPreviewComponent,
- MyDSpaceItemStatusComponent,
- ItemSubmitterComponent,
- ItemDetailPreviewComponent,
- ItemDetailPreviewFieldComponent,
- ClaimedTaskActionsComponent,
- ClaimedTaskActionsApproveComponent,
- ClaimedTaskActionsRejectComponent,
- ClaimedTaskActionsReturnToPoolComponent,
- ClaimedTaskActionsEditMetadataComponent,
- ClaimedTaskActionsLoaderComponent,
- ItemActionsComponent,
- PoolTaskActionsComponent,
- WorkflowitemActionsComponent,
- WorkspaceitemActionsComponent,
ViewModeSwitchComponent,
TruncatableComponent,
TruncatablePartComponent,
@@ -429,90 +326,33 @@ const COMPONENTS = [
ValidationSuggestionsComponent,
DsoInputSuggestionsComponent,
DSOSelectorComponent,
- CreateCommunityParentSelectorComponent,
- ThemedCreateCommunityParentSelectorComponent,
- CreateCollectionParentSelectorComponent,
- ThemedCreateCollectionParentSelectorComponent,
- CreateItemParentSelectorComponent,
- ThemedCreateItemParentSelectorComponent,
- EditCommunitySelectorComponent,
- ThemedEditCommunitySelectorComponent,
- EditCollectionSelectorComponent,
- ThemedEditCollectionSelectorComponent,
- EditItemSelectorComponent,
- ThemedEditItemSelectorComponent,
- CommunitySearchResultListElementComponent,
- CollectionSearchResultListElementComponent,
- BrowseByComponent,
-
- CollectionSearchResultGridElementComponent,
- CommunitySearchResultGridElementComponent,
SearchExportCsvComponent,
PageSizeSelectorComponent,
ListableObjectComponentLoaderComponent,
- CollectionListElementComponent,
- CommunityListElementComponent,
- CollectionGridElementComponent,
- CommunityGridElementComponent,
- BrowseByComponent,
AbstractTrackableComponent,
ComcolMetadataComponent,
TypeBadgeComponent,
AccessStatusBadgeComponent,
- BrowseByComponent,
- AbstractTrackableComponent,
-
ItemSelectComponent,
CollectionSelectComponent,
MetadataRepresentationLoaderComponent,
SelectableListItemControlComponent,
-
ImportableListItemControlComponent,
-
- LogInShibbolethComponent,
- LogInOidcComponent,
- LogInOrcidComponent,
- LogInPasswordComponent,
LogInContainerComponent,
- ItemVersionsComponent,
- ItemSearchResultListElementComponent,
- ItemVersionsNoticeComponent,
ModifyItemOverviewComponent,
ImpersonateNavbarComponent,
- FileDownloadLinkComponent,
- BitstreamDownloadPageComponent,
- BitstreamRequestACopyPageComponent,
- CollectionDropdownComponent,
EntityDropdownComponent,
ExportMetadataSelectorComponent,
ImportBatchSelectorComponent,
ExportBatchSelectorComponent,
ConfirmationModalComponent,
- VocabularyTreeviewComponent,
AuthorizedCollectionSelectorComponent,
- CurationFormComponent,
- SearchResultListElementComponent,
- SearchResultGridElementComponent,
- ItemListElementComponent,
- ItemGridElementComponent,
- ItemSearchResultGridElementComponent,
- BrowseEntryListElementComponent,
- SearchResultDetailElementComponent,
- PlainTextMetadataListElementComponent,
- ItemMetadataListElementComponent,
- MetadataRepresentationListElementComponent,
- ItemMetadataRepresentationListElementComponent,
- BundleListElementComponent,
- StartsWithDateComponent,
- StartsWithTextComponent,
- SidebarSearchListElementComponent,
- PublicationSidebarSearchListElementComponent,
- CollectionSidebarSearchListElementComponent,
- CommunitySidebarSearchListElementComponent,
SearchNavbarComponent,
- ScopeSelectorModalComponent,
ItemPageTitleFieldComponent,
ThemedSearchNavbarComponent,
+ ListableNotificationObjectComponent,
+ DsoPageEditButtonComponent,
+ MetadataFieldWrapperComponent,
];
const ENTRY_COMPONENTS = [
@@ -555,46 +395,25 @@ const ENTRY_COMPONENTS = [
LogInShibbolethComponent,
LogInOidcComponent,
LogInOrcidComponent,
- BundleListElementComponent,
- ClaimedTaskActionsApproveComponent,
- ClaimedTaskActionsRejectComponent,
- ClaimedTaskActionsReturnToPoolComponent,
- ClaimedTaskActionsEditMetadataComponent,
CollectionDropdownComponent,
+ ThemedCollectionDropdownComponent,
FileDownloadLinkComponent,
- BitstreamDownloadPageComponent,
- BitstreamRequestACopyPageComponent,
CurationFormComponent,
ExportMetadataSelectorComponent,
ImportBatchSelectorComponent,
ExportBatchSelectorComponent,
ConfirmationModalComponent,
- VocabularyTreeviewComponent,
SidebarSearchListElementComponent,
PublicationSidebarSearchListElementComponent,
CollectionSidebarSearchListElementComponent,
CommunitySidebarSearchListElementComponent,
- LinkMenuItemComponent,
- OnClickMenuItemComponent,
- TextMenuItemComponent,
ScopeSelectorModalComponent,
+ ListableNotificationObjectComponent,
ExternalLinkMenuItemComponent,
DsoEditMenuSectionComponent,
DsoEditMenuExpandableSectionComponent,
];
-const SHARED_ITEM_PAGE_COMPONENTS = [
- MetadataFieldWrapperComponent,
- MetadataValuesComponent,
- ItemAlertsComponent,
- GenericItemPageFieldComponent,
- MetadataRepresentationListComponent,
- RelatedItemsComponent,
- DsoEditMenuSectionComponent,
- DsoEditMenuComponent,
- DsoEditMenuExpandableSectionComponent,
-];
-
const PROVIDERS = [
TruncatableService,
MockAdminGuard,
@@ -606,7 +425,6 @@ const DIRECTIVES = [
DragClickDirective,
DebounceDirective,
ClickOutsideDirective,
- AuthorityConfidenceStateDirective,
InListValidator,
AutoFocusDirective,
RoleDirective,
@@ -629,10 +447,8 @@ const DIRECTIVES = [
declarations: [
...PIPES,
...COMPONENTS,
+ ...ENTRY_COMPONENTS,
...DIRECTIVES,
- ...SHARED_ITEM_PAGE_COMPONENTS,
- ItemVersionsSummaryModalComponent,
- ItemVersionsDeleteModalComponent,
],
providers: [
...PROVIDERS
@@ -641,9 +457,9 @@ const DIRECTIVES = [
...MODULES,
...PIPES,
...COMPONENTS,
- ...SHARED_ITEM_PAGE_COMPONENTS,
+ ...ENTRY_COMPONENTS,
...DIRECTIVES,
- TranslateModule
+ TranslateModule,
]
})
diff --git a/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.html b/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.html
deleted file mode 100644
index bbe0b93566..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- {{label}}
-
-
diff --git a/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.scss b/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.scss
deleted file mode 100644
index 30ab8912d3..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-a {
- color: var(--bs-body-color);
-
- &:hover, &focus {
- text-decoration: none;
- }
-
- span.badge {
- vertical-align: text-top;
- }
-}
diff --git a/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.ts b/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.ts
deleted file mode 100644
index 4f1d2415ae..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter-selected-option.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-
-@Component({
- selector: 'ds-sidebar-filter-selected-option',
- styleUrls: ['./sidebar-filter-selected-option.component.scss'],
- templateUrl: './sidebar-filter-selected-option.component.html',
-})
-
-/**
- * Represents a single selected option in a sidebar filter
- */
-export class SidebarFilterSelectedOptionComponent {
- @Input() label: string;
- @Output() click: EventEmitter = new EventEmitter();
-}
diff --git a/src/app/shared/sidebar/filter/sidebar-filter.actions.ts b/src/app/shared/sidebar/filter/sidebar-filter.actions.ts
deleted file mode 100644
index 5dab677c5c..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter.actions.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-/* eslint-disable max-classes-per-file */
-import { Action } from '@ngrx/store';
-
-import { type } from '../../ngrx/type';
-
-/**
- * For each action type in an action group, make a simple
- * enum object for all of this group's action types.
- *
- * The 'type' utility function coerces strings into string
- * literal types and runs a simple check to guarantee all
- * action types in the application are unique.
- */
-export const SidebarFilterActionTypes = {
- INITIALIZE: type('dspace/sidebar-filter/INITIALIZE'),
- COLLAPSE: type('dspace/sidebar-filter/COLLAPSE'),
- EXPAND: type('dspace/sidebar-filter/EXPAND'),
- TOGGLE: type('dspace/sidebar-filter/TOGGLE'),
-};
-
-export class SidebarFilterAction implements Action {
- /**
- * Name of the filter the action is performed on, used to identify the filter
- */
- filterName: string;
-
- /**
- * Type of action that will be performed
- */
- type;
-
- /**
- * Initialize with the filter's name
- * @param {string} name of the filter
- */
- constructor(name: string) {
- this.filterName = name;
- }
-}
-
-/**
- * Used to initialize a filter
- */
-export class FilterInitializeAction extends SidebarFilterAction {
- type = SidebarFilterActionTypes.INITIALIZE;
- initiallyExpanded;
-
- constructor(name: string, initiallyExpanded: boolean) {
- super(name);
- this.initiallyExpanded = initiallyExpanded;
- }
-}
-
-/**
- * Used to collapse a filter
- */
-export class FilterCollapseAction extends SidebarFilterAction {
- type = SidebarFilterActionTypes.COLLAPSE;
-}
-
-/**
- * Used to expand a filter
- */
-export class FilterExpandAction extends SidebarFilterAction {
- type = SidebarFilterActionTypes.EXPAND;
-}
-
-/**
- * Used to collapse a filter when it's expanded and expand it when it's collapsed
- */
-export class FilterToggleAction extends SidebarFilterAction {
- type = SidebarFilterActionTypes.TOGGLE;
-}
diff --git a/src/app/shared/sidebar/filter/sidebar-filter.component.html b/src/app/shared/sidebar/filter/sidebar-filter.component.html
deleted file mode 100644
index 79afaa7583..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter.component.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- {{ label | translate }}
-
-
-
-
-
-
diff --git a/src/app/shared/sidebar/filter/sidebar-filter.component.scss b/src/app/shared/sidebar/filter/sidebar-filter.component.scss
deleted file mode 100644
index bf7a089cb1..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter.component.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-:host .facet-filter {
- border: 1px solid var(--bs-light);
- cursor: pointer;
-
- .sidebar-filter-wrapper.closed {
- overflow: hidden;
- }
-
- .filter-toggle {
- line-height: var(--bs-line-height-base);
- }
-}
diff --git a/src/app/shared/sidebar/filter/sidebar-filter.component.ts b/src/app/shared/sidebar/filter/sidebar-filter.component.ts
deleted file mode 100644
index 5a019d41df..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter.component.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-import { Observable } from 'rxjs';
-import { SidebarFilterService } from './sidebar-filter.service';
-import { slide } from '../../animations/slide';
-
-@Component({
- selector: 'ds-sidebar-filter',
- styleUrls: ['./sidebar-filter.component.scss'],
- templateUrl: './sidebar-filter.component.html',
- animations: [slide],
-})
-/**
- * This components renders a sidebar filter including the label and the selected values.
- * The filter input itself should still be provided in the content.
- */
-export class SidebarFilterComponent implements OnInit {
-
- @Input() name: string;
- @Input() type: string;
- @Input() label: string;
- @Input() expanded = true;
- @Input() singleValue = false;
- @Input() selectedValues: Observable;
- @Output() removeValue: EventEmitter = new EventEmitter();
-
- /**
- * True when the filter is 100% collapsed in the UI
- */
- closed = true;
-
- /**
- * Emits true when the filter is currently collapsed in the store
- */
- collapsed$: Observable;
-
- constructor(
- protected filterService: SidebarFilterService,
- ) {
- }
-
- /**
- * Changes the state for this filter to collapsed when it's expanded and to expanded it when it's collapsed
- */
- toggle() {
- this.filterService.toggle(this.name);
- }
-
- /**
- * Method to change this.collapsed to false when the slide animation ends and is sliding open
- * @param event The animation event
- */
- finishSlide(event: any): void {
- if (event.fromState === 'collapsed') {
- this.closed = false;
- }
- }
-
- /**
- * Method to change this.collapsed to true when the slide animation starts and is sliding closed
- * @param event The animation event
- */
- startSlide(event: any): void {
- if (event.toState === 'collapsed') {
- this.closed = true;
- }
- }
-
- ngOnInit(): void {
- this.closed = !this.expanded;
- this.initializeFilter();
- this.collapsed$ = this.isCollapsed();
- }
-
- /**
- * Sets the initial state of the filter
- */
- initializeFilter() {
- this.filterService.initializeFilter(this.name, this.expanded);
- }
-
- /**
- * Checks if the filter is currently collapsed
- * @returns {Observable} Emits true when the current state of the filter is collapsed, false when it's expanded
- */
- private isCollapsed(): Observable {
- return this.filterService.isCollapsed(this.name);
- }
-
-}
diff --git a/src/app/shared/sidebar/filter/sidebar-filter.reducer.ts b/src/app/shared/sidebar/filter/sidebar-filter.reducer.ts
deleted file mode 100644
index b7784dd12b..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter.reducer.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import {
- FilterInitializeAction,
- SidebarFilterAction,
- SidebarFilterActionTypes
-} from './sidebar-filter.actions';
-
-/**
- * Interface that represents the state for a single filters
- */
-export interface SidebarFilterState {
- filterCollapsed: boolean;
-}
-
-/**
- * Interface that represents the state for all available filters
- */
-export interface SidebarFiltersState {
- [name: string]: SidebarFilterState;
-}
-
-const initialState: SidebarFiltersState = Object.create(null);
-
-/**
- * Performs a filter action on the current state
- * @param {SidebarFiltersState} state The state before the action is performed
- * @param {SidebarFilterAction} action The action that should be performed
- * @returns {SidebarFiltersState} The state after the action is performed
- */
-export function sidebarFilterReducer(state = initialState, action: SidebarFilterAction): SidebarFiltersState {
-
- switch (action.type) {
-
- case SidebarFilterActionTypes.INITIALIZE: {
- const initAction = (action as FilterInitializeAction);
- return Object.assign({}, state, {
- [action.filterName]: {
- filterCollapsed: !initAction.initiallyExpanded,
- }
- });
- }
-
- case SidebarFilterActionTypes.COLLAPSE: {
- return Object.assign({}, state, {
- [action.filterName]: {
- filterCollapsed: true,
- }
- });
- }
-
- case SidebarFilterActionTypes.EXPAND: {
- return Object.assign({}, state, {
- [action.filterName]: {
- filterCollapsed: false,
- }
- });
- }
-
- case SidebarFilterActionTypes.TOGGLE: {
- return Object.assign({}, state, {
- [action.filterName]: {
- filterCollapsed: !state[action.filterName].filterCollapsed,
- }
- });
- }
-
- default: {
- return state;
- }
- }
-}
diff --git a/src/app/shared/sidebar/filter/sidebar-filter.service.spec.ts b/src/app/shared/sidebar/filter/sidebar-filter.service.spec.ts
deleted file mode 100644
index 49192a2006..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter.service.spec.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import { TestBed, waitForAsync } from '@angular/core/testing';
-import { Store, StoreModule } from '@ngrx/store';
-import { provideMockStore } from '@ngrx/store/testing';
-import { cold } from 'jasmine-marbles';
-
-import { sidebarFilterReducer } from './sidebar-filter.reducer';
-import { SidebarFilterService } from './sidebar-filter.service';
-import {
- FilterCollapseAction,
- FilterExpandAction,
- FilterInitializeAction,
- FilterToggleAction
-} from './sidebar-filter.actions';
-import { storeModuleConfig } from '../../../app.reducer';
-
-describe('SidebarFilterService', () => {
- let service: SidebarFilterService;
- let store: any;
- let initialState;
-
- function init() {
-
- initialState = {
- sidebarFilter: {
- filter_1: {
- filterCollapsed: true
- },
- filter_2: {
- filterCollapsed: false
- },
- filter_3: {
- filterCollapsed: true
- }
- }
- };
-
- }
-
- beforeEach(waitForAsync(() => {
- init();
- TestBed.configureTestingModule({
- imports: [
- StoreModule.forRoot({ sidebarFilter: sidebarFilterReducer }, storeModuleConfig)
- ],
- providers: [
- provideMockStore({ initialState }),
- { provide: SidebarFilterService, useValue: service }
- ]
- }).compileComponents();
- }));
-
- beforeEach(() => {
- store = TestBed.inject(Store);
- service = new SidebarFilterService(store);
- spyOn(store, 'dispatch');
- });
-
- describe('initializeFilter', () => {
- it('should dispatch an FilterInitializeAction with the correct arguments', () => {
- service.initializeFilter('fakeFilter', true);
- expect(store.dispatch).toHaveBeenCalledWith(new FilterInitializeAction('fakeFilter', true));
- });
- });
-
- describe('collapse', () => {
- it('should dispatch an FilterInitializeAction with the correct arguments', () => {
- service.collapse('fakeFilter');
- expect(store.dispatch).toHaveBeenCalledWith(new FilterCollapseAction('fakeFilter'));
- });
- });
-
- describe('expand', () => {
- it('should dispatch an FilterInitializeAction with the correct arguments', () => {
- service.expand('fakeFilter');
- expect(store.dispatch).toHaveBeenCalledWith(new FilterExpandAction('fakeFilter'));
- });
- });
-
- describe('toggle', () => {
- it('should dispatch an FilterInitializeAction with the correct arguments', () => {
- service.toggle('fakeFilter');
- expect(store.dispatch).toHaveBeenCalledWith(new FilterToggleAction('fakeFilter'));
- });
- });
-
- describe('isCollapsed', () => {
- it('should return true', () => {
-
- const result = service.isCollapsed('filter_1');
- const expected = cold('b', {
- b: true
- });
-
- expect(result).toBeObservable(expected);
- });
-
- it('should return false', () => {
-
- const result = service.isCollapsed('filter_2');
- const expected = cold('b', {
- b: false
- });
-
- expect(result).toBeObservable(expected);
- });
- });
-});
diff --git a/src/app/shared/sidebar/filter/sidebar-filter.service.ts b/src/app/shared/sidebar/filter/sidebar-filter.service.ts
deleted file mode 100644
index b67de24f9e..0000000000
--- a/src/app/shared/sidebar/filter/sidebar-filter.service.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { Injectable } from '@angular/core';
-import {
- FilterCollapseAction,
- FilterExpandAction, FilterInitializeAction,
- FilterToggleAction
-} from './sidebar-filter.actions';
-import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
-import { SidebarFiltersState, SidebarFilterState } from './sidebar-filter.reducer';
-import { Observable } from 'rxjs';
-import { distinctUntilChanged, map } from 'rxjs/operators';
-import { hasValue } from '../../empty.util';
-
-/**
- * Service that performs all actions that have to do with sidebar filters like collapsing or expanding them.
- */
-@Injectable()
-export class SidebarFilterService {
-
- constructor(private store: Store) {
- }
-
- /**
- * Dispatches an initialize action to the store for a given filter
- * @param {string} filter The filter for which the action is dispatched
- * @param {boolean} expanded If the filter should be open from the start
- */
- public initializeFilter(filter: string, expanded: boolean): void {
- this.store.dispatch(new FilterInitializeAction(filter, expanded));
- }
-
- /**
- * Dispatches a collapse action to the store for a given filter
- * @param {string} filterName The filter for which the action is dispatched
- */
- public collapse(filterName: string): void {
- this.store.dispatch(new FilterCollapseAction(filterName));
- }
-
- /**
- * Dispatches an expand action to the store for a given filter
- * @param {string} filterName The filter for which the action is dispatched
- */
- public expand(filterName: string): void {
- this.store.dispatch(new FilterExpandAction(filterName));
- }
-
- /**
- * Dispatches a toggle action to the store for a given filter
- * @param {string} filterName The filter for which the action is dispatched
- */
- public toggle(filterName: string): void {
- this.store.dispatch(new FilterToggleAction(filterName));
- }
-
- /**
- * Checks if the state of a given filter is currently collapsed or not
- * @param {string} filterName The filtername for which the collapsed state is checked
- * @returns {Observable} Emits the current collapsed state of the given filter, if it's unavailable, return false
- */
- isCollapsed(filterName: string): Observable {
- return this.store.pipe(
- select(filterByNameSelector(filterName)),
- map((object: SidebarFilterState) => {
- if (object) {
- return object.filterCollapsed;
- } else {
- return false;
- }
- }),
- distinctUntilChanged()
- );
- }
-
-}
-
-const filterStateSelector = (state: SidebarFiltersState) => state.sidebarFilter;
-
-function filterByNameSelector(name: string): MemoizedSelector {
- return keySelector(name);
-}
-
-export function keySelector(key: string): MemoizedSelector {
- return createSelector(filterStateSelector, (state: SidebarFilterState) => {
- if (hasValue(state)) {
- return state[key];
- } else {
- return undefined;
- }
- });
-}
diff --git a/src/app/shared/theme-support/themed.component.spec.ts b/src/app/shared/theme-support/themed.component.spec.ts
index 404e970a7a..7776e60379 100644
--- a/src/app/shared/theme-support/themed.component.spec.ts
+++ b/src/app/shared/theme-support/themed.component.spec.ts
@@ -71,6 +71,12 @@ describe('ThemedComponent', () => {
expect((component as any).compRef.instance.testInput).toEqual('changed');
});
}));
+
+ it(`should set usedTheme to the name of the matched theme`, waitForAsync(() => {
+ fixture.whenStable().then(() => {
+ expect(component.usedTheme).toEqual('custom');
+ });
+ }));
});
describe('when the current theme doesn\'t match a themed component', () => {
@@ -92,6 +98,12 @@ describe('ThemedComponent', () => {
expect((component as any).compRef.instance.testInput).toEqual('changed');
});
}));
+
+ it(`should set usedTheme to the name of the base theme`, waitForAsync(() => {
+ fixture.whenStable().then(() => {
+ expect(component.usedTheme).toEqual('base');
+ });
+ }));
});
describe('and it extends another theme', () => {
@@ -117,6 +129,12 @@ describe('ThemedComponent', () => {
expect((component as any).compRef.instance.testInput).toEqual('changed');
});
}));
+
+ it(`should set usedTheme to the name of the base theme`, waitForAsync(() => {
+ fixture.whenStable().then(() => {
+ expect(component.usedTheme).toEqual('base');
+ });
+ }));
});
describe('that does match it', () => {
@@ -141,6 +159,12 @@ describe('ThemedComponent', () => {
expect((component as any).compRef.instance.testInput).toEqual('changed');
});
}));
+
+ it(`should set usedTheme to the name of the matched theme`, waitForAsync(() => {
+ fixture.whenStable().then(() => {
+ expect(component.usedTheme).toEqual('custom');
+ });
+ }));
});
describe('that extends another theme that doesn\'t match it either', () => {
@@ -167,6 +191,12 @@ describe('ThemedComponent', () => {
expect((component as any).compRef.instance.testInput).toEqual('changed');
});
}));
+
+ it(`should set usedTheme to the name of the base theme`, waitForAsync(() => {
+ fixture.whenStable().then(() => {
+ expect(component.usedTheme).toEqual('base');
+ });
+ }));
});
describe('that extends another theme that does match it', () => {
@@ -193,6 +223,12 @@ describe('ThemedComponent', () => {
expect((component as any).compRef.instance.testInput).toEqual('changed');
});
}));
+
+ it(`should set usedTheme to the name of the matched theme`, waitForAsync(() => {
+ fixture.whenStable().then(() => {
+ expect(component.usedTheme).toEqual('custom');
+ });
+ }));
});
});
});
diff --git a/src/app/shared/theme-support/themed.component.ts b/src/app/shared/theme-support/themed.component.ts
index 87f182a5ff..995122d284 100644
--- a/src/app/shared/theme-support/themed.component.ts
+++ b/src/app/shared/theme-support/themed.component.ts
@@ -8,13 +8,15 @@ import {
OnDestroy,
ComponentFactoryResolver,
ChangeDetectorRef,
- OnChanges
+ OnChanges,
+ HostBinding
} from '@angular/core';
import { hasValue, isNotEmpty } from '../empty.util';
-import { from as fromPromise, Observable, of as observableOf, Subscription } from 'rxjs';
+import { from as fromPromise, Observable, of as observableOf, Subscription, BehaviorSubject } from 'rxjs';
import { ThemeService } from './theme.service';
-import { catchError, switchMap, map } from 'rxjs/operators';
+import { catchError, switchMap, map, tap } from 'rxjs/operators';
import { GenericConstructor } from '../../core/shared/generic-constructor';
+import { BASE_THEME_NAME } from './theme.constants';
@Component({
selector: 'ds-themed',
@@ -25,11 +27,22 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges
@ViewChild('vcr', { read: ViewContainerRef }) vcr: ViewContainerRef;
protected compRef: ComponentRef;
+ /**
+ * A reference to the themed component. Will start as undefined and emit every time the themed
+ * component is rendered
+ */
+ public compRef$: BehaviorSubject> = new BehaviorSubject(undefined);
+
protected lazyLoadSub: Subscription;
protected themeSub: Subscription;
protected inAndOutputNames: (keyof T & keyof this)[] = [];
+ /**
+ * A data attribute on the ThemedComponent to indicate which theme the rendered component came from.
+ */
+ @HostBinding('attr.data-used-theme') usedTheme: string;
+
constructor(
protected resolver: ComponentFactoryResolver,
protected cdr: ChangeDetectorRef,
@@ -80,6 +93,7 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges
} else {
// otherwise import and return the default component
return fromPromise(this.importUnthemedComponent()).pipe(
+ tap(() => this.usedTheme = BASE_THEME_NAME),
map((unthemedFile: any) => {
return unthemedFile[this.getComponentName()];
})
@@ -90,6 +104,7 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges
const factory = this.resolver.resolveComponentFactory(constructor);
this.compRef = this.vcr.createComponent(factory);
this.connectInputsAndOutputs();
+ this.compRef$.next(this.compRef);
this.cdr.markForCheck();
});
}
@@ -123,6 +138,7 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges
private resolveThemedComponent(themeName?: string, checkedThemeNames: string[] = []): Observable {
if (isNotEmpty(themeName)) {
return fromPromise(this.importThemedComponent(themeName)).pipe(
+ tap(() => this.usedTheme = themeName),
catchError(() => {
// Try the next ancestor theme instead
const nextTheme = this.themeService.getThemeConfigFor(themeName)?.extends;
diff --git a/src/app/shared/file-dropzone-no-uploader/file-dropzone-no-uploader.component.html b/src/app/shared/upload/file-dropzone-no-uploader/file-dropzone-no-uploader.component.html
similarity index 100%
rename from src/app/shared/file-dropzone-no-uploader/file-dropzone-no-uploader.component.html
rename to src/app/shared/upload/file-dropzone-no-uploader/file-dropzone-no-uploader.component.html
diff --git a/src/app/shared/file-dropzone-no-uploader/file-dropzone-no-uploader.component.ts b/src/app/shared/upload/file-dropzone-no-uploader/file-dropzone-no-uploader.component.ts
similarity index 100%
rename from src/app/shared/file-dropzone-no-uploader/file-dropzone-no-uploader.component.ts
rename to src/app/shared/upload/file-dropzone-no-uploader/file-dropzone-no-uploader.component.ts
diff --git a/src/app/shared/file-dropzone-no-uploader/file-dropzone-no-uploader.scss b/src/app/shared/upload/file-dropzone-no-uploader/file-dropzone-no-uploader.scss
similarity index 100%
rename from src/app/shared/file-dropzone-no-uploader/file-dropzone-no-uploader.scss
rename to src/app/shared/upload/file-dropzone-no-uploader/file-dropzone-no-uploader.scss
diff --git a/src/app/shared/upload/upload.module.ts b/src/app/shared/upload/upload.module.ts
new file mode 100644
index 0000000000..9f2895d7ac
--- /dev/null
+++ b/src/app/shared/upload/upload.module.ts
@@ -0,0 +1,38 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SharedModule } from '../shared.module';
+import { FileUploadModule } from 'ng2-file-upload';
+import { UploaderComponent } from './uploader/uploader.component';
+import { FileDropzoneNoUploaderComponent } from './file-dropzone-no-uploader/file-dropzone-no-uploader.component';
+
+const COMPONENTS = [
+ UploaderComponent,
+ FileDropzoneNoUploaderComponent,
+];
+
+@NgModule({
+ imports: [
+ CommonModule,
+ SharedModule,
+ FileUploadModule,
+ ],
+ declarations: [
+ ...COMPONENTS,
+ ],
+ providers: [
+ ...COMPONENTS,
+ ],
+ exports: [
+ ...COMPONENTS,
+ FileUploadModule,
+ ]
+})
+export class UploadModule {
+}
diff --git a/src/app/shared/uploader/uploader-error.model.ts b/src/app/shared/upload/uploader/uploader-error.model.ts
similarity index 100%
rename from src/app/shared/uploader/uploader-error.model.ts
rename to src/app/shared/upload/uploader/uploader-error.model.ts
diff --git a/src/app/shared/uploader/uploader-options.model.ts b/src/app/shared/upload/uploader/uploader-options.model.ts
similarity index 86%
rename from src/app/shared/uploader/uploader-options.model.ts
rename to src/app/shared/upload/uploader/uploader-options.model.ts
index 959e5c3295..559fb0485b 100644
--- a/src/app/shared/uploader/uploader-options.model.ts
+++ b/src/app/shared/upload/uploader/uploader-options.model.ts
@@ -1,4 +1,4 @@
-import { RestRequestMethod } from '../../core/data/rest-request-method';
+import { RestRequestMethod } from '../../../core/data/rest-request-method';
export class UploaderOptions {
/**
diff --git a/src/app/shared/uploader/uploader-properties.model.ts b/src/app/shared/upload/uploader/uploader-properties.model.ts
similarity index 83%
rename from src/app/shared/uploader/uploader-properties.model.ts
rename to src/app/shared/upload/uploader/uploader-properties.model.ts
index bc0376b809..b84ae30bf8 100644
--- a/src/app/shared/uploader/uploader-properties.model.ts
+++ b/src/app/shared/upload/uploader/uploader-properties.model.ts
@@ -1,4 +1,4 @@
-import { MetadataMap } from '../../core/shared/metadata.models';
+import { MetadataMap } from '../../../core/shared/metadata.models';
/**
* Properties to send to the REST API for uploading a bitstream
diff --git a/src/app/shared/uploader/uploader.component.html b/src/app/shared/upload/uploader/uploader.component.html
similarity index 100%
rename from src/app/shared/uploader/uploader.component.html
rename to src/app/shared/upload/uploader/uploader.component.html
diff --git a/src/app/shared/uploader/uploader.component.scss b/src/app/shared/upload/uploader/uploader.component.scss
similarity index 100%
rename from src/app/shared/uploader/uploader.component.scss
rename to src/app/shared/upload/uploader/uploader.component.scss
diff --git a/src/app/shared/uploader/uploader.component.spec.ts b/src/app/shared/upload/uploader/uploader.component.spec.ts
similarity index 86%
rename from src/app/shared/uploader/uploader.component.spec.ts
rename to src/app/shared/upload/uploader/uploader.component.spec.ts
index 84fee2e147..8ea23c8acb 100644
--- a/src/app/shared/uploader/uploader.component.spec.ts
+++ b/src/app/shared/upload/uploader/uploader.component.spec.ts
@@ -4,16 +4,16 @@ import { ComponentFixture, inject, TestBed, waitForAsync, } from '@angular/core/
import { ScrollToService } from '@nicky-lenaers/ngx-scroll-to';
-import { UploaderService } from './uploader.service';
+import { DragService } from '../../../core/drag.service';
import { UploaderOptions } from './uploader-options.model';
import { UploaderComponent } from './uploader.component';
import { FileUploadModule } from 'ng2-file-upload';
import { TranslateModule } from '@ngx-translate/core';
-import { createTestComponent } from '../testing/utils.test';
+import { createTestComponent } from '../../testing/utils.test';
import { HttpXsrfTokenExtractor } from '@angular/common/http';
-import { CookieService } from '../../core/services/cookie.service';
-import { CookieServiceMock } from '../mocks/cookie.service.mock';
-import { HttpXsrfTokenExtractorMock } from '../mocks/http-xsrf-token-extractor.mock';
+import { CookieService } from '../../../core/services/cookie.service';
+import { CookieServiceMock } from '../../mocks/cookie.service.mock';
+import { HttpXsrfTokenExtractorMock } from '../../mocks/http-xsrf-token-extractor.mock';
describe('Chips component', () => {
@@ -37,7 +37,7 @@ describe('Chips component', () => {
ChangeDetectorRef,
ScrollToService,
UploaderComponent,
- UploaderService,
+ DragService,
{ provide: HttpXsrfTokenExtractor, useValue: new HttpXsrfTokenExtractorMock('mock-token') },
{ provide: CookieService, useValue: new CookieServiceMock() },
],
diff --git a/src/app/shared/uploader/uploader.component.ts b/src/app/shared/upload/uploader/uploader.component.ts
similarity index 93%
rename from src/app/shared/uploader/uploader.component.ts
rename to src/app/shared/upload/uploader/uploader.component.ts
index 3cbf033b17..14b1ca9b94 100644
--- a/src/app/shared/uploader/uploader.component.ts
+++ b/src/app/shared/upload/uploader/uploader.component.ts
@@ -6,12 +6,12 @@ import uniqueId from 'lodash/uniqueId';
import { ScrollToService } from '@nicky-lenaers/ngx-scroll-to';
import { UploaderOptions } from './uploader-options.model';
-import { hasValue, isNotEmpty, isUndefined } from '../empty.util';
-import { UploaderService } from './uploader.service';
+import { hasValue, isNotEmpty, isUndefined } from '../../empty.util';
import { UploaderProperties } from './uploader-properties.model';
import { HttpXsrfTokenExtractor } from '@angular/common/http';
-import { XSRF_COOKIE, XSRF_REQUEST_HEADER, XSRF_RESPONSE_HEADER } from '../../core/xsrf/xsrf.interceptor';
-import { CookieService } from '../../core/services/cookie.service';
+import { XSRF_COOKIE, XSRF_REQUEST_HEADER, XSRF_RESPONSE_HEADER } from '../../../core/xsrf/xsrf.interceptor';
+import { CookieService } from '../../../core/services/cookie.service';
+import { DragService } from '../../../core/drag.service';
@Component({
selector: 'ds-uploader',
@@ -76,7 +76,7 @@ export class UploaderComponent {
@HostListener('window:dragover', ['$event'])
onDragOver(event: any) {
- if (this.enableDragOverDocument && this.uploaderService.isAllowedDragOverPage()) {
+ if (this.enableDragOverDocument && this.dragService.isAllowedDragOverPage()) {
// Show drop area on the page
event.preventDefault();
if ((event.target as any).tagName !== 'HTML') {
@@ -85,9 +85,13 @@ export class UploaderComponent {
}
}
- constructor(private cdr: ChangeDetectorRef, private scrollToService: ScrollToService,
- private uploaderService: UploaderService, private tokenExtractor: HttpXsrfTokenExtractor,
- private cookieService: CookieService) {
+ constructor(
+ private cdr: ChangeDetectorRef,
+ private scrollToService: ScrollToService,
+ private dragService: DragService,
+ private tokenExtractor: HttpXsrfTokenExtractor,
+ private cookieService: CookieService
+ ) {
}
/**
diff --git a/src/app/statistics-page/statistics-table/statistics-table.component.html b/src/app/statistics-page/statistics-table/statistics-table.component.html
index 3ecd256812..fb042b25c3 100644
--- a/src/app/statistics-page/statistics-table/statistics-table.component.html
+++ b/src/app/statistics-page/statistics-table/statistics-table.component.html
@@ -10,7 +10,7 @@
-
+