diff --git a/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.html b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.html new file mode 100644 index 00000000000..9f35d4886ce --- /dev/null +++ b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.html @@ -0,0 +1,53 @@ + +
+
+

+
+
+
+
+

+
+
+

+
+
+

+
+
+
+
+
+ @if (bitstreamsRD?.payload?.totalElements > 0) { + +
+ @for (file of bitstreamsRD?.payload?.page; track file) { +
+
+ +
+
+ {{ (bitstreamFormatDataService.findByBitstream(file) | async).payload?.shortDescription }} +
+
+ {{ (file?.sizeBytes) | dsFileSize }} +
+
+ + + +
+
+ } +
+
+ } +
+
+
+
diff --git a/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.scss b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.scss new file mode 100644 index 00000000000..0e9396c0881 --- /dev/null +++ b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.scss @@ -0,0 +1,29 @@ +@import '../../../../../styles/variables.scss'; + +.file-section { + padding: 1rem; + background-color: var(--bs-gray-200); + + .file-section-header { + border-bottom: 4px solid var(--bs-primary); + } + + .file-section-table { + .row { + padding: 0.4em 0.75em; + } + .entries { + .file-section-entry { + background-color: var(--bs-300); + &:nth-child(2n + 1) { + background-color: var(--bs-gray-100); + } + } + } + .heading { + border-bottom: 1px solid var(--bs-gray-900); + background-color: var(--bs-gray-400); + font-size: 1.25em; + } + } +} diff --git a/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.spec.ts b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.spec.ts new file mode 100644 index 00000000000..f809f3713a0 --- /dev/null +++ b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.spec.ts @@ -0,0 +1,154 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { + ComponentFixture, + TestBed, + waitForAsync, +} from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ActivatedRoute } from '@angular/router'; +import { APP_CONFIG } from '@dspace/config/app-config.interface'; +import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service'; +import { BitstreamFormatDataService } from '@dspace/core/data/bitstream-format-data.service'; +import { LocaleService } from '@dspace/core/locale/locale.service'; +import { NotificationsService } from '@dspace/core/notification-system/notifications.service'; +import { PaginationService } from '@dspace/core/pagination/pagination.service'; +import { Bitstream } from '@dspace/core/shared/bitstream.model'; +import { BitstreamFormat } from '@dspace/core/shared/bitstream-format.model'; +import { Item } from '@dspace/core/shared/item.model'; +import { ActivatedRouteStub } from '@dspace/core/testing/active-router.stub'; +import { NotificationsServiceStub } from '@dspace/core/testing/notifications-service.stub'; +import { PaginationServiceStub } from '@dspace/core/testing/pagination-service.stub'; +import { TranslateLoaderMock } from '@dspace/core/testing/translate-loader.mock'; +import { createPaginatedList } from '@dspace/core/testing/utils.test'; +import { createSuccessfulRemoteDataObject$ } from '@dspace/core/utilities/remote-data.utils'; +import { XSRFService } from '@dspace/core/xsrf/xsrf.service'; +import { provideMockStore } from '@ngrx/store/testing'; +import { + TranslateLoader, + TranslateModule, +} from '@ngx-translate/core'; +import { of } from 'rxjs'; + +import { environment } from '../../../../../environments/environment'; +import { ThemedFileDownloadLinkComponent } from '../../../../shared/file-download-link/themed-file-download-link.component'; +import { PaginationComponent } from '../../../../shared/pagination/pagination.component'; +import { SearchConfigurationService } from '../../../../shared/search/search-configuration.service'; +import { getMockThemeService } from '../../../../shared/theme-support/test/theme-service.mock'; +import { ThemeService } from '../../../../shared/theme-support/theme.service'; +import { FileSizePipe } from '../../../../shared/utils/file-size-pipe'; +import { VarDirective } from '../../../../shared/utils/var.directive'; +import { ExtendedFileSectionComponent } from './extended-file-section.component'; + +describe('ExtendedFileSectionComponent', () => { + let component: ExtendedFileSectionComponent; + let fixture: ComponentFixture; + let localeService: any; + const languageList = ['en;q=1', 'de;q=0.8']; + const mockLocaleService = jasmine.createSpyObj('LocaleService', { + getCurrentLanguageCode: jasmine.createSpy('getCurrentLanguageCode'), + getLanguageCodeList: of(languageList), + }); + + const paginationServiceStub = new PaginationServiceStub(); + + const mockItem = Object.assign(new Item(), { + id: 'test-item-id', + uuid: 'test-item-id', + _links: { + self: { href: 'test-item-selflink' }, + }, + }); + + const mockBitstream = Object.assign(new Bitstream(), { + id: 'test-bitstream-id', + uuid: 'test-bitstream-id', + name: 'test-bitstream.pdf', + sizeBytes: 1024, + _links: { + self: { href: 'test-bitstream-selflink' }, + }, + }); + + const mockBitstreamFormat = Object.assign(new BitstreamFormat(), { + resourceType: 'testResourceType', + shortDescription: 'testShortDescription', + description: 'testDescription', + mimetype: 'test/mimeType', + }); + + const paginatedList = createPaginatedList([mockBitstream]); + + paginatedList.pageInfo.elementsPerPage = environment.item.bitstream.pageSize; + + const bitstreamDataService = jasmine.createSpyObj('bitstreamDataService', { + findAllByItemAndBundleName: createSuccessfulRemoteDataObject$(paginatedList), + }); + + const bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', { + findByBitstream: createSuccessfulRemoteDataObject$(mockBitstreamFormat), + }); + + beforeEach(waitForAsync(() => { + + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock, + }, + }), + BrowserAnimationsModule, + ExtendedFileSectionComponent, + VarDirective, + FileSizePipe, + ], + providers: [ + provideMockStore(), + { provide: XSRFService, useValue: {} }, + { provide: BitstreamDataService, useValue: bitstreamDataService }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService }, + { provide: ThemeService, useValue: getMockThemeService() }, + { provide: SearchConfigurationService, useValue: jasmine.createSpyObj(['getCurrentConfiguration']) }, + { provide: PaginationService, useValue: paginationServiceStub }, + { provide: ActivatedRoute, useValue: new ActivatedRouteStub() }, + { provide: LocaleService, useValue: mockLocaleService }, + { provide: APP_CONFIG, useValue: environment }, + ], + schemas: [NO_ERRORS_SCHEMA], + }).overrideComponent(ExtendedFileSectionComponent, { + remove: { + imports: [ + PaginationComponent, + ThemedFileDownloadLinkComponent, + ], + }, + }).compileComponents(); + })); + + beforeEach(waitForAsync(() => { + localeService = TestBed.inject(LocaleService); + localeService.getCurrentLanguageCode.and.returnValue(of('en')); + fixture = TestBed.createComponent(ExtendedFileSectionComponent); + component = fixture.componentInstance; + component.item = mockItem; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set pageSize from appConfig', () => { + expect(component.pageSize).toEqual(environment.item.bitstream.pageSize); + }); + + describe('when the extended file section gets loaded with bitstreams available', () => { + it('should contain a list with bitstream', () => { + const fileSection = fixture.debugElement.queryAll(By.css('.file-section-entry')); + expect(fileSection.length).toEqual(1); + }); + }); +}); diff --git a/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.ts b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.ts new file mode 100644 index 00000000000..174f2ee1cf7 --- /dev/null +++ b/src/app/item-page/simple/field-components/extended-file-section/extended-file-section.component.ts @@ -0,0 +1,97 @@ +import { AsyncPipe } from '@angular/common'; +import { + Component, + Inject, + Input, + OnInit, +} from '@angular/core'; +import { + APP_CONFIG, + AppConfig, +} from '@dspace/config/app-config.interface'; +import { DSONameService } from '@dspace/core/breadcrumbs/dso-name.service'; +import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service'; +import { BitstreamFormatDataService } from '@dspace/core/data/bitstream-format-data.service'; +import { PaginatedList } from '@dspace/core/data/paginated-list.model'; +import { RemoteData } from '@dspace/core/data/remote-data'; +import { PaginationService } from '@dspace/core/pagination/pagination.service'; +import { PaginationComponentOptions } from '@dspace/core/pagination/pagination-component-options.model'; +import { Bitstream } from '@dspace/core/shared/bitstream.model'; +import { followLink } from '@dspace/core/shared/follow-link-config.model'; +import { Item } from '@dspace/core/shared/item.model'; +import { TranslateModule } from '@ngx-translate/core'; +import { + from, + Observable, +} from 'rxjs'; +import { switchMap } from 'rxjs/operators'; + +import { ThemedFileDownloadLinkComponent } from '../../../../shared/file-download-link/themed-file-download-link.component'; +import { PaginationComponent } from '../../../../shared/pagination/pagination.component'; +import { FileSizePipe } from '../../../../shared/utils/file-size-pipe'; +import { VarDirective } from '../../../../shared/utils/var.directive'; + +@Component({ + selector: 'ds-extended-file-section', + imports: [ + AsyncPipe, + FileSizePipe, + PaginationComponent, + ThemedFileDownloadLinkComponent, + TranslateModule, + VarDirective, + ], + templateUrl: './extended-file-section.component.html', + styleUrl: './extended-file-section.component.scss', +}) +export class ExtendedFileSectionComponent implements OnInit { + + @Input() item: Item; + + @Input() bundleName = 'ORIGINAL'; + + @Input() label = 'item.page.extended-file-section'; + + bitstreamsRD$: Observable>>; + + pageSize = this.appConfig.item.bitstream.pageSize; + + + /** + * The current pagination configuration for the page + */ + pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { + id: 'efs', + currentPage: 1, + pageSize: this.appConfig.item.bitstream.pageSize, + }); + + + constructor( + protected bitstreamDataService: BitstreamDataService, + protected bitstreamFormatDataService: BitstreamFormatDataService, + public dsoNameService: DSONameService, + @Inject(APP_CONFIG) protected appConfig: AppConfig, + private paginationService: PaginationService, + ) { + this.bitstreamsRD$ = from([]); + } + + ngOnInit(): void { + this.bitstreamsRD$ = this.paginationService.getCurrentPagination(this.pageConfig.id, this.pageConfig).pipe( + switchMap((options: PaginationComponentOptions) => { + return this.bitstreamDataService.findAllByItemAndBundleName( + this.item, + this.bundleName, + { elementsPerPage: options.pageSize, currentPage: options.currentPage }, + true, + true, + followLink('format'), + followLink('accessStatus'), + ); + }), + ); + } + + +} diff --git a/src/app/item-page/simple/item-types/dataset/dataset.component.html b/src/app/item-page/simple/item-types/dataset/dataset.component.html new file mode 100644 index 00000000000..756420f7f89 --- /dev/null +++ b/src/app/item-page/simple/item-types/dataset/dataset.component.html @@ -0,0 +1,107 @@ +@if (showBackButton$ | async) { + +} +@if (iiifEnabled) { +
+
+ + +
+
+} +
+ + + +
+
+
+ @if (!(mediaViewer.image || mediaViewer.video)) { + + + + } + @if (mediaViewer.image || mediaViewer.video) { +
+ +
+ } + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + @if (geospatialItemPageFieldsEnabled) { + + + } +
+ + {{"item.page.link.full" | translate}} + +
+
+
+ + +
+
diff --git a/src/app/item-page/simple/item-types/dataset/dataset.component.scss b/src/app/item-page/simple/item-types/dataset/dataset.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/app/item-page/simple/item-types/dataset/dataset.component.spec.ts b/src/app/item-page/simple/item-types/dataset/dataset.component.spec.ts new file mode 100644 index 00000000000..0b335118b9d --- /dev/null +++ b/src/app/item-page/simple/item-types/dataset/dataset.component.spec.ts @@ -0,0 +1,273 @@ +import { HttpClient } from '@angular/common/http'; +import { + ChangeDetectionStrategy, + NO_ERRORS_SCHEMA, +} from '@angular/core'; +import { + ComponentFixture, + fakeAsync, + TestBed, + tick, + waitForAsync, +} from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { RouterTestingModule } from '@angular/router/testing'; +import { APP_CONFIG } from '@dspace/config/app-config.interface'; +import { BrowseDefinitionDataService } from '@dspace/core/browse/browse-definition-data.service'; +import { RemoteDataBuildService } from '@dspace/core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '@dspace/core/cache/object-cache.service'; +import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service'; +import { CommunityDataService } from '@dspace/core/data/community-data.service'; +import { DefaultChangeAnalyzer } from '@dspace/core/data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '@dspace/core/data/dso-change-analyzer.service'; +import { ItemDataService } from '@dspace/core/data/item-data.service'; +import { RelationshipDataService } from '@dspace/core/data/relationship-data.service'; +import { RemoteData } from '@dspace/core/data/remote-data'; +import { VersionDataService } from '@dspace/core/data/version-data.service'; +import { VersionHistoryDataService } from '@dspace/core/data/version-history-data.service'; +import { APP_DATA_SERVICES_MAP } from '@dspace/core/data-services-map-type'; +import { NotificationsService } from '@dspace/core/notification-system/notifications.service'; +import { RouteService } from '@dspace/core/services/route.service'; +import { Bitstream } from '@dspace/core/shared/bitstream.model'; +import { HALEndpointService } from '@dspace/core/shared/hal-endpoint.service'; +import { Item } from '@dspace/core/shared/item.model'; +import { MetadataMap } from '@dspace/core/shared/metadata.models'; +import { UUIDService } from '@dspace/core/shared/uuid.service'; +import { WorkspaceitemDataService } from '@dspace/core/submission/workspaceitem-data.service'; +import { BrowseDefinitionDataServiceStub } from '@dspace/core/testing/browse-definition-data-service.stub'; +import { mockTruncatableService } from '@dspace/core/testing/mock-trucatable.service'; +import { TranslateLoaderMock } from '@dspace/core/testing/translate-loader.mock'; +import { createPaginatedList } from '@dspace/core/testing/utils.test'; +import { createSuccessfulRemoteDataObject$ } from '@dspace/core/utilities/remote-data.utils'; +import { Store } from '@ngrx/store'; +import { + TranslateLoader, + TranslateModule, +} from '@ngx-translate/core'; +import { + Observable, + of, +} from 'rxjs'; + +import { environment } from '../../../../../environments/environment.test'; +import { DsoEditMenuComponent } from '../../../../shared/dso-page/dso-edit-menu/dso-edit-menu.component'; +import { MetadataFieldWrapperComponent } from '../../../../shared/metadata-field-wrapper/metadata-field-wrapper.component'; +import { ThemedResultsBackButtonComponent } from '../../../../shared/results-back-button/themed-results-back-button.component'; +import { SearchService } from '../../../../shared/search/search.service'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { ThemedThumbnailComponent } from '../../../../thumbnail/themed-thumbnail.component'; +import { CollectionsComponent } from '../../../field-components/collections/collections.component'; +import { ThemedMediaViewerComponent } from '../../../media-viewer/themed-media-viewer.component'; +import { MiradorViewerComponent } from '../../../mirador-viewer/mirador-viewer.component'; +import { ExtendedFileSectionComponent } from '../../field-components/extended-file-section/extended-file-section.component'; +import { ItemPageAbstractFieldComponent } from '../../field-components/specific-field/abstract/item-page-abstract-field.component'; +import { ItemPageDateFieldComponent } from '../../field-components/specific-field/date/item-page-date-field.component'; +import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component'; +import { GeospatialItemPageFieldComponent } from '../../field-components/specific-field/geospatial/geospatial-item-page-field.component'; +import { ThemedItemPageTitleFieldComponent } from '../../field-components/specific-field/title/themed-item-page-field.component'; +import { ItemPageUriFieldComponent } from '../../field-components/specific-field/uri/item-page-uri-field.component'; +import { ThemedMetadataRepresentationListComponent } from '../../metadata-representation-list/themed-metadata-representation-list.component'; +import { RelatedItemsComponent } from '../../related-items/related-items-component'; +import { + createRelationshipsObservable, + getIIIFEnabled, + getIIIFSearchEnabled, + mockRouteService, +} from '../shared/item.component.spec'; +import { DatasetComponent } from './dataset.component'; + +const noMetadata = new MetadataMap(); + +function getItem(metadata: MetadataMap) { + return Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), + metadata: metadata, + relationships: createRelationshipsObservable(), + }); +} + +describe('DatasetComponent', () => { + let comp: DatasetComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + }, + }; + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock, + }, + }), + RouterTestingModule, + GenericItemPageFieldComponent, TruncatePipe, + DatasetComponent, + ], + providers: [ + { provide: ItemDataService, useValue: {} }, + { provide: TruncatableService, useValue: mockTruncatableService }, + { provide: RelationshipDataService, useValue: {} }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: Store, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: NotificationsService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: VersionHistoryDataService, useValue: {} }, + { provide: VersionDataService, useValue: {} }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, + { provide: WorkspaceitemDataService, useValue: {} }, + { provide: SearchService, useValue: {} }, + { provide: RouteService, useValue: mockRouteService }, + { provide: BrowseDefinitionDataService, useValue: BrowseDefinitionDataServiceStub }, + { provide: APP_CONFIG, useValue: environment }, + { provide: APP_DATA_SERVICES_MAP, useValue: {} }, + ], + schemas: [NO_ERRORS_SCHEMA], + }).overrideComponent(DatasetComponent, { + add: { changeDetection: ChangeDetectionStrategy.Default }, + remove: { + imports: [ThemedResultsBackButtonComponent, MiradorViewerComponent, ThemedItemPageTitleFieldComponent, DsoEditMenuComponent, MetadataFieldWrapperComponent, ThemedThumbnailComponent, ThemedMediaViewerComponent, ExtendedFileSectionComponent, ItemPageDateFieldComponent, ThemedMetadataRepresentationListComponent, GenericItemPageFieldComponent, RelatedItemsComponent, ItemPageAbstractFieldComponent, ItemPageUriFieldComponent, CollectionsComponent, GeospatialItemPageFieldComponent], + }, + }); + })); + + describe('default view', () => { + beforeEach(waitForAsync(() => { + TestBed.compileComponents(); + fixture = TestBed.createComponent(DatasetComponent); + comp = fixture.componentInstance; + comp.object = getItem(noMetadata); + fixture.detectChanges(); + })); + + it('should contain a component to display the date', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-date-field')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should not contain a metadata only author field', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-author-field')); + expect(fields.length).toBe(0); + }); + + it('should contain a mixed metadata and relationship field for authors', () => { + const fields = fixture.debugElement.queryAll(By.css('.ds-item-page-mixed-author-field')); + expect(fields.length).toBe(1); + }); + + it('should contain a component to display the abstract', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-abstract-field')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should contain a component to display the uri', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-uri-field')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should contain a component to display the collections', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-collections')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + }); + + describe('with IIIF viewer', () => { + + beforeEach(waitForAsync(() => { + const iiifEnabledMap: MetadataMap = { + 'dspace.iiif.enabled': [getIIIFEnabled(true)], + 'iiif.search.enabled': [getIIIFSearchEnabled(false)], + }; + TestBed.compileComponents(); + fixture = TestBed.createComponent(DatasetComponent); + comp = fixture.componentInstance; + comp.object = getItem(iiifEnabledMap); + fixture.detectChanges(); + })); + + it('should contain an iiif viewer component', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-mirador-viewer')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + it('should not retrieve the query term for previous route', fakeAsync((): void => { + //tick(10) + expect(comp.iiifQuery$).toBeFalsy(); + })); + + }); + + describe('with IIIF viewer and search', () => { + + const localMockRouteService = { + getPreviousUrl(): Observable { + return of('/search?query=test%20query&fakeParam=true'); + }, + }; + beforeEach(waitForAsync(() => { + const iiifEnabledMap: MetadataMap = { + 'dspace.iiif.enabled': [getIIIFEnabled(true)], + 'iiif.search.enabled': [getIIIFSearchEnabled(true)], + }; + TestBed.overrideProvider(RouteService, { useValue: localMockRouteService }); + TestBed.compileComponents(); + fixture = TestBed.createComponent(DatasetComponent); + comp = fixture.componentInstance; + comp.object = getItem(iiifEnabledMap); + fixture.detectChanges(); + })); + + it('should contain an iiif viewer component', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-mirador-viewer')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should retrieve the query term for previous route', fakeAsync((): void => { + expect(comp.iiifQuery$.subscribe(result => expect(result).toEqual('test query'))); + })); + + }); + + describe('with IIIF viewer and search but no previous search query', () => { + const localMockRouteService = { + getPreviousUrl(): Observable { + return of('/item'); + }, + }; + beforeEach(waitForAsync(() => { + const iiifEnabledMap: MetadataMap = { + 'dspace.iiif.enabled': [getIIIFEnabled(true)], + 'iiif.search.enabled': [getIIIFSearchEnabled(true)], + }; + TestBed.overrideProvider(RouteService, { useValue: localMockRouteService }); + TestBed.compileComponents(); + fixture = TestBed.createComponent(DatasetComponent); + comp = fixture.componentInstance; + comp.object = getItem(iiifEnabledMap); + fixture.detectChanges(); + })); + + it('should contain an iiif viewer component', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-mirador-viewer')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should not retrieve the query term for previous route', fakeAsync( () => { + let emitted; + comp.iiifQuery$.subscribe(result => emitted = result); + tick(10); + expect(emitted).toBeUndefined(); + })); + + }); +}); diff --git a/src/app/item-page/simple/item-types/dataset/dataset.component.ts b/src/app/item-page/simple/item-types/dataset/dataset.component.ts new file mode 100644 index 00000000000..ed156a22549 --- /dev/null +++ b/src/app/item-page/simple/item-types/dataset/dataset.component.ts @@ -0,0 +1,59 @@ +import { AsyncPipe } from '@angular/common'; +import { Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { ViewMode } from '@dspace/core/shared/view-mode.model'; +import { TranslatePipe } from '@ngx-translate/core'; + +import { DsoEditMenuComponent } from '../../../../shared/dso-page/dso-edit-menu/dso-edit-menu.component'; +import { MetadataFieldWrapperComponent } from '../../../../shared/metadata-field-wrapper/metadata-field-wrapper.component'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ThemedResultsBackButtonComponent } from '../../../../shared/results-back-button/themed-results-back-button.component'; +import { ThemedThumbnailComponent } from '../../../../thumbnail/themed-thumbnail.component'; +import { CollectionsComponent } from '../../../field-components/collections/collections.component'; +import { ThemedMediaViewerComponent } from '../../../media-viewer/themed-media-viewer.component'; +import { MiradorViewerComponent } from '../../../mirador-viewer/mirador-viewer.component'; +import { ExtendedFileSectionComponent } from '../../field-components/extended-file-section/extended-file-section.component'; +import { ItemPageAbstractFieldComponent } from '../../field-components/specific-field/abstract/item-page-abstract-field.component'; +import { ItemPageDateFieldComponent } from '../../field-components/specific-field/date/item-page-date-field.component'; +import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component'; +import { GeospatialItemPageFieldComponent } from '../../field-components/specific-field/geospatial/geospatial-item-page-field.component'; +import { ThemedItemPageTitleFieldComponent } from '../../field-components/specific-field/title/themed-item-page-field.component'; +import { ItemPageUriFieldComponent } from '../../field-components/specific-field/uri/item-page-uri-field.component'; +import { ThemedMetadataRepresentationListComponent } from '../../metadata-representation-list/themed-metadata-representation-list.component'; +import { RelatedItemsComponent } from '../../related-items/related-items-component'; +import { ItemComponent } from '../shared/item.component'; + +/** + * Component that represents a Dataset Item page + */ + +@listableObjectComponent('Dataset', ViewMode.StandalonePage) +@Component({ + selector: 'ds-dataset', + imports: [ + AsyncPipe, + CollectionsComponent, + DsoEditMenuComponent, + ExtendedFileSectionComponent, + GenericItemPageFieldComponent, + GeospatialItemPageFieldComponent, + ItemPageAbstractFieldComponent, + ItemPageDateFieldComponent, + ItemPageUriFieldComponent, + MetadataFieldWrapperComponent, + MiradorViewerComponent, + RelatedItemsComponent, + RouterLink, + ThemedItemPageTitleFieldComponent, + ThemedMediaViewerComponent, + ThemedMetadataRepresentationListComponent, + ThemedResultsBackButtonComponent, + ThemedThumbnailComponent, + TranslatePipe, + ], + templateUrl: './dataset.component.html', + styleUrl: './dataset.component.scss', +}) +export class DatasetComponent extends ItemComponent { + +} diff --git a/src/app/shared/listable.module.ts b/src/app/shared/listable.module.ts index cf417129e6b..f98996006db 100644 --- a/src/app/shared/listable.module.ts +++ b/src/app/shared/listable.module.ts @@ -68,6 +68,7 @@ import { ItemPageDateFieldComponent } from '../item-page/simple/field-components import { GenericItemPageFieldComponent } from '../item-page/simple/field-components/specific-field/generic/generic-item-page-field.component'; import { ThemedItemPageTitleFieldComponent } from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component'; import { ItemPageUriFieldComponent } from '../item-page/simple/field-components/specific-field/uri/item-page-uri-field.component'; +import { DatasetComponent } from '../item-page/simple/item-types/dataset/dataset.component'; import { PublicationComponent } from '../item-page/simple/item-types/publication/publication.component'; import { UntypedItemComponent } from '../item-page/simple/item-types/untyped-item/untyped-item.component'; import { ThemedMetadataRepresentationListComponent } from '../item-page/simple/metadata-representation-list/themed-metadata-representation-list.component'; @@ -208,6 +209,7 @@ const ENTRY_COMPONENTS = [ PoolSearchResultDetailElementComponent, ItemSearchResultListElementSubmissionComponent, PublicationComponent, + DatasetComponent, UntypedItemComponent, ]; diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 0fc94d16210..c99e1f4deeb 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -7291,4 +7291,40 @@ "item.preview.organization.address.addressLocality": "City", "item.preview.organization.alternateName": "Alternative name", + + "item.page.extended-file-section": "Bitstreams", + + "file.section.name": "Document", + + "file.section.type": "Type", + + "file.section.size": "Size", + + "dataset.page.titleprefix": "Dataset", + + "dataset.listelement.badge": "Dataset", + + "dataset.page.options": "Options", + + "dataset.page.edit": "Edit this Dataset", + + "relationships.Dataset.isAuthorOfDataset.Person": "Authors (Persons)", + + "relationships.Dataset.isProjectOfDataset.Project": "Research Projects", + + "relationships.Dataset.isAuthorOfDataset.OrgUnit": "Organizational Units", + + "relationships.Dataset.isOrgUnitOfDataset.OrgUnit": "Authors (Organizational Units)", + + "relationships.Dataset.isPublicationOfDataset.Publication": "Publications", + + "relationships.Publication.isDatasetOfPublication.Dataset": "Datasets", + + "relationships.Person.isDatasetOfAuthor.Dataset": "Datasets", + + "relationships.Project.isDatasetOfProject.Dataset": "Datasets", + + "relationships.OrgUnit.isDatasetOfAuthor.Dataset": "Authored Datasets", + + "relationships.OrgUnit.isDatasetOfOrgUnit.Dataset": "Organisation Datasets", }