+
diff --git a/src/app/shared/item/item-versions/notice/item-versions-notice.component.html b/src/app/shared/item/item-versions/notice/item-versions-notice.component.html
new file mode 100644
index 0000000000..cec0bdcb04
--- /dev/null
+++ b/src/app/shared/item/item-versions/notice/item-versions-notice.component.html
@@ -0,0 +1,5 @@
+
+
diff --git a/src/app/shared/item/item-versions/notice/item-versions-notice.component.spec.ts b/src/app/shared/item/item-versions/notice/item-versions-notice.component.spec.ts
new file mode 100644
index 0000000000..ffcd1d897e
--- /dev/null
+++ b/src/app/shared/item/item-versions/notice/item-versions-notice.component.spec.ts
@@ -0,0 +1,93 @@
+import { ItemVersionsNoticeComponent } from './item-versions-notice.component';
+import { async, ComponentFixture, TestBed } 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 { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../../testing/utils';
+import { Item } from '../../../../core/shared/item.model';
+import { VersionHistoryDataService } from '../../../../core/data/version-history-data.service';
+import { By } from '@angular/platform-browser';
+
+describe('ItemVersionsNoticeComponent', () => {
+ let component: ItemVersionsNoticeComponent;
+ let fixture: ComponentFixture;
+
+ const versionHistory = Object.assign(new VersionHistory(), {
+ id: '1'
+ });
+ const firstVersion = Object.assign(new Version(), {
+ id: '1',
+ version: 1,
+ created: new Date(2020, 1, 1),
+ summary: 'first version',
+ versionhistory: createSuccessfulRemoteDataObject$(versionHistory)
+ });
+ const latestVersion = Object.assign(new Version(), {
+ id: '2',
+ version: 2,
+ summary: 'latest version',
+ created: new Date(2020, 1, 2),
+ versionhistory: createSuccessfulRemoteDataObject$(versionHistory)
+ });
+ const versions = [latestVersion, firstVersion];
+ versionHistory.versions = createSuccessfulRemoteDataObject$(createPaginatedList(versions));
+ const firstItem = Object.assign(new Item(), {
+ id: 'first_item_id',
+ uuid: 'first_item_id',
+ handle: '123456789/1',
+ version: createSuccessfulRemoteDataObject$(firstVersion)
+ });
+ const latestItem = Object.assign(new Item(), {
+ id: 'latest_item_id',
+ uuid: 'latest_item_id',
+ handle: '123456789/2',
+ version: createSuccessfulRemoteDataObject$(latestVersion)
+ });
+ firstVersion.item = createSuccessfulRemoteDataObject$(firstItem);
+ latestVersion.item = createSuccessfulRemoteDataObject$(latestItem);
+ const versionHistoryService = jasmine.createSpyObj('versionHistoryService', {
+ getVersions: createSuccessfulRemoteDataObject$(createPaginatedList(versions))
+ });
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ItemVersionsNoticeComponent],
+ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])],
+ providers: [
+ { provide: VersionHistoryDataService, useValue: versionHistoryService }
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ describe('when the item is the latest version', () => {
+ beforeEach(() => {
+ initComponentWithItem(latestItem);
+ });
+
+ it('should not display a notice', () => {
+ const alert = fixture.debugElement.query(By.css('ds-alert'));
+ expect(alert).toBeNull();
+ });
+ });
+
+ describe('when the item is not the latest version', () => {
+ beforeEach(() => {
+ initComponentWithItem(firstItem);
+ });
+
+ it('should display a notice', () => {
+ const alert = fixture.debugElement.query(By.css('ds-alert'));
+ expect(alert).not.toBeNull();
+ });
+ });
+
+ function initComponentWithItem(item: Item) {
+ fixture = TestBed.createComponent(ItemVersionsNoticeComponent);
+ component = fixture.componentInstance;
+ component.item = item;
+ fixture.detectChanges();
+ }
+});
diff --git a/src/app/shared/item/item-versions/notice/item-versions-notice.component.ts b/src/app/shared/item/item-versions/notice/item-versions-notice.component.ts
new file mode 100644
index 0000000000..c2bd316137
--- /dev/null
+++ b/src/app/shared/item/item-versions/notice/item-versions-notice.component.ts
@@ -0,0 +1,114 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { Item } from '../../../../core/shared/item.model';
+import { PaginationComponentOptions } from '../../../pagination/pagination-component-options.model';
+import { PaginatedSearchOptions } from '../../../search/paginated-search-options.model';
+import { Observable } from 'rxjs/internal/Observable';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { VersionHistory } from '../../../../core/shared/version-history.model';
+import { Version } from '../../../../core/shared/version.model';
+import { hasValue } from '../../../empty.util';
+import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../core/shared/operators';
+import { filter, map, startWith, switchMap } from 'rxjs/operators';
+import { followLink } from '../../../utils/follow-link-config.model';
+import { VersionHistoryDataService } from '../../../../core/data/version-history-data.service';
+import { AlertType } from '../../../alert/aletr-type';
+import { combineLatest as observableCombineLatest } from 'rxjs';
+import { getItemPageRoute } from '../../../../+item-page/item-page-routing.module';
+
+@Component({
+ selector: 'ds-item-versions-notice',
+ templateUrl: './item-versions-notice.component.html'
+})
+/**
+ * Component for displaying a warning notice when the item is not the latest version within its version history
+ * The notice contains a link to the latest version's item page
+ */
+export class ItemVersionsNoticeComponent implements OnInit {
+ /**
+ * The item to display a version notice for
+ */
+ @Input() item: Item;
+
+ /**
+ * The item's version
+ */
+ versionRD$: Observable>;
+
+ /**
+ * The item's full version history
+ */
+ versionHistoryRD$: Observable>;
+
+ /**
+ * The latest version of the item's version history
+ */
+ latestVersion$: Observable;
+
+ /**
+ * Is the item's version equal to the latest version from the version history?
+ * This will determine whether or not to display a notice linking to the latest version
+ */
+ isLatestVersion$: Observable;
+
+ /**
+ * Pagination options to fetch a single version on the first page (this is the latest version in the history)
+ */
+ latestVersionOptions = Object.assign(new PaginationComponentOptions(),{
+ id: 'item-newest-version-options',
+ currentPage: 1,
+ pageSize: 1
+ });
+
+ /**
+ * The AlertType enumeration
+ * @type {AlertType}
+ */
+ public AlertTypeEnum = AlertType;
+
+ constructor(private versionHistoryService: VersionHistoryDataService) {
+ }
+
+ /**
+ * Initialize the component's observables
+ */
+ ngOnInit(): void {
+ const latestVersionSearch = new PaginatedSearchOptions({pagination: this.latestVersionOptions});
+ if (hasValue(this.item.version)) {
+ this.versionRD$ = this.item.version;
+ this.versionHistoryRD$ = this.versionRD$.pipe(
+ getAllSucceededRemoteData(),
+ getRemoteDataPayload(),
+ switchMap((version: Version) => version.versionhistory)
+ );
+ const versionHistory$ = this.versionHistoryRD$.pipe(
+ getAllSucceededRemoteData(),
+ getRemoteDataPayload(),
+ );
+ this.latestVersion$ = versionHistory$.pipe(
+ switchMap((versionHistory: VersionHistory) =>
+ this.versionHistoryService.getVersions(versionHistory.id, latestVersionSearch, followLink('item'))),
+ getAllSucceededRemoteData(),
+ getRemoteDataPayload(),
+ filter((versions) => versions.page.length > 0),
+ map((versions) => versions.page[0])
+ );
+
+ this.isLatestVersion$ = observableCombineLatest(
+ this.versionRD$.pipe(getAllSucceededRemoteData(), getRemoteDataPayload()), this.latestVersion$
+ ).pipe(
+ map(([itemVersion, latestVersion]: [Version, Version]) => itemVersion.id === latestVersion.id),
+ startWith(true)
+ )
+ }
+ }
+
+ /**
+ * Get the item page url
+ * @param item The item for which the url is requested
+ */
+ getItemPage(item: Item): string {
+ if (hasValue(item)) {
+ return getItemPageRoute(item.id);
+ }
+ }
+}
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index b8cf064bc4..18275f8f3b 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -181,6 +181,7 @@ import { SortablejsModule } from 'ngx-sortablejs';
import { CustomSwitchComponent } from './form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.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';
const MODULES = [
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
@@ -352,6 +353,7 @@ const COMPONENTS = [
ExistingMetadataListElementComponent,
ItemVersionsComponent,
PublicationSearchResultListElementComponent,
+ ItemVersionsNoticeComponent
];
const ENTRY_COMPONENTS = [
@@ -417,7 +419,8 @@ const ENTRY_COMPONENTS = [
DsDynamicLookupRelationExternalSourceTabComponent,
ExternalSourceEntryImportModalComponent,
ItemVersionsComponent,
- BundleListElementComponent
+ BundleListElementComponent,
+ ItemVersionsNoticeComponent
];
const SHARED_ITEM_PAGE_COMPONENTS = [