75939: (edit) item links refactored to contain entity types

This commit is contained in:
Kristof De Langhe
2021-01-15 16:33:27 +01:00
parent 1942e0e2ba
commit 8e75132086
93 changed files with 392 additions and 199 deletions

View File

@@ -56,19 +56,19 @@ describe('ItemAdminSearchResultActionsComponent', () => {
it('should render an edit button with the correct link', () => { it('should render an edit button with the correct link', () => {
const button = fixture.debugElement.query(By.css('a.edit-link')); const button = fixture.debugElement.query(By.css('a.edit-link'));
const link = button.nativeElement.href; const link = button.nativeElement.href;
expect(link).toContain(getItemEditRoute(id)); expect(link).toContain(getItemEditRoute(item));
}); });
it('should render a delete button with the correct link', () => { it('should render a delete button with the correct link', () => {
const button = fixture.debugElement.query(By.css('a.delete-link')); const button = fixture.debugElement.query(By.css('a.delete-link'));
const link = button.nativeElement.href; const link = button.nativeElement.href;
expect(link).toContain(new URLCombiner(getItemEditRoute(id), ITEM_EDIT_DELETE_PATH).toString()); expect(link).toContain(new URLCombiner(getItemEditRoute(item), ITEM_EDIT_DELETE_PATH).toString());
}); });
it('should render a move button with the correct link', () => { it('should render a move button with the correct link', () => {
const a = fixture.debugElement.query(By.css('a.move-link')); const a = fixture.debugElement.query(By.css('a.move-link'));
const link = a.nativeElement.href; const link = a.nativeElement.href;
expect(link).toContain(new URLCombiner(getItemEditRoute(id), ITEM_EDIT_MOVE_PATH).toString()); expect(link).toContain(new URLCombiner(getItemEditRoute(item), ITEM_EDIT_MOVE_PATH).toString());
}); });
describe('when the item is not withdrawn', () => { describe('when the item is not withdrawn', () => {
@@ -80,7 +80,7 @@ describe('ItemAdminSearchResultActionsComponent', () => {
it('should render a withdraw button with the correct link', () => { it('should render a withdraw button with the correct link', () => {
const a = fixture.debugElement.query(By.css('a.withdraw-link')); const a = fixture.debugElement.query(By.css('a.withdraw-link'));
const link = a.nativeElement.href; const link = a.nativeElement.href;
expect(link).toContain(new URLCombiner(getItemEditRoute(id), ITEM_EDIT_WITHDRAW_PATH).toString()); expect(link).toContain(new URLCombiner(getItemEditRoute(item), ITEM_EDIT_WITHDRAW_PATH).toString());
}); });
it('should not render a reinstate button with the correct link', () => { it('should not render a reinstate button with the correct link', () => {
@@ -103,7 +103,7 @@ describe('ItemAdminSearchResultActionsComponent', () => {
it('should render a reinstate button with the correct link', () => { it('should render a reinstate button with the correct link', () => {
const a = fixture.debugElement.query(By.css('a.reinstate-link')); const a = fixture.debugElement.query(By.css('a.reinstate-link'));
const link = a.nativeElement.href; const link = a.nativeElement.href;
expect(link).toContain(new URLCombiner(getItemEditRoute(id), ITEM_EDIT_REINSTATE_PATH).toString()); expect(link).toContain(new URLCombiner(getItemEditRoute(item), ITEM_EDIT_REINSTATE_PATH).toString());
}); });
}); });
@@ -116,7 +116,7 @@ describe('ItemAdminSearchResultActionsComponent', () => {
it('should render a make private button with the correct link', () => { it('should render a make private button with the correct link', () => {
const a = fixture.debugElement.query(By.css('a.private-link')); const a = fixture.debugElement.query(By.css('a.private-link'));
const link = a.nativeElement.href; const link = a.nativeElement.href;
expect(link).toContain(new URLCombiner(getItemEditRoute(id), ITEM_EDIT_PRIVATE_PATH).toString()); expect(link).toContain(new URLCombiner(getItemEditRoute(item), ITEM_EDIT_PRIVATE_PATH).toString());
}); });
it('should not render a make public button with the correct link', () => { it('should not render a make public button with the correct link', () => {
@@ -139,7 +139,7 @@ describe('ItemAdminSearchResultActionsComponent', () => {
it('should render a make private button with the correct link', () => { it('should render a make private button with the correct link', () => {
const a = fixture.debugElement.query(By.css('a.public-link')); const a = fixture.debugElement.query(By.css('a.public-link'));
const link = a.nativeElement.href; const link = a.nativeElement.href;
expect(link).toContain(new URLCombiner(getItemEditRoute(id), ITEM_EDIT_PUBLIC_PATH).toString()); expect(link).toContain(new URLCombiner(getItemEditRoute(item), ITEM_EDIT_PUBLIC_PATH).toString());
}); });
}); });
}); });

View File

@@ -34,7 +34,7 @@ export class ItemAdminSearchResultActionsComponent {
* Returns the path to the edit page of this item * Returns the path to the edit page of this item
*/ */
getEditRoute(): string { getEditRoute(): string {
return getItemEditRoute(this.item.uuid); return getItemEditRoute(this.item);
} }
/** /**

View File

@@ -18,10 +18,14 @@ import { hasValue } from '../../shared/empty.util';
import { FormControl, FormGroup } from '@angular/forms'; import { FormControl, FormGroup } from '@angular/forms';
import { FileSizePipe } from '../../shared/utils/file-size-pipe'; import { FileSizePipe } from '../../shared/utils/file-size-pipe';
import { VarDirective } from '../../shared/utils/var.directive'; import { VarDirective } from '../../shared/utils/var.directive';
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; import {
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/remote-data.utils';
import { RouterStub } from '../../shared/testing/router.stub'; import { RouterStub } from '../../shared/testing/router.stub';
import { getItemEditRoute } from '../../+item-page/item-page-routing-paths'; import { getEntityEditRoute, getItemEditRoute } from '../../+item-page/item-page-routing-paths';
import { createPaginatedList } from '../../shared/testing/utils.test'; import { createPaginatedList } from '../../shared/testing/utils.test';
import { Item } from '../../core/shared/item.model';
const infoNotification: INotification = new Notification('id', NotificationType.Info, 'info'); const infoNotification: INotification = new Notification('id', NotificationType.Info, 'info');
const warningNotification: INotification = new Notification('id', NotificationType.Warning, 'warning'); const warningNotification: INotification = new Notification('id', NotificationType.Warning, 'warning');
@@ -109,9 +113,9 @@ describe('EditBitstreamPageComponent', () => {
self: 'bitstream-selflink' self: 'bitstream-selflink'
}, },
bundle: createSuccessfulRemoteDataObject$({ bundle: createSuccessfulRemoteDataObject$({
item: createSuccessfulRemoteDataObject$({ item: createSuccessfulRemoteDataObject$(Object.assign(new Item(), {
uuid: 'some-uuid' uuid: 'some-uuid'
}) }))
}) })
}); });
bitstreamService = jasmine.createSpyObj('bitstreamService', { bitstreamService = jasmine.createSpyObj('bitstreamService', {
@@ -237,14 +241,14 @@ describe('EditBitstreamPageComponent', () => {
it('should redirect to the item edit page on the bitstreams tab with the itemId from the component', () => { it('should redirect to the item edit page on the bitstreams tab with the itemId from the component', () => {
comp.itemId = 'some-uuid1'; comp.itemId = 'some-uuid1';
comp.navigateToItemEditBitstreams(); comp.navigateToItemEditBitstreams();
expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute('some-uuid1'), 'bitstreams']); expect(routerStub.navigate).toHaveBeenCalledWith([getEntityEditRoute(null, 'some-uuid1'), 'bitstreams']);
}); });
}); });
describe('when navigateToItemEditBitstreams is called, and the component does not have an itemId', () => { describe('when navigateToItemEditBitstreams is called, and the component does not have an itemId', () => {
it('should redirect to the item edit page on the bitstreams tab with the itemId from the bundle links ', () => { it('should redirect to the item edit page on the bitstreams tab with the itemId from the bundle links ', () => {
comp.itemId = undefined; comp.itemId = undefined;
comp.navigateToItemEditBitstreams(); comp.navigateToItemEditBitstreams();
expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute('some-uuid'), 'bitstreams']); expect(routerStub.navigate).toHaveBeenCalledWith([getEntityEditRoute(null, 'some-uuid'), 'bitstreams']);
}); });
}); });
}); });

View File

@@ -33,9 +33,8 @@ import { Metadata } from '../../core/shared/metadata.utils';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { RemoteData } from '../../core/data/remote-data'; import { RemoteData } from '../../core/data/remote-data';
import { PaginatedList } from '../../core/data/paginated-list.model'; import { PaginatedList } from '../../core/data/paginated-list.model';
import { getItemEditRoute } from '../../+item-page/item-page-routing-paths'; import { getEntityEditRoute, getItemEditRoute } from '../../+item-page/item-page-routing-paths';
import { Bundle } from '../../core/shared/bundle.model'; import { Bundle } from '../../core/shared/bundle.model';
import { Item } from '../../core/shared/item.model';
@Component({ @Component({
selector: 'ds-edit-bitstream-page', selector: 'ds-edit-bitstream-page',
@@ -264,9 +263,17 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
/** /**
* The ID of the item the bitstream originates from * The ID of the item the bitstream originates from
* Taken from the current query parameters when present * Taken from the current query parameters when present
* This will determine the route of the item edit page to return to
*/ */
itemId: string; itemId: string;
/**
* The entity type of the item the bitstream originates from
* Taken from the current query parameters when present
* This will determine the route of the item edit page to return to
*/
entityType: string;
/** /**
* Array to track all subscriptions and unsubscribe them onDestroy * Array to track all subscriptions and unsubscribe them onDestroy
* @type {Array} * @type {Array}
@@ -293,6 +300,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
this.formGroup = this.formService.createFormGroup(this.formModel); this.formGroup = this.formService.createFormGroup(this.formModel);
this.itemId = this.route.snapshot.queryParams.itemId; this.itemId = this.route.snapshot.queryParams.itemId;
this.entityType = this.route.snapshot.queryParams.entityType;
this.bitstreamRD$ = this.route.data.pipe(map((data) => data.bitstream)); this.bitstreamRD$ = this.route.data.pipe(map((data) => data.bitstream));
this.bitstreamFormatsRD$ = this.bitstreamFormatService.findAll(this.findAllOptions); this.bitstreamFormatsRD$ = this.bitstreamFormatService.findAll(this.findAllOptions);
@@ -499,10 +507,10 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
*/ */
navigateToItemEditBitstreams() { navigateToItemEditBitstreams() {
if (hasValue(this.itemId)) { if (hasValue(this.itemId)) {
this.router.navigate([getItemEditRoute(this.itemId), 'bitstreams']); this.router.navigate([getEntityEditRoute(this.entityType, this.itemId), 'bitstreams']);
} else { } else {
this.bitstream.bundle.pipe(getFirstSucceededRemoteDataPayload(), this.bitstream.bundle.pipe(getFirstSucceededRemoteDataPayload(),
mergeMap((bundle: Bundle) => bundle.item.pipe(getFirstSucceededRemoteDataPayload(), map((item: Item) => item.uuid)))) mergeMap((bundle: Bundle) => bundle.item.pipe(getFirstSucceededRemoteDataPayload())))
.subscribe((item) => { .subscribe((item) => {
this.router.navigate(([getItemEditRoute(item), 'bitstreams'])); this.router.navigate(([getItemEditRoute(item), 'bitstreams']));
}); });

View File

@@ -35,7 +35,7 @@
</ds-comcol-page-content> </ds-comcol-page-content>
</header> </header>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'collections'" [dso]="collection" [tooltipMsg]="'collection.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="collectionPageRoute$ | async" [dso]="collection" [tooltipMsg]="'collection.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<section class="comcol-page-browse-section"> <section class="comcol-page-browse-section">

View File

@@ -15,12 +15,18 @@ import { Bitstream } from '../core/shared/bitstream.model';
import { Collection } from '../core/shared/collection.model'; import { Collection } from '../core/shared/collection.model';
import { DSpaceObjectType } from '../core/shared/dspace-object-type.model'; import { DSpaceObjectType } from '../core/shared/dspace-object-type.model';
import { Item } from '../core/shared/item.model'; import { Item } from '../core/shared/item.model';
import { getFirstSucceededRemoteData, redirectOn4xx, toDSpaceObjectListRD } from '../core/shared/operators'; import {
getAllSucceededRemoteDataPayload,
getFirstSucceededRemoteData,
redirectOn4xx,
toDSpaceObjectListRD
} from '../core/shared/operators';
import { fadeIn, fadeInOut } from '../shared/animations/fade'; import { fadeIn, fadeInOut } from '../shared/animations/fade';
import { hasValue, isNotEmpty } from '../shared/empty.util'; import { hasValue, isNotEmpty } from '../shared/empty.util';
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
import { AuthService } from '../core/auth/auth.service'; import { AuthService } from '../core/auth/auth.service';
import { getCollectionPageRoute } from './collection-page-routing-paths';
@Component({ @Component({
selector: 'ds-collection-page', selector: 'ds-collection-page',
@@ -43,6 +49,11 @@ export class CollectionPageComponent implements OnInit {
sortConfig: SortOptions sortConfig: SortOptions
}>; }>;
/**
* Route to the community page
*/
collectionPageRoute$: Observable<string>;
constructor( constructor(
private collectionDataService: CollectionDataService, private collectionDataService: CollectionDataService,
private searchService: SearchService, private searchService: SearchService,
@@ -93,6 +104,11 @@ export class CollectionPageComponent implements OnInit {
) )
); );
this.collectionPageRoute$ = this.collectionRD$.pipe(
getAllSucceededRemoteDataPayload(),
map((collection) => getCollectionPageRoute(collection.id))
);
this.route.queryParams.pipe(take(1)).subscribe((params) => { this.route.queryParams.pipe(take(1)).subscribe((params) => {
this.metadata.processRemoteData(this.collectionRD$); this.metadata.processRemoteData(this.collectionRD$);
this.onPaginationChange(params); this.onPaginationChange(params);

View File

@@ -21,7 +21,7 @@
</ds-comcol-page-content> </ds-comcol-page-content>
</header> </header>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'communities'" [dso]="communityPayload" [tooltipMsg]="'community.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="communityPageRoute$ | async" [dso]="communityPayload" [tooltipMsg]="'community.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<section class="comcol-page-browse-section"> <section class="comcol-page-browse-section">

View File

@@ -13,8 +13,9 @@ import { MetadataService } from '../core/metadata/metadata.service';
import { fadeInOut } from '../shared/animations/fade'; import { fadeInOut } from '../shared/animations/fade';
import { hasValue } from '../shared/empty.util'; import { hasValue } from '../shared/empty.util';
import { redirectOn4xx } from '../core/shared/operators'; import { getAllSucceededRemoteDataPayload, redirectOn4xx } from '../core/shared/operators';
import { AuthService } from '../core/auth/auth.service'; import { AuthService } from '../core/auth/auth.service';
import { getCommunityPageRoute } from './community-page-routing-paths';
@Component({ @Component({
selector: 'ds-community-page', selector: 'ds-community-page',
@@ -36,6 +37,12 @@ export class CommunityPageComponent implements OnInit {
* The logo of this community * The logo of this community
*/ */
logoRD$: Observable<RemoteData<Bitstream>>; logoRD$: Observable<RemoteData<Bitstream>>;
/**
* Route to the community page
*/
communityPageRoute$: Observable<string>;
constructor( constructor(
private communityDataService: CommunityDataService, private communityDataService: CommunityDataService,
private metadata: MetadataService, private metadata: MetadataService,
@@ -55,6 +62,10 @@ export class CommunityPageComponent implements OnInit {
map((rd: RemoteData<Community>) => rd.payload), map((rd: RemoteData<Community>) => rd.payload),
filter((community: Community) => hasValue(community)), filter((community: Community) => hasValue(community)),
mergeMap((community: Community) => community.logo)); mergeMap((community: Community) => community.logo));
this.communityPageRoute$ = this.communityRD$.pipe(
getAllSucceededRemoteDataPayload(),
map((community) => getCommunityPageRoute(community.id))
);
} }
} }

View File

@@ -17,7 +17,7 @@ import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operato
import { UploaderComponent } from '../../../shared/uploader/uploader.component'; import { UploaderComponent } from '../../../shared/uploader/uploader.component';
import { RequestService } from '../../../core/data/request.service'; import { RequestService } from '../../../core/data/request.service';
import { getBitstreamModuleRoute } from '../../../app-routing-paths'; import { getBitstreamModuleRoute } from '../../../app-routing-paths';
import { getItemEditRoute } from '../../item-page-routing-paths'; import { getEntityEditRoute } from '../../item-page-routing-paths';
@Component({ @Component({
selector: 'ds-upload-bitstream', selector: 'ds-upload-bitstream',
@@ -37,6 +37,12 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
*/ */
itemId: string; itemId: string;
/**
* The entity type of the item
* This is fetched from the current URL and will determine the item's page route
*/
entityType: string;
/** /**
* The item to upload a bitstream to * The item to upload a bitstream to
*/ */
@@ -100,6 +106,7 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
*/ */
ngOnInit(): void { ngOnInit(): void {
this.itemId = this.route.snapshot.params.id; this.itemId = this.route.snapshot.params.id;
this.entityType = this.route.snapshot.params['entity-type'];
this.itemRD$ = this.route.data.pipe(map((data) => data.dso)); this.itemRD$ = this.route.data.pipe(map((data) => data.dso));
this.bundlesRD$ = this.itemRD$.pipe( this.bundlesRD$ = this.itemRD$.pipe(
switchMap((itemRD: RemoteData<Item>) => itemRD.payload.bundles) switchMap((itemRD: RemoteData<Item>) => itemRD.payload.bundles)
@@ -167,7 +174,7 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
}); });
// Bring over the item ID as a query parameter // Bring over the item ID as a query parameter
const queryParams = { itemId: this.itemId }; const queryParams = { itemId: this.itemId, entityType: this.entityType };
this.router.navigate([getBitstreamModuleRoute(), bitstream.id, 'edit'], { queryParams: queryParams }); this.router.navigate([getBitstreamModuleRoute(), bitstream.id, 'edit'], { queryParams: queryParams });
} }
@@ -193,7 +200,7 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
* When cancel is clicked, navigate back to the item's edit bitstreams page * When cancel is clicked, navigate back to the item's edit bitstreams page
*/ */
onCancel() { onCancel() {
this.router.navigate([getItemEditRoute(this.itemId), 'bitstreams']); this.router.navigate([getEntityEditRoute(this.entityType, this.itemId), 'bitstreams']);
} }
/** /**

View File

@@ -11,6 +11,7 @@ import { first, map } from 'rxjs/operators';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { AbstractTrackableComponent } from '../../../shared/trackable/abstract-trackable.component'; import { AbstractTrackableComponent } from '../../../shared/trackable/abstract-trackable.component';
import { environment } from '../../../../environments/environment'; import { environment } from '../../../../environments/environment';
import { getItemPageRoute } from '../../item-page-routing-paths';
@Component({ @Component({
selector: 'ds-abstract-item-update', selector: 'ds-abstract-item-update',
@@ -30,6 +31,11 @@ export class AbstractItemUpdateComponent extends AbstractTrackableComponent impl
*/ */
updates$: Observable<FieldUpdates>; updates$: Observable<FieldUpdates>;
/**
* Route to the item's page
*/
itemPageRoute: string;
constructor( constructor(
public itemService: ItemDataService, public itemService: ItemDataService,
public objectUpdatesService: ObjectUpdatesService, public objectUpdatesService: ObjectUpdatesService,
@@ -52,6 +58,7 @@ export class AbstractItemUpdateComponent extends AbstractTrackableComponent impl
map((data: RemoteData<Item>) => data.payload) map((data: RemoteData<Item>) => data.payload)
).subscribe((item: Item) => { ).subscribe((item: Item) => {
this.item = item; this.item = item;
this.itemPageRoute = getItemPageRoute(this.item);
this.postItemInit(); this.postItemInit();
}); });

View File

@@ -55,6 +55,6 @@ export class EditItemPageComponent implements OnInit {
* @param item The item for which the url is requested * @param item The item for which the url is requested
*/ */
getItemPage(item: Item): string { getItemPage(item: Item): string {
return getItemPageRoute(item.id); return getItemPageRoute(item);
} }
} }

View File

@@ -1,7 +1,7 @@
<div class="item-bitstreams" *ngVar="(bundles$ | async) as bundles"> <div class="item-bitstreams" *ngVar="(bundles$ | async) as bundles">
<div class="button-row top d-flex mt-2"> <div class="button-row top d-flex mt-2">
<button class="mr-auto btn btn-success" <button class="mr-auto btn btn-success"
[routerLink]="['/items/', item.id, 'bitstreams', 'new']"><i [routerLink]="[itemPageRoute, 'bitstreams', 'new']"><i
class="fas fa-upload"></i> class="fas fa-upload"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.upload-button" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.upload-button" | translate}}</span>
</button> </button>

View File

@@ -8,7 +8,7 @@
</div> </div>
<div class="{{columnSizes.columns[3].buildClasses()}} text-center row-element"> <div class="{{columnSizes.columns[3].buildClasses()}} text-center row-element">
<div class="btn-group bundle-action-buttons"> <div class="btn-group bundle-action-buttons">
<button [routerLink]="['/items/', item.id, 'bitstreams', 'new']" <button [routerLink]="[itemPageRoute, 'bitstreams', 'new']"
[queryParams]="{bundle: bundle.id}" [queryParams]="{bundle: bundle.id}"
class="btn btn-outline-success btn-sm" class="btn btn-outline-success btn-sm"
title="{{'item.edit.bitstreams.bundle.edit.buttons.upload' | translate}}"> title="{{'item.edit.bitstreams.bundle.edit.buttons.upload' | translate}}">

View File

@@ -3,6 +3,7 @@ import { Bundle } from '../../../../core/shared/bundle.model';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { ResponsiveColumnSizes } from '../../../../shared/responsive-table-sizes/responsive-column-sizes'; import { ResponsiveColumnSizes } from '../../../../shared/responsive-table-sizes/responsive-column-sizes';
import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes'; import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
import { getItemPageRoute } from '../../../item-page-routing-paths';
@Component({ @Component({
selector: 'ds-item-edit-bitstream-bundle', selector: 'ds-item-edit-bitstream-bundle',
@@ -49,11 +50,17 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
*/ */
bundleNameColumn: ResponsiveColumnSizes; bundleNameColumn: ResponsiveColumnSizes;
/**
* Route to the item's page
*/
itemPageRoute: string;
constructor(private viewContainerRef: ViewContainerRef) { constructor(private viewContainerRef: ViewContainerRef) {
} }
ngOnInit(): void { ngOnInit(): void {
this.bundleNameColumn = this.columnSizes.combineColumns(0, 2); this.bundleNameColumn = this.columnSizes.combineColumns(0, 2);
this.viewContainerRef.createEmbeddedView(this.bundleView); this.viewContainerRef.createEmbeddedView(this.bundleView);
this.itemPageRoute = getItemPageRoute(this.item);
} }
} }

View File

@@ -56,6 +56,7 @@ describe('ItemCollectionMapperComponent', () => {
const mockCollection = Object.assign(new Collection(), { id: 'collection1' }); const mockCollection = Object.assign(new Collection(), { id: 'collection1' });
const mockItem: Item = Object.assign(new Item(), { const mockItem: Item = Object.assign(new Item(), {
id: '932c7d50-d85a-44cb-b9dc-b427b12877bd', id: '932c7d50-d85a-44cb-b9dc-b427b12877bd',
uuid: '932c7d50-d85a-44cb-b9dc-b427b12877bd',
name: 'test-item' name: 'test-item'
}); });
const mockItemRD: RemoteData<Item> = createSuccessfulRemoteDataObject(mockItem); const mockItemRD: RemoteData<Item> = createSuccessfulRemoteDataObject(mockItem);
@@ -207,7 +208,7 @@ describe('ItemCollectionMapperComponent', () => {
}); });
it('should navigate to the item page', () => { it('should navigate to the item page', () => {
expect(router.navigate).toHaveBeenCalledWith(['/items/', mockItem.id]); expect(router.navigate).toHaveBeenCalledWith(['/items/' + mockItem.uuid]);
}); });
}); });

View File

@@ -25,6 +25,7 @@ import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { SearchService } from '../../../core/shared/search/search.service'; import { SearchService } from '../../../core/shared/search/search.service';
import { NoContent } from '../../../core/shared/NoContent.model'; import { NoContent } from '../../../core/shared/NoContent.model';
import { getItemPageRoute } from '../../item-page-routing-paths';
@Component({ @Component({
selector: 'ds-item-collection-mapper', selector: 'ds-item-collection-mapper',
@@ -289,7 +290,7 @@ export class ItemCollectionMapperComponent implements OnInit {
getRemoteDataPayload(), getRemoteDataPayload(),
take(1) take(1)
).subscribe((item: Item) => { ).subscribe((item: Item) => {
this.router.navigate(['/items/', item.id]); this.router.navigate([getItemPageRoute(item)]);
}); });
} }

View File

@@ -89,7 +89,7 @@
<button (click)="performAction()" <button (click)="performAction()"
class="btn btn-outline-secondary perform-action">{{confirmMessage | translate}} class="btn btn-outline-secondary perform-action">{{confirmMessage | translate}}
</button> </button>
<button [routerLink]="['/items/', item.id, 'edit']" class="btn btn-outline-secondary cancel"> <button [routerLink]="[itemPageRoute, 'edit']" class="btn btn-outline-secondary cancel">
{{cancelMessage| translate}} {{cancelMessage| translate}}
</button> </button>

View File

@@ -183,7 +183,7 @@ describe('ItemDeleteComponent', () => {
describe('notify', () => { describe('notify', () => {
it('should navigate to the item edit page on failed deletion of the item', () => { it('should navigate to the item edit page on failed deletion of the item', () => {
comp.notify(false); comp.notify(false);
expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute('fake-id')]); expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute(mockItem)]);
}); });
}); });
}); });

View File

@@ -355,7 +355,7 @@ export class ItemDeleteComponent
this.router.navigate(['']); this.router.navigate(['']);
} else { } else {
this.notificationsService.error(this.translateService.get('item.edit.' + this.messageKey + '.error')); this.notificationsService.error(this.translateService.get('item.edit.' + this.messageKey + '.error'));
this.router.navigate([getItemEditRoute(this.item.id)]); this.router.navigate([getItemEditRoute(this.item)]);
} }
} }
} }

View File

@@ -39,7 +39,7 @@
{{'item.edit.move.processing' | translate}} {{'item.edit.move.processing' | translate}}
</span> </span>
</button> </button>
<button [routerLink]="['/items/', (itemRD$ | async)?.payload?.id, 'edit']" <button [routerLink]="[(itemPageRoute$ | async), 'edit']"
class="btn btn-outline-secondary"> class="btn btn-outline-secondary">
{{'item.edit.move.cancel' | translate}} {{'item.edit.move.cancel' | translate}}
</button> </button>

View File

@@ -57,9 +57,9 @@ describe('ItemMoveComponent', () => {
const routeStub = { const routeStub = {
data: observableOf({ data: observableOf({
dso: createSuccessfulRemoteDataObject({ dso: createSuccessfulRemoteDataObject(Object.assign(new Item(), {
id: 'item1' id: 'item1'
}) }))
}) })
}; };
@@ -122,7 +122,10 @@ describe('ItemMoveComponent', () => {
}); });
describe('moveCollection', () => { describe('moveCollection', () => {
it('should call itemDataService.moveToCollection', () => { it('should call itemDataService.moveToCollection', () => {
comp.itemId = 'item-id'; comp.item = Object.assign(new Item(), {
id: 'item-id',
uuid: 'item-id',
});
comp.selectedCollectionName = 'selected-collection-id'; comp.selectedCollectionName = 'selected-collection-id';
comp.selectedCollection = collection1; comp.selectedCollection = collection1;
comp.moveCollection(); comp.moveCollection();

View File

@@ -10,7 +10,7 @@ import { NotificationsService } from '../../../shared/notifications/notification
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
getFirstSucceededRemoteData, getFirstSucceededRemoteData,
getFirstCompletedRemoteData getFirstCompletedRemoteData, getAllSucceededRemoteDataPayload
} from '../../../core/shared/operators'; } from '../../../core/shared/operators';
import { ItemDataService } from '../../../core/data/item-data.service'; import { ItemDataService } from '../../../core/data/item-data.service';
import { Observable, of as observableOf } from 'rxjs'; import { Observable, of as observableOf } from 'rxjs';
@@ -19,7 +19,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
import { SearchService } from '../../../core/shared/search/search.service'; import { SearchService } from '../../../core/shared/search/search.service';
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
import { SearchResult } from '../../../shared/search/search-result.model'; import { SearchResult } from '../../../shared/search/search-result.model';
import { getItemEditRoute } from '../../item-page-routing-paths'; import { getItemEditRoute, getItemPageRoute } from '../../item-page-routing-paths';
@Component({ @Component({
selector: 'ds-item-move', selector: 'ds-item-move',
@@ -43,11 +43,16 @@ export class ItemMoveComponent implements OnInit {
selectedCollection: Collection; selectedCollection: Collection;
canSubmit = false; canSubmit = false;
itemId: string; item: Item;
processing = false; processing = false;
pagination = new PaginationComponentOptions(); pagination = new PaginationComponentOptions();
/**
* Route to the item's page
*/
itemPageRoute$: Observable<string>;
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private router: Router, private router: Router,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
@@ -58,8 +63,12 @@ export class ItemMoveComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.itemRD$ = this.route.data.pipe(map((data) => data.dso), getFirstSucceededRemoteData()) as Observable<RemoteData<Item>>; this.itemRD$ = this.route.data.pipe(map((data) => data.dso), getFirstSucceededRemoteData()) as Observable<RemoteData<Item>>;
this.itemPageRoute$ = this.itemRD$.pipe(
getAllSucceededRemoteDataPayload(),
map((item) => getItemPageRoute(item))
);
this.itemRD$.subscribe((rd) => { this.itemRD$.subscribe((rd) => {
this.itemId = rd.payload.id; this.item = rd.payload;
} }
); );
this.pagination.pageSize = 5; this.pagination.pageSize = 5;
@@ -116,9 +125,9 @@ export class ItemMoveComponent implements OnInit {
*/ */
moveCollection() { moveCollection() {
this.processing = true; this.processing = true;
this.itemDataService.moveToCollection(this.itemId, this.selectedCollection).pipe(getFirstCompletedRemoteData()).subscribe( this.itemDataService.moveToCollection(this.item.id, this.selectedCollection).pipe(getFirstCompletedRemoteData()).subscribe(
(response: RemoteData<Collection>) => { (response: RemoteData<Collection>) => {
this.router.navigate([getItemEditRoute(this.itemId)]); this.router.navigate([getItemEditRoute(this.item)]);
if (response.hasSucceeded) { if (response.hasSucceeded) {
this.notificationsService.success(this.translateService.get('item.edit.move.success')); this.notificationsService.success(this.translateService.get('item.edit.move.success'));
} else { } else {

View File

@@ -47,9 +47,9 @@ describe('ItemReinstateComponent', () => {
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
dso: createSuccessfulRemoteDataObject({ dso: createSuccessfulRemoteDataObject(Object.assign(new Item(), {
id: 'fake-id' id: 'fake-id'
}) }))
}) })
}; };

View File

@@ -12,7 +12,7 @@
{{'item.edit.tabs.status.labels.itemPage' | translate}}: {{'item.edit.tabs.status.labels.itemPage' | translate}}:
</div> </div>
<div class="col-9 float-left status-data" id="status-itemPage"> <div class="col-9 float-left status-data" id="status-itemPage">
<a [routerLink]="getItemPage((itemRD$ | async)?.payload)">{{getItemPage((itemRD$ | async)?.payload)}}</a> <a [routerLink]="itemPageRoute$ | async">{{itemPageRoute$ | async}}</a>
</div> </div>
<div *ngFor="let operation of (operations$ | async)" class="w-100" [ngClass]="{'pt-3': operation}"> <div *ngFor="let operation of (operations$ | async)" class="w-100" [ngClass]="{'pt-3': operation}">

View File

@@ -20,6 +20,7 @@ describe('ItemStatusComponent', () => {
const mockItem = Object.assign(new Item(), { const mockItem = Object.assign(new Item(), {
id: 'fake-id', id: 'fake-id',
uuid: 'fake-id',
handle: 'fake/handle', handle: 'fake/handle',
lastModified: '2018', lastModified: '2018',
_links: { _links: {
@@ -27,7 +28,7 @@ describe('ItemStatusComponent', () => {
} }
}); });
const itemPageUrl = `items/${mockItem.id}`; const itemPageUrl = `/items/${mockItem.uuid}`;
const routeStub = { const routeStub = {
parent: { parent: {

View File

@@ -10,6 +10,7 @@ import { getItemEditRoute, getItemPageRoute } from '../../item-page-routing-path
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
import { getAllSucceededRemoteDataPayload } from '../../../core/shared/operators';
@Component({ @Component({
selector: 'ds-item-status', selector: 'ds-item-status',
@@ -50,6 +51,11 @@ export class ItemStatusComponent implements OnInit {
*/ */
actionsKeys; actionsKeys;
/**
* Route to the item's page
*/
itemPageRoute$: Observable<string>;
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private authorizationService: AuthorizationDataService) { private authorizationService: AuthorizationDataService) {
} }
@@ -109,15 +115,10 @@ export class ItemStatusComponent implements OnInit {
}); });
} }
}); });
this.itemPageRoute$ = this.itemRD$.pipe(
} getAllSucceededRemoteDataPayload(),
map((item) => getItemPageRoute(item))
/** );
* Get the url to the simple item page
* @returns {string} url
*/
getItemPage(item: Item): string {
return getItemPageRoute(item.id);
} }
/** /**
@@ -125,7 +126,7 @@ export class ItemStatusComponent implements OnInit {
* @returns {string} url * @returns {string} url
*/ */
getCurrentUrl(item: Item): string { getCurrentUrl(item: Item): string {
return getItemEditRoute(item.id); return getItemEditRoute(item);
} }
trackOperation(index: number, operation: ItemOperation) { trackOperation(index: number, operation: ItemOperation) {

View File

@@ -6,7 +6,7 @@
<ds-modify-item-overview [item]="item"></ds-modify-item-overview> <ds-modify-item-overview [item]="item"></ds-modify-item-overview>
<button (click)="performAction()" class="btn btn-outline-secondary perform-action">{{confirmMessage | translate}} <button (click)="performAction()" class="btn btn-outline-secondary perform-action">{{confirmMessage | translate}}
</button> </button>
<button [routerLink]="['/items/', item.id, 'edit']" class="btn btn-outline-secondary cancel"> <button [routerLink]="[itemPageRoute, 'edit']" class="btn btn-outline-secondary cancel">
{{cancelMessage| translate}} {{cancelMessage| translate}}
</button> </button>

View File

@@ -74,9 +74,9 @@ describe('AbstractSimpleItemActionComponent', () => {
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
dso: createSuccessfulRemoteDataObject({ dso: createSuccessfulRemoteDataObject(Object.assign(new Item(), {
id: 'fake-id' id: 'fake-id'
}) }))
}) })
}; };
@@ -136,14 +136,14 @@ describe('AbstractSimpleItemActionComponent', () => {
comp.processRestResponse(successfulRemoteData); comp.processRestResponse(successfulRemoteData);
expect(notificationsServiceStub.success).toHaveBeenCalled(); expect(notificationsServiceStub.success).toHaveBeenCalled();
expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute(mockItem.id)]); expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute(mockItem)]);
}); });
it('should process a RemoteData to navigate and display success notification', () => { it('should process a RemoteData to navigate and display success notification', () => {
comp.processRestResponse(failedRemoteData); comp.processRestResponse(failedRemoteData);
expect(notificationsServiceStub.error).toHaveBeenCalled(); expect(notificationsServiceStub.error).toHaveBeenCalled();
expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute(mockItem.id)]); expect(routerStub.navigate).toHaveBeenCalledWith([getItemEditRoute(mockItem)]);
}); });
}); });

View File

@@ -9,7 +9,7 @@ import { Observable } from 'rxjs';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators'; import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { first, map } from 'rxjs/operators'; import { first, map } from 'rxjs/operators';
import { findSuccessfulAccordingTo } from '../edit-item-operators'; import { findSuccessfulAccordingTo } from '../edit-item-operators';
import { getItemEditRoute } from '../../item-page-routing-paths'; import { getItemEditRoute, getItemPageRoute } from '../../item-page-routing-paths';
/** /**
* Component to render and handle simple item edit actions such as withdrawal and reinstatement. * Component to render and handle simple item edit actions such as withdrawal and reinstatement.
@@ -30,6 +30,11 @@ export class AbstractSimpleItemActionComponent implements OnInit {
headerMessage: string; headerMessage: string;
descriptionMessage: string; descriptionMessage: string;
/**
* Route to the item's page
*/
itemPageRoute: string;
protected predicate: Predicate<RemoteData<Item>>; protected predicate: Predicate<RemoteData<Item>>;
constructor(protected route: ActivatedRoute, constructor(protected route: ActivatedRoute,
@@ -47,6 +52,7 @@ export class AbstractSimpleItemActionComponent implements OnInit {
this.itemRD$.pipe(first()).subscribe((rd) => { this.itemRD$.pipe(first()).subscribe((rd) => {
this.item = rd.payload; this.item = rd.payload;
this.itemPageRoute = getItemPageRoute(this.item);
} }
); );
@@ -71,11 +77,11 @@ export class AbstractSimpleItemActionComponent implements OnInit {
this.itemDataService.findById(this.item.id).pipe( this.itemDataService.findById(this.item.id).pipe(
findSuccessfulAccordingTo(this.predicate)).subscribe(() => { findSuccessfulAccordingTo(this.predicate)).subscribe(() => {
this.notificationsService.success(this.translateService.get('item.edit.' + this.messageKey + '.success')); this.notificationsService.success(this.translateService.get('item.edit.' + this.messageKey + '.success'));
this.router.navigate([getItemEditRoute(this.item.id)]); this.router.navigate([getItemEditRoute(this.item)]);
}); });
} else { } else {
this.notificationsService.error(this.translateService.get('item.edit.' + this.messageKey + '.error')); this.notificationsService.error(this.translateService.get('item.edit.' + this.messageKey + '.error'));
this.router.navigate([getItemEditRoute(this.item.id)]); this.router.navigate([getItemEditRoute(this.item)]);
} }
} }

View File

@@ -7,11 +7,11 @@
<div class="d-flex flex-row"> <div class="d-flex flex-row">
<ds-item-page-title-field class="mr-auto" [item]="item"></ds-item-page-title-field> <ds-item-page-title-field class="mr-auto" [item]="item"></ds-item-page-title-field>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="item" [tooltipMsg]="'item.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute$ | async" [dso]="item" [tooltipMsg]="'item.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="simple-view-link my-3"> <div class="simple-view-link my-3">
<a class="btn btn-outline-primary" [routerLink]="['/items/' + item.id]"> <a class="btn btn-outline-primary" [routerLink]="[(itemPageRoute$ | async)]">
{{"item.page.link.simple" | translate}} {{"item.page.link.simple" | translate}}
</a> </a>
</div> </div>

View File

@@ -1,4 +1,6 @@
import { URLCombiner } from '../core/url-combiner/url-combiner'; import { URLCombiner } from '../core/url-combiner/url-combiner';
import { Item } from '../core/shared/item.model';
import { isNotEmpty } from '../shared/empty.util';
export const ITEM_MODULE_PATH = 'items'; export const ITEM_MODULE_PATH = 'items';
@@ -6,12 +8,30 @@ export function getItemModuleRoute() {
return `/${ITEM_MODULE_PATH}`; return `/${ITEM_MODULE_PATH}`;
} }
export function getItemPageRoute(itemId: string) { /**
return new URLCombiner(getItemModuleRoute(), itemId).toString(); * Get the route to an item's page
* Depending on the item's relationship type, the route will either start with /items or /entities
* @param item The item to retrieve the route for
*/
export function getItemPageRoute(item: Item) {
const type = item.firstMetadataValue('relationship.type');
return getEntityPageRoute(type, item.uuid);
} }
export function getItemEditRoute(id: string) { export function getItemEditRoute(item: Item) {
return new URLCombiner(getItemModuleRoute(), id, ITEM_EDIT_PATH).toString(); return new URLCombiner(getItemPageRoute(item), ITEM_EDIT_PATH).toString()
}
export function getEntityPageRoute(entityType: string, itemId: string) {
if (isNotEmpty(entityType)) {
return new URLCombiner('/entities', entityType, itemId).toString();
} else {
return new URLCombiner(getItemModuleRoute(), itemId).toString();
}
}
export function getEntityEditRoute(entityType: string, itemId: string) {
return new URLCombiner(getEntityPageRoute(entityType, itemId), ITEM_EDIT_PATH).toString();
} }
export const ITEM_EDIT_PATH = 'edit'; export const ITEM_EDIT_PATH = 'edit';

View File

@@ -11,9 +11,10 @@ import { Item } from '../../core/shared/item.model';
import { MetadataService } from '../../core/metadata/metadata.service'; import { MetadataService } from '../../core/metadata/metadata.service';
import { fadeInOut } from '../../shared/animations/fade'; import { fadeInOut } from '../../shared/animations/fade';
import { redirectOn4xx } from '../../core/shared/operators'; import { getAllSucceededRemoteDataPayload, redirectOn4xx } from '../../core/shared/operators';
import { ViewMode } from '../../core/shared/view-mode.model'; import { ViewMode } from '../../core/shared/view-mode.model';
import { AuthService } from '../../core/auth/auth.service'; import { AuthService } from '../../core/auth/auth.service';
import { getItemPageRoute } from '../item-page-routing-paths';
/** /**
* This component renders a simple item page. * This component renders a simple item page.
@@ -44,6 +45,11 @@ export class ItemPageComponent implements OnInit {
*/ */
viewMode = ViewMode.StandalonePage; viewMode = ViewMode.StandalonePage;
/**
* Route to the item's page
*/
itemPageRoute$: Observable<string>;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
@@ -61,5 +67,9 @@ export class ItemPageComponent implements OnInit {
redirectOn4xx(this.router, this.authService) redirectOn4xx(this.router, this.authService)
); );
this.metadataService.processRemoteData(this.itemRD$); this.metadataService.processRemoteData(this.itemRD$);
this.itemPageRoute$ = this.itemRD$.pipe(
getAllSucceededRemoteDataPayload(),
map((item) => getItemPageRoute(item))
);
} }
} }

View File

@@ -3,7 +3,7 @@
{{'publication.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values> {{'publication.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'publication.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'publication.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -74,7 +74,7 @@
</ds-item-page-uri-field> </ds-item-page-uri-field>
<ds-item-page-collections [item]="object"></ds-item-page-collections> <ds-item-page-collections [item]="object"></ds-item-page-collections>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -1,9 +1,10 @@
import { Component, Input } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service'; import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
import { Bitstream } from '../../../../core/shared/bitstream.model'; import { Bitstream } from '../../../../core/shared/bitstream.model';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators'; import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators';
import { getItemPageRoute } from '../../../item-page-routing-paths';
@Component({ @Component({
selector: 'ds-item', selector: 'ds-item',
@@ -12,12 +13,21 @@ import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/oper
/** /**
* A generic component for displaying metadata and relations of an item * A generic component for displaying metadata and relations of an item
*/ */
export class ItemComponent { export class ItemComponent implements OnInit {
@Input() object: Item; @Input() object: Item;
/**
* Route to the item page
*/
itemPageRoute: string;
constructor(protected bitstreamDataService: BitstreamDataService) { constructor(protected bitstreamDataService: BitstreamDataService) {
} }
ngOnInit(): void {
this.itemPageRoute = getItemPageRoute(this.object);
}
// TODO refactor to return RemoteData, and thumbnail template to deal with loading // TODO refactor to return RemoteData, and thumbnail template to deal with loading
getThumbnail(): Observable<Bitstream> { getThumbnail(): Observable<Bitstream> {
return this.bitstreamDataService.getThumbnailFor(this.object).pipe( return this.bitstreamDataService.getThumbnailFor(this.object).pipe(

View File

@@ -3,7 +3,7 @@
<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values> <ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'item.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'item.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -59,7 +59,7 @@
</ds-item-page-uri-field> </ds-item-page-uri-field>
<ds-item-page-collections [item]="object"></ds-item-page-collections> <ds-item-page-collections [item]="object"></ds-item-page-collections>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -51,7 +51,7 @@ export function getDSORoute(dso: DSpaceObject): string {
case Collection.type.value: case Collection.type.value:
return getCollectionPageRoute(dso.uuid); return getCollectionPageRoute(dso.uuid);
case Item.type.value: case Item.type.value:
return getItemPageRoute(dso.uuid); return getItemPageRoute(dso as Item);
} }
} }

View File

@@ -12,6 +12,7 @@ import { DsoRedirectDataService } from './dso-redirect-data.service';
import { GetRequest, IdentifierType } from './request.models'; import { GetRequest, IdentifierType } from './request.models';
import { RequestService } from './request.service'; import { RequestService } from './request.service';
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
import { Item } from '../shared/item.model';
describe('DsoRedirectDataService', () => { describe('DsoRedirectDataService', () => {
let scheduler: TestScheduler; let scheduler: TestScheduler;
@@ -48,10 +49,10 @@ describe('DsoRedirectDataService', () => {
navigate: jasmine.createSpy('navigate') navigate: jasmine.createSpy('navigate')
}; };
remoteData = createSuccessfulRemoteDataObject({ remoteData = createSuccessfulRemoteDataObject(Object.assign(new Item(), {
type: 'item', type: 'item',
uuid: '123456789' uuid: '123456789'
}); }));
rdbService = jasmine.createSpyObj('rdbService', { rdbService = jasmine.createSpyObj('rdbService', {
buildSingle: cold('a', { buildSingle: cold('a', {
@@ -114,7 +115,7 @@ describe('DsoRedirectDataService', () => {
redir.subscribe(); redir.subscribe();
scheduler.schedule(() => redir); scheduler.schedule(() => redir);
scheduler.flush(); scheduler.flush();
expect(router.navigate).toHaveBeenCalledWith([remoteData.payload.type + 's/' + remoteData.payload.uuid]); expect(router.navigate).toHaveBeenCalledWith(['/items/' + remoteData.payload.uuid]);
}); });
it('should navigate to entities route with the corresponding entity type', () => { it('should navigate to entities route with the corresponding entity type', () => {
remoteData.payload.type = 'item'; remoteData.payload.type = 'item';
@@ -131,7 +132,7 @@ describe('DsoRedirectDataService', () => {
redir.subscribe(); redir.subscribe();
scheduler.schedule(() => redir); scheduler.schedule(() => redir);
scheduler.flush(); scheduler.flush();
expect(router.navigate).toHaveBeenCalledWith(['entities/publication/' + remoteData.payload.uuid]); expect(router.navigate).toHaveBeenCalledWith(['/entities/Publication/' + remoteData.payload.uuid]);
}); });
it('should navigate to collections route', () => { it('should navigate to collections route', () => {

View File

@@ -20,6 +20,7 @@ import { getFirstCompletedRemoteData } from '../shared/operators';
import { DSpaceObject } from '../shared/dspace-object.model'; import { DSpaceObject } from '../shared/dspace-object.model';
import { Item } from '../shared/item.model'; import { Item } from '../shared/item.model';
import { Metadata } from '../shared/metadata.utils'; import { Metadata } from '../shared/metadata.utils';
import { getItemPageRoute } from '../../+item-page/item-page-routing-paths';
@Injectable() @Injectable()
export class DsoRedirectDataService extends DataService<any> { export class DsoRedirectDataService extends DataService<any> {
@@ -64,15 +65,16 @@ export class DsoRedirectDataService extends DataService<any> {
if (response.hasSucceeded) { if (response.hasSucceeded) {
const dso = response.payload; const dso = response.payload;
const uuid = dso.uuid; const uuid = dso.uuid;
if (hasValue(uuid)) {
let newRoute = this.getEndpointFromDSOType(response.payload.type); let newRoute = this.getEndpointFromDSOType(response.payload.type);
if (dso.type.startsWith('item')) { if (dso.type.startsWith('item')) {
const relation = Metadata.firstValue(dso.metadata, 'relationship.type'); newRoute = getItemPageRoute(dso as Item);
if (hasValue(relation)) { } else if (hasValue(newRoute)) {
newRoute = `entities/${relation.toLowerCase()}`; newRoute += '/' + uuid;
} }
if (hasValue(newRoute)) {
this.router.navigate([newRoute]);
} }
if (hasValue(uuid) && hasValue(newRoute)) {
this.router.navigate([newRoute + '/' + uuid]);
} }
} }
}) })

View File

@@ -5,7 +5,7 @@
</div> </div>
<a *ngIf="linkType != linkTypes.None" <a *ngIf="linkType != linkTypes.None"
[target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width"> class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="getThumbnail() | async"> <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
@@ -36,7 +36,7 @@
</p> </p>
<div *ngIf="linkType != linkTypes.None" class="text-center"> <div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a> class="lead btn btn-primary viewButton">View</a>
</div> </div>
</div> </div>

View File

@@ -2,9 +2,7 @@ import { Component } from '@angular/core';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { focusShadow } from '../../../../../shared/animations/focus'; import { focusShadow } from '../../../../../shared/animations/focus';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; import { ItemSearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('JournalIssueSearchResult', ViewMode.GridElement) @listableObjectComponent('JournalIssueSearchResult', ViewMode.GridElement)
@Component({ @Component({
@@ -16,5 +14,5 @@ import { Item } from '../../../../../core/shared/item.model';
/** /**
* The component for displaying a grid element for an item search result of the type Journal Issue * The component for displaying a grid element for an item search result of the type Journal Issue
*/ */
export class JournalIssueSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class JournalIssueSearchResultGridElementComponent extends ItemSearchResultGridElementComponent {
} }

View File

@@ -5,7 +5,7 @@
</div> </div>
<a *ngIf="linkType != linkTypes.None" <a *ngIf="linkType != linkTypes.None"
[target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width"> class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="getThumbnail() | async"> <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
@@ -36,7 +36,7 @@
</p> </p>
<div *ngIf="linkType != linkTypes.None" class="text-center"> <div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a> class="lead btn btn-primary viewButton">View</a>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,8 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { focusShadow } from '../../../../../shared/animations/focus'; import { focusShadow } from '../../../../../shared/animations/focus';
import { ItemSearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
@listableObjectComponent('JournalVolumeSearchResult', ViewMode.GridElement) @listableObjectComponent('JournalVolumeSearchResult', ViewMode.GridElement)
@Component({ @Component({
@@ -16,5 +14,5 @@ import { focusShadow } from '../../../../../shared/animations/focus';
/** /**
* The component for displaying a grid element for an item search result of the type Journal Volume * The component for displaying a grid element for an item search result of the type Journal Volume
*/ */
export class JournalVolumeSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class JournalVolumeSearchResultGridElementComponent extends ItemSearchResultGridElementComponent {
} }

View File

@@ -5,7 +5,7 @@
</div> </div>
<a *ngIf="linkType != linkTypes.None" <a *ngIf="linkType != linkTypes.None"
[target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width"> class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="getThumbnail() | async"> <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
@@ -40,7 +40,7 @@
</p> </p>
<div *ngIf="linkType != linkTypes.None" class="text-center"> <div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a> class="lead btn btn-primary viewButton">View</a>
</div> </div>
</div> </div>

View File

@@ -2,9 +2,7 @@ import { Component } from '@angular/core';
import { focusShadow } from '../../../../../shared/animations/focus'; import { focusShadow } from '../../../../../shared/animations/focus';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; import { ItemSearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('JournalSearchResult', ViewMode.GridElement) @listableObjectComponent('JournalSearchResult', ViewMode.GridElement)
@Component({ @Component({
@@ -16,5 +14,5 @@ import { Item } from '../../../../../core/shared/item.model';
/** /**
* The component for displaying a grid element for an item search result of the type Journal * The component for displaying a grid element for an item search result of the type Journal
*/ */
export class JournalSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class JournalSearchResultGridElementComponent extends ItemSearchResultGridElementComponent {
} }

View File

@@ -1,7 +1,7 @@
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead" [routerLink]="[itemPageRoute]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a> [innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None" <span *ngIf="linkType == linkTypes.None"
class="lead" class="lead"

View File

@@ -1,9 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('JournalIssueSearchResult', ViewMode.ListElement) @listableObjectComponent('JournalIssueSearchResult', ViewMode.ListElement)
@Component({ @Component({
@@ -14,5 +12,5 @@ import { Item } from '../../../../../core/shared/item.model';
/** /**
* The component for displaying a list element for an item search result of the type Journal Issue * The component for displaying a list element for an item search result of the type Journal Issue
*/ */
export class JournalIssueSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class JournalIssueSearchResultListElementComponent extends ItemSearchResultListElementComponent {
} }

View File

@@ -1,7 +1,7 @@
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead" [routerLink]="[itemPageRoute]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a> [innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None" <span *ngIf="linkType == linkTypes.None"
class="lead" class="lead"

View File

@@ -1,9 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
@listableObjectComponent('JournalVolumeSearchResult', ViewMode.ListElement) @listableObjectComponent('JournalVolumeSearchResult', ViewMode.ListElement)
@Component({ @Component({
@@ -14,5 +12,5 @@ import { ViewMode } from '../../../../../core/shared/view-mode.model';
/** /**
* The component for displaying a list element for an item search result of the type Journal Volume * The component for displaying a list element for an item search result of the type Journal Volume
*/ */
export class JournalVolumeSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class JournalVolumeSearchResultListElementComponent extends ItemSearchResultListElementComponent {
} }

View File

@@ -1,7 +1,7 @@
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead" [routerLink]="[itemPageRoute]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a> [innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None" <span *ngIf="linkType == linkTypes.None"
class="lead" class="lead"

View File

@@ -1,9 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
@listableObjectComponent('JournalSearchResult', ViewMode.ListElement) @listableObjectComponent('JournalSearchResult', ViewMode.ListElement)
@Component({ @Component({
@@ -14,5 +12,5 @@ import { ViewMode } from '../../../../../core/shared/view-mode.model';
/** /**
* The component for displaying a list element for an item search result of the type Journal * The component for displaying a list element for an item search result of the type Journal
*/ */
export class JournalSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class JournalSearchResultListElementComponent extends ItemSearchResultListElementComponent {
} }

View File

@@ -3,7 +3,7 @@
{{'journalissue.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values> {{'journalissue.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'journalissue.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'journalissue.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -53,7 +53,7 @@
[label]="'journalissue.page.keyword'"> [label]="'journalissue.page.keyword'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -3,7 +3,7 @@
{{'journalvolume.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values> {{'journalvolume.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'journalvolume.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'journalvolume.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -36,7 +36,7 @@
[label]="'journalvolume.page.description'"> [label]="'journalvolume.page.description'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -3,7 +3,7 @@
{{'journal.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values> {{'journal.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'journal.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'journal.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -35,7 +35,7 @@
[label]="'journal.page.description'"> [label]="'journal.page.description'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -5,7 +5,7 @@
</div> </div>
<a *ngIf="linkType != linkTypes.None" <a *ngIf="linkType != linkTypes.None"
[target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width"> class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="getThumbnail() | async"> <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
@@ -42,7 +42,7 @@
</p> </p>
<div *ngIf="linkType != linkTypes.None" class="text-center"> <div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a> class="lead btn btn-primary viewButton">View</a>
</div> </div>
</div> </div>

View File

@@ -2,9 +2,7 @@ import { Component } from '@angular/core';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { focusShadow } from '../../../../../shared/animations/focus'; import { focusShadow } from '../../../../../shared/animations/focus';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; import { ItemSearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('OrgUnitSearchResult', ViewMode.GridElement) @listableObjectComponent('OrgUnitSearchResult', ViewMode.GridElement)
@Component({ @Component({
@@ -16,5 +14,5 @@ import { Item } from '../../../../../core/shared/item.model';
/** /**
* The component for displaying a grid element for an item search result of the type Organisation Unit * The component for displaying a grid element for an item search result of the type Organisation Unit
*/ */
export class OrgUnitSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class OrgUnitSearchResultGridElementComponent extends ItemSearchResultGridElementComponent {
} }

View File

@@ -5,7 +5,7 @@
</div> </div>
<a *ngIf="linkType != linkTypes.None" <a *ngIf="linkType != linkTypes.None"
[target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width"> class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="getThumbnail() | async"> <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
@@ -36,7 +36,7 @@
</p> </p>
<div *ngIf="linkType != linkTypes.None" class="text-center"> <div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a> class="lead btn btn-primary viewButton">View</a>
</div> </div>
</div> </div>

View File

@@ -2,9 +2,7 @@ import { Component } from '@angular/core';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { focusShadow } from '../../../../../shared/animations/focus'; import { focusShadow } from '../../../../../shared/animations/focus';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; import { ItemSearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('PersonSearchResult', ViewMode.GridElement) @listableObjectComponent('PersonSearchResult', ViewMode.GridElement)
@Component({ @Component({
@@ -16,5 +14,5 @@ import { Item } from '../../../../../core/shared/item.model';
/** /**
* The component for displaying a grid element for an item search result of the type Person * The component for displaying a grid element for an item search result of the type Person
*/ */
export class PersonSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class PersonSearchResultGridElementComponent extends ItemSearchResultGridElementComponent {
} }

View File

@@ -5,7 +5,7 @@
</div> </div>
<a *ngIf="linkType != linkTypes.None" <a *ngIf="linkType != linkTypes.None"
[target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width"> class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="getThumbnail() | async"> <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
@@ -30,7 +30,7 @@
</p> </p>
<div *ngIf="linkType != linkTypes.None" class="text-center"> <div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" <a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a> class="lead btn btn-primary viewButton">View</a>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,8 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component';
import { Item } from '../../../../../core/shared/item.model';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { focusShadow } from '../../../../../shared/animations/focus'; import { focusShadow } from '../../../../../shared/animations/focus';
import { ItemSearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
@listableObjectComponent('ProjectSearchResult', ViewMode.GridElement) @listableObjectComponent('ProjectSearchResult', ViewMode.GridElement)
@Component({ @Component({
@@ -16,5 +14,5 @@ import { focusShadow } from '../../../../../shared/animations/focus';
/** /**
* The component for displaying a grid element for an item search result of the type Project * The component for displaying a grid element for an item search result of the type Project
*/ */
export class ProjectSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class ProjectSearchResultGridElementComponent extends ItemSearchResultGridElementComponent {
} }

View File

@@ -1,7 +1,7 @@
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead" [routerLink]="[itemPageRoute]" class="lead"
[innerHTML]="firstMetadataValue('organization.legalName')"></a> [innerHTML]="firstMetadataValue('organization.legalName')"></a>
<span *ngIf="linkType == linkTypes.None" <span *ngIf="linkType == linkTypes.None"
class="lead" class="lead"

View File

@@ -1,9 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('OrgUnitSearchResult', ViewMode.ListElement) @listableObjectComponent('OrgUnitSearchResult', ViewMode.ListElement)
@Component({ @Component({
@@ -14,5 +12,5 @@ import { Item } from '../../../../../core/shared/item.model';
/** /**
* The component for displaying a list element for an item search result of the type Organisation Unit * The component for displaying a list element for an item search result of the type Organisation Unit
*/ */
export class OrgUnitSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class OrgUnitSearchResultListElementComponent extends ItemSearchResultListElementComponent {
} }

View File

@@ -1,7 +1,7 @@
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead" [routerLink]="[itemPageRoute]" class="lead"
[innerHTML]="name"></a> [innerHTML]="name"></a>
<span *ngIf="linkType == linkTypes.None" <span *ngIf="linkType == linkTypes.None"
class="lead" class="lead"

View File

@@ -1,9 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { Item } from '../../../../../core/shared/item.model'; import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
@listableObjectComponent('PersonSearchResult', ViewMode.ListElement) @listableObjectComponent('PersonSearchResult', ViewMode.ListElement)
@Component({ @Component({
@@ -14,7 +12,7 @@ import { Item } from '../../../../../core/shared/item.model';
/** /**
* The component for displaying a list element for an item search result of the type Person * The component for displaying a list element for an item search result of the type Person
*/ */
export class PersonSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class PersonSearchResultListElementComponent extends ItemSearchResultListElementComponent {
get name() { get name() {
return this.value ? return this.value ?

View File

@@ -1,7 +1,7 @@
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge> <ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead" [routerLink]="[itemPageRoute]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a> [innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None" <span *ngIf="linkType == linkTypes.None"
class="lead" class="lead"

View File

@@ -1,9 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
@listableObjectComponent('ProjectSearchResult', ViewMode.ListElement) @listableObjectComponent('ProjectSearchResult', ViewMode.ListElement)
@Component({ @Component({
@@ -14,5 +12,5 @@ import { ViewMode } from '../../../../../core/shared/view-mode.model';
/** /**
* The component for displaying a list element for an item search result of the type Project * The component for displaying a list element for an item search result of the type Project
*/ */
export class ProjectSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class ProjectSearchResultListElementComponent extends ItemSearchResultListElementComponent {
} }

View File

@@ -3,7 +3,7 @@
{{'orgunit.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['organization.legalName'])"></ds-metadata-values> {{'orgunit.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['organization.legalName'])"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'orgunit.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'orgunit.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -39,7 +39,7 @@
[label]="'orgunit.page.description'"> [label]="'orgunit.page.description'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -3,7 +3,7 @@
{{'person.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="[object?.firstMetadata('person.familyName'), object?.firstMetadata('person.givenName')]" [separator]="', '"></ds-metadata-values> {{'person.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="[object?.firstMetadata('person.familyName'), object?.firstMetadata('person.givenName')]" [separator]="', '"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'person.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'person.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -52,7 +52,7 @@
[label]="'person.page.firstname'"> [label]="'person.page.firstname'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -3,7 +3,7 @@
{{'project.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values> {{'project.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="pl-2"> <div class="pl-2">
<ds-dso-page-edit-button [pageRoutePrefix]="'items'" [dso]="object" [tooltipMsg]="'project.page.edit'"></ds-dso-page-edit-button> <ds-dso-page-edit-button [pageRoute]="itemPageRoute" [dso]="object" [tooltipMsg]="'project.page.edit'"></ds-dso-page-edit-button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -59,7 +59,7 @@
[label]="'project.page.keyword'"> [label]="'project.page.keyword'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -6,7 +6,7 @@
</span> </span>
</ng-template> </ng-template>
<ds-truncatable [id]="metadataRepresentation.id"> <ds-truncatable [id]="metadataRepresentation.id">
<a [routerLink]="['/items/' + metadataRepresentation.id]" <a [routerLink]="[itemPageRoute]"
[innerHTML]="metadataRepresentation.getValue()" [innerHTML]="metadataRepresentation.getValue()"
[ngbTooltip]="metadataRepresentation.allMetadata(['dc.description']).length > 0 ? descTemplate : null"></a> [ngbTooltip]="metadataRepresentation.allMetadata(['dc.description']).length > 0 ? descTemplate : null"></a>
</ds-truncatable> </ds-truncatable>

View File

@@ -9,7 +9,7 @@
</span> </span>
</ng-template> </ng-template>
<ds-truncatable [id]="metadataRepresentation.id"> <ds-truncatable [id]="metadataRepresentation.id">
<a [routerLink]="['/items/' + metadataRepresentation.id]" <a [routerLink]="[itemPageRoute]"
[innerHTML]="metadataRepresentation.getValue()" [innerHTML]="metadataRepresentation.getValue()"
[ngbTooltip]="metadataRepresentation.allMetadata(['person.jobTitle']).length > 0 ? descTemplate : null"></a> [ngbTooltip]="metadataRepresentation.allMetadata(['person.jobTitle']).length > 0 ? descTemplate : null"></a>
</ds-truncatable> </ds-truncatable>

View File

@@ -1,5 +1,5 @@
<a *ngIf="isAuthorized$ | async" <a *ngIf="isAuthorized$ | async"
[routerLink]="['/' + pageRoutePrefix, dso.id, 'edit']" [routerLink]="[pageRoute, 'edit']"
class="edit-button btn btn-dark text-light btn-sm" class="edit-button btn btn-dark text-light btn-sm"
[ngbTooltip]="tooltipMsg | translate"> [ngbTooltip]="tooltipMsg | translate">
<i class="fas fa-pencil-alt fa-fw"></i> <i class="fas fa-pencil-alt fa-fw"></i>

View File

@@ -40,7 +40,7 @@ describe('DsoPageEditButtonComponent', () => {
fixture = TestBed.createComponent(DsoPageEditButtonComponent); fixture = TestBed.createComponent(DsoPageEditButtonComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.dso = dso; component.dso = dso;
component.pageRoutePrefix = 'test'; component.pageRoute = 'test';
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -21,7 +21,7 @@ export class DsoPageEditButtonComponent implements OnInit {
/** /**
* The prefix of the route to the edit page (before the object's UUID, e.g. "items") * The prefix of the route to the edit page (before the object's UUID, e.g. "items")
*/ */
@Input() pageRoutePrefix: string; @Input() pageRoute: string;
/** /**
* A message for the tooltip on the button * A message for the tooltip on the button

View File

@@ -5,6 +5,7 @@ import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { DSOSelectorModalWrapperComponent, SelectorActionType } from '../dso-selector-modal-wrapper.component'; import { DSOSelectorModalWrapperComponent, SelectorActionType } from '../dso-selector-modal-wrapper.component';
import { getItemEditRoute } from '../../../../+item-page/item-page-routing-paths'; import { getItemEditRoute } from '../../../../+item-page/item-page-routing-paths';
import { Item } from '../../../../core/shared/item.model';
/** /**
* Component to wrap a list of existing items inside a modal * Component to wrap a list of existing items inside a modal
@@ -28,6 +29,6 @@ export class EditItemSelectorComponent extends DSOSelectorModalWrapperComponent
* Navigate to the item edit page * Navigate to the item edit page
*/ */
navigate(dso: DSpaceObject) { navigate(dso: DSpaceObject) {
this.router.navigate([getItemEditRoute(dso.uuid)]); this.router.navigate([getItemEditRoute(dso as Item)]);
} }
} }

View File

@@ -25,7 +25,7 @@
<td class="version-row-element-version">{{version?.version}}</td> <td class="version-row-element-version">{{version?.version}}</td>
<td class="version-row-element-item"> <td class="version-row-element-item">
<span *ngVar="(version?.item | async)?.payload as item"> <span *ngVar="(version?.item | async)?.payload as item">
<a *ngIf="item" [routerLink]="['/items', item?.id]">{{item?.handle}}</a> <a *ngIf="item" [routerLink]="[(itemPageRoutes$ | async)[item?.id]]">{{item?.handle}}</a>
<span *ngIf="version?.id === itemVersion?.id">*</span> <span *ngIf="version?.id === itemVersion?.id">*</span>
</span> </span>
</td> </td>

View File

@@ -4,7 +4,11 @@ import { Version } from '../../../core/shared/version.model';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { BehaviorSubject, combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { BehaviorSubject, combineLatest as observableCombineLatest, Observable } from 'rxjs';
import { VersionHistory } from '../../../core/shared/version-history.model'; import { VersionHistory } from '../../../core/shared/version-history.model';
import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../core/shared/operators'; import {
getAllSucceededRemoteData,
getAllSucceededRemoteDataPayload,
getRemoteDataPayload
} from '../../../core/shared/operators';
import { map, startWith, switchMap } from 'rxjs/operators'; import { map, startWith, switchMap } from 'rxjs/operators';
import { PaginatedList } from '../../../core/data/paginated-list.model'; import { PaginatedList } from '../../../core/data/paginated-list.model';
import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model';
@@ -13,6 +17,7 @@ import { PaginatedSearchOptions } from '../../search/paginated-search-options.mo
import { AlertType } from '../../alert/aletr-type'; import { AlertType } from '../../alert/aletr-type';
import { followLink } from '../../utils/follow-link-config.model'; import { followLink } from '../../utils/follow-link-config.model';
import { hasValueOperator } from '../../empty.util'; import { hasValueOperator } from '../../empty.util';
import { getItemPageRoute } from '../../../+item-page/item-page-routing-paths';
@Component({ @Component({
selector: 'ds-item-versions', selector: 'ds-item-versions',
@@ -86,6 +91,15 @@ export class ItemVersionsComponent implements OnInit {
*/ */
currentPage$ = new BehaviorSubject<number>(1); currentPage$ = new BehaviorSubject<number>(1);
/**
* The routes to the versions their item pages
* Key: Item ID
* Value: Route to item page
*/
itemPageRoutes$: Observable<{
[itemId: string]: string
}>
constructor(private versionHistoryService: VersionHistoryDataService) { constructor(private versionHistoryService: VersionHistoryDataService) {
} }
@@ -118,6 +132,15 @@ export class ItemVersionsComponent implements OnInit {
map((versions: PaginatedList<Version>) => versions.page.filter((version: Version) => version.eperson !== undefined).length > 0), map((versions: PaginatedList<Version>) => versions.page.filter((version: Version) => version.eperson !== undefined).length > 0),
startWith(false) startWith(false)
); );
this.itemPageRoutes$ = this.versionsRD$.pipe(
getAllSucceededRemoteDataPayload(),
switchMap((versions) => observableCombineLatest(...versions.page.map((version) => version.item.pipe(getAllSucceededRemoteDataPayload())))),
map((versions) => {
const itemPageRoutes = {};
versions.forEach((item) => itemPageRoutes[item.uuid] = getItemPageRoute(item));
return itemPageRoutes;
})
);
} }
/** /**

View File

@@ -109,7 +109,7 @@ export class ItemVersionsNoticeComponent implements OnInit {
*/ */
getItemPage(item: Item): string { getItemPage(item: Item): string {
if (hasValue(item)) { if (hasValue(item)) {
return getItemPageRoute(item.id); return getItemPageRoute(item);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
<button class="btn btn-primary mt-1 mb-3" <button class="btn btn-primary mt-1 mb-3"
ngbTooltip="{{'submission.workflow.generic.view-help' | translate}}" ngbTooltip="{{'submission.workflow.generic.view-help' | translate}}"
[routerLink]="['/items/' + object.id]"> [routerLink]="[itemPageRoute]">
<i class="fa fa-info-circle"></i> {{"submission.workflow.generic.view" | translate}} <i class="fa fa-info-circle"></i> {{"submission.workflow.generic.view" | translate}}
</button> </button>

View File

@@ -1,14 +1,13 @@
import { Component, Injector, Input } from '@angular/core'; import { Component, Injector, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { MyDSpaceActionsComponent } from '../mydspace-actions';
import { ItemDataService } from '../../../core/data/item-data.service'; import { ItemDataService } from '../../../core/data/item-data.service';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { NotificationsService } from '../../notifications/notifications.service'; import { NotificationsService } from '../../notifications/notifications.service';
import { RequestService } from '../../../core/data/request.service'; import { RequestService } from '../../../core/data/request.service';
import { SearchService } from '../../../core/shared/search/search.service'; import { SearchService } from '../../../core/shared/search/search.service';
import { getItemPageRoute } from '../../../+item-page/item-page-routing-paths';
/** /**
* This component represents mydspace actions related to Item object. * This component represents mydspace actions related to Item object.
@@ -19,13 +18,18 @@ import { SearchService } from '../../../core/shared/search/search.service';
templateUrl: './item-actions.component.html', templateUrl: './item-actions.component.html',
}) })
export class ItemActionsComponent extends MyDSpaceActionsComponent<Item, ItemDataService> { export class ItemActionsComponent extends MyDSpaceActionsComponent<Item, ItemDataService> implements OnInit {
/** /**
* The Item object * The Item object
*/ */
@Input() object: Item; @Input() object: Item;
/**
* Route to the item's page
*/
itemPageRoute: string;
/** /**
* Initialize instance variables * Initialize instance variables
* *
@@ -45,6 +49,10 @@ export class ItemActionsComponent extends MyDSpaceActionsComponent<Item, ItemDat
super(Item.type, injector, router, notificationsService, translate, searchService, requestService); super(Item.type, injector, router, notificationsService, translate, searchService, requestService);
} }
ngOnInit(): void {
this.initPageRoute();
}
/** /**
* Init the target object * Init the target object
* *
@@ -52,6 +60,14 @@ export class ItemActionsComponent extends MyDSpaceActionsComponent<Item, ItemDat
*/ */
initObjects(object: Item) { initObjects(object: Item) {
this.object = object; this.object = object;
this.initPageRoute();
}
/**
* Initialise the route to the item's page
*/
initPageRoute() {
this.itemPageRoute = getItemPageRoute(this.object);
} }
} }

View File

@@ -3,7 +3,7 @@
<div class="position-absolute ml-1"> <div class="position-absolute ml-1">
<ng-content></ng-content> <ng-content></ng-content>
</div> </div>
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width"> class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="getThumbnail() | async"> <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
@@ -36,7 +36,7 @@
</ds-truncatable-part> </ds-truncatable-part>
</p> </p>
<div *ngIf="linkType != linkTypes.None" class="text-center"> <div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" <a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a> class="lead btn btn-primary viewButton">View</a>
</div> </div>
</div> </div>

View File

@@ -5,6 +5,7 @@ import { listableObjectComponent } from '../../../../object-collection/shared/li
import { SearchResultGridElementComponent } from '../../search-result-grid-element.component'; import { SearchResultGridElementComponent } from '../../search-result-grid-element.component';
import { Item } from '../../../../../core/shared/item.model'; import { Item } from '../../../../../core/shared/item.model';
import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
import { getItemPageRoute } from '../../../../../+item-page/item-page-routing-paths';
@listableObjectComponent('PublicationSearchResult', ViewMode.GridElement) @listableObjectComponent('PublicationSearchResult', ViewMode.GridElement)
@listableObjectComponent(ItemSearchResult, ViewMode.GridElement) @listableObjectComponent(ItemSearchResult, ViewMode.GridElement)
@@ -18,4 +19,13 @@ import { ItemSearchResult } from '../../../../object-collection/shared/item-sear
* The component for displaying a grid element for an item search result of the type Publication * The component for displaying a grid element for an item search result of the type Publication
*/ */
export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> {
/**
* Route to the item's page
*/
itemPageRoute: string;
ngOnInit(): void {
super.ngOnInit();
this.itemPageRoute = getItemPageRoute(this.dso);
}
} }

View File

@@ -1,6 +1,7 @@
import { MetadataRepresentationListElementComponent } from '../metadata-representation-list-element.component'; import { MetadataRepresentationListElementComponent } from '../metadata-representation-list-element.component';
import { Component } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
import { getItemPageRoute } from '../../../../+item-page/item-page-routing-paths';
@Component({ @Component({
selector: 'ds-item-metadata-representation-list-element', selector: 'ds-item-metadata-representation-list-element',
@@ -9,6 +10,15 @@ import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-rep
/** /**
* An abstract class for displaying a single ItemMetadataRepresentation * An abstract class for displaying a single ItemMetadataRepresentation
*/ */
export class ItemMetadataRepresentationListElementComponent extends MetadataRepresentationListElementComponent { export class ItemMetadataRepresentationListElementComponent extends MetadataRepresentationListElementComponent implements OnInit {
metadataRepresentation: ItemMetadataRepresentation; metadataRepresentation: ItemMetadataRepresentation;
/**
* Route to the item's page
*/
itemPageRoute: string;
ngOnInit(): void {
this.itemPageRoute = getItemPageRoute(this.metadataRepresentation);
}
} }

View File

@@ -2,7 +2,7 @@
<ds-truncatable [id]="dso.id" *ngIf="object !== undefined && object !== null"> <ds-truncatable [id]="dso.id" *ngIf="object !== undefined && object !== null">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead" [routerLink]="[itemPageRoute]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a> [innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None" class="lead" <span *ngIf="linkType == linkTypes.None" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></span> [innerHTML]="firstMetadataValue('dc.title')"></span>

View File

@@ -4,6 +4,7 @@ import { ViewMode } from '../../../../../../core/shared/view-mode.model';
import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model';
import { SearchResultListElementComponent } from '../../../search-result-list-element.component'; import { SearchResultListElementComponent } from '../../../search-result-list-element.component';
import { Item } from '../../../../../../core/shared/item.model'; import { Item } from '../../../../../../core/shared/item.model';
import { getItemPageRoute } from '../../../../../../+item-page/item-page-routing-paths';
@listableObjectComponent('PublicationSearchResult', ViewMode.ListElement) @listableObjectComponent('PublicationSearchResult', ViewMode.ListElement)
@listableObjectComponent(ItemSearchResult, ViewMode.ListElement) @listableObjectComponent(ItemSearchResult, ViewMode.ListElement)
@@ -16,4 +17,13 @@ import { Item } from '../../../../../../core/shared/item.model';
* The component for displaying a list element for an item search result of the type Publication * The component for displaying a list element for an item search result of the type Publication
*/ */
export class ItemSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class ItemSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {
/**
* Route to the item's page
*/
itemPageRoute: string;
ngOnInit(): void {
super.ngOnInit();
this.itemPageRoute = getItemPageRoute(this.dso);
}
} }

View File

@@ -26,7 +26,7 @@
</span> </span>
</td> </td>
<td><span *ngIf="item.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])">{{item.firstMetadataValue(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])}}</span></td> <td><span *ngIf="item.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])">{{item.firstMetadataValue(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])}}</span></td>
<td><a [routerLink]="['/items', item.id]">{{item.firstMetadataValue("dc.title")}}</a></td> <td><a [routerLink]="[(itemPageRoutes$ | async)[item.id]]">{{item.firstMetadataValue("dc.title")}}</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -2,7 +2,11 @@ import { Component, Input } from '@angular/core';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { ObjectSelectService } from '../object-select.service'; import { ObjectSelectService } from '../object-select.service';
import { ObjectSelectComponent } from '../object-select/object-select.component'; import { ObjectSelectComponent } from '../object-select/object-select.component';
import { isNotEmpty } from '../../empty.util'; import { hasValueOperator, isNotEmpty } from '../../empty.util';
import { Observable } from 'rxjs';
import { getAllSucceededRemoteDataPayload } from '../../../core/shared/operators';
import { map } from 'rxjs/operators';
import { getItemPageRoute } from '../../../+item-page/item-page-routing-paths';
@Component({ @Component({
selector: 'ds-item-select', selector: 'ds-item-select',
@@ -20,6 +24,15 @@ export class ItemSelectComponent extends ObjectSelectComponent<Item> {
@Input() @Input()
hideCollection = false; hideCollection = false;
/**
* The routes to the items their pages
* Key: Item ID
* Value: Route to item page
*/
itemPageRoutes$: Observable<{
[itemId: string]: string
}>
constructor(protected objectSelectService: ObjectSelectService) { constructor(protected objectSelectService: ObjectSelectService) {
super(objectSelectService); super(objectSelectService);
} }
@@ -29,6 +42,15 @@ export class ItemSelectComponent extends ObjectSelectComponent<Item> {
if (!isNotEmpty(this.confirmButton)) { if (!isNotEmpty(this.confirmButton)) {
this.confirmButton = 'item.select.confirm'; this.confirmButton = 'item.select.confirm';
} }
this.itemPageRoutes$ = this.dsoRD$.pipe(
hasValueOperator(),
getAllSucceededRemoteDataPayload(),
map((items) => {
const itemPageRoutes = {};
items.page.forEach((item) => itemPageRoutes[item.uuid] = getItemPageRoute(item));
return itemPageRoutes;
})
);
} }
} }

View File

@@ -8,7 +8,7 @@ a<div class="top-item-page">
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<div> <div>
<a class="btn btn-secondary" <a class="btn btn-secondary"
[routerLink]="['/items/' + object.id + '/full']"> [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -8,7 +8,7 @@
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<div> <div>
<a class="btn btn-secondary" <a class="btn btn-secondary"
[routerLink]="['/items/' + object.id + '/full']"> [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -8,7 +8,7 @@
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<div> <div>
<a class="btn btn-secondary" <a class="btn btn-secondary"
[routerLink]="['/items/' + object.id + '/full']"> [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -7,7 +7,7 @@
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<div> <div>
<a class="btn btn-secondary" <a class="btn btn-secondary"
[routerLink]="['/items/' + object.id + '/full']"> [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -9,7 +9,7 @@
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<div> <div>
<a class="btn btn-secondary" <a class="btn btn-secondary"
[routerLink]="['/items/' + object.id + '/full']"> [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -9,7 +9,7 @@
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<div> <div>
<a class="btn btn-secondary" <a class="btn btn-secondary"
[routerLink]="['/items/' + object.id + '/full']"> [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -9,7 +9,7 @@
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<div> <div>
<a class="btn btn-secondary" <a class="btn btn-secondary"
[routerLink]="['/items/' + object.id + '/full']"> [routerLink]="[itemPageRoute + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>