From 1974ae54e31485bdcd5de80317051c336baa320c Mon Sep 17 00:00:00 2001 From: amadulhaxxani Date: Fri, 15 May 2026 13:28:22 +0200 Subject: [PATCH 1/3] resolve archived item hang and false Archived badge in MyDSpace resolve archived item hang and false Archived badge in MyDSpace --- src/app/app.component.ts | 4 +++- .../submission/resolver/submission-links-to-follow.ts | 10 +++++++++- .../submission/resolver/submission-object.resolver.ts | 2 +- src/app/item-page/item.resolver.ts | 2 +- .../versions/notice/item-versions-notice.component.ts | 8 +++++--- ...ch-result-list-element-submission.component.spec.ts | 7 +++++++ ...-search-result-list-element-submission.component.ts | 10 +++++++++- src/app/shared/theme-support/themed.component.ts | 3 +++ .../dspace/view-tracker-resolver.service.spec.ts | 6 ++---- .../dspace/view-tracker-resolver.service.ts | 1 + 10 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index b77d53c81d4..d9c85a24d83 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -12,6 +12,7 @@ import { import { NavigationCancel, NavigationEnd, + NavigationError, NavigationStart, Router, } from '@angular/router'; @@ -122,7 +123,8 @@ export class AppComponent implements OnInit, AfterViewInit { distinctNext(this.isRouteLoading$, true); } else if ( event instanceof NavigationEnd || - event instanceof NavigationCancel + event instanceof NavigationCancel || + event instanceof NavigationError ) { distinctNext(this.isRouteLoading$, false); } diff --git a/src/app/core/submission/resolver/submission-links-to-follow.ts b/src/app/core/submission/resolver/submission-links-to-follow.ts index b4aa3586ebe..35b6f360328 100644 --- a/src/app/core/submission/resolver/submission-links-to-follow.ts +++ b/src/app/core/submission/resolver/submission-links-to-follow.ts @@ -9,6 +9,14 @@ import { WorkspaceItem } from '../models/workspaceitem.model'; * Needs to be in a separate file to prevent circular dependencies in webpack. */ export const SUBMISSION_LINKS_TO_FOLLOW: FollowLinkConfig[] = [ - followLink('item'), + followLink('item', {}, + followLink('owningCollection', {}, + followLink('parentCommunity', {}, + followLink('parentCommunity')), + ), + followLink('relationships'), + followLink('version', {}, followLink('versionhistory')), + followLink('thumbnail'), + ), followLink('collection'), ]; diff --git a/src/app/core/submission/resolver/submission-object.resolver.ts b/src/app/core/submission/resolver/submission-object.resolver.ts index b059b69e4d2..d09c96d54e7 100644 --- a/src/app/core/submission/resolver/submission-object.resolver.ts +++ b/src/app/core/submission/resolver/submission-object.resolver.ts @@ -26,7 +26,7 @@ export class SubmissionObjectResolver implements Resolve> { */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable> { const itemRD$ = this.dataService.findById(route.params.id, - true, + false, false, ...SUBMISSION_LINKS_TO_FOLLOW, ).pipe( diff --git a/src/app/item-page/item.resolver.ts b/src/app/item-page/item.resolver.ts index c5225675991..e3cb87ddf6d 100644 --- a/src/app/item-page/item.resolver.ts +++ b/src/app/item-page/item.resolver.ts @@ -51,7 +51,7 @@ export class ItemResolver implements Resolve> { */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable> { const itemRD$ = this.itemService.findById(route.params.id, - true, + false, true, ...getItemPageLinksToFollow(), ).pipe( diff --git a/src/app/item-page/versions/notice/item-versions-notice.component.ts b/src/app/item-page/versions/notice/item-versions-notice.component.ts index 37f81976132..fe6e5182dc9 100644 --- a/src/app/item-page/versions/notice/item-versions-notice.component.ts +++ b/src/app/item-page/versions/notice/item-versions-notice.component.ts @@ -89,8 +89,6 @@ export class ItemVersionsNoticeComponent implements OnInit { map((isLatest) => isLatest != null && !isLatest), startWith(false), ); - } - // Compute the destination URL from latestVersion$ with the namespace this.destinationUrl$ = this.latestVersion$.pipe( switchMap(latestVersion => latestVersion?.item || of(null)), @@ -110,7 +108,11 @@ export class ItemVersionsNoticeComponent implements OnInit { return finalUrl; }) - ); + ); + } else { + this.showLatestVersionNotice$ = of(false); + this.destinationUrl$ = of(this.document.location.pathname); + } } } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.spec.ts index a26fbaaf57c..2b5396edca1 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.spec.ts @@ -78,6 +78,13 @@ describe('ItemMyDSpaceResultListElementComponent', () => { }); it('should have correct badge context', () => { + expect(component.badgeContext).toEqual(Context.Any); + }); + + it('should show archived badge context when item is archived', () => { + component.dso = Object.assign(new Item(), mockResultObject.indexableObject, { isArchived: true }); + component.ngOnInit(); + expect(component.badgeContext).toEqual(Context.MyDSpaceArchived); }); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.ts index 39dc208bf4a..579f5c6ec1f 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.ts @@ -22,7 +22,7 @@ export class ItemSearchResultListElementSubmissionComponent extends SearchResult /** * Represents the badge context */ - public badgeContext = Context.MyDSpaceArchived; + public badgeContext = Context.Any; /** @@ -33,6 +33,14 @@ export class ItemSearchResultListElementSubmissionComponent extends SearchResult ngOnInit() { super.ngOnInit(); + + // Show the Archived badge only for items that are actually archived. + if (this.dso?.isArchived) { + this.badgeContext = Context.MyDSpaceArchived; + } else { + this.badgeContext = Context.Any; + } + this.showThumbnails = this.appConfig.browseBy.showThumbnails; } } diff --git a/src/app/shared/theme-support/themed.component.ts b/src/app/shared/theme-support/themed.component.ts index 2e2585f7774..df4037e0f6e 100644 --- a/src/app/shared/theme-support/themed.component.ts +++ b/src/app/shared/theme-support/themed.component.ts @@ -119,6 +119,9 @@ export abstract class ThemedComponent implements AfterViewInit, OnDestroy, On this.lazyLoadSub = this.lazyLoadObs.subscribe(([simpleChanges, constructor]: [SimpleChanges, GenericConstructor]) => { this.destroyComponentInstance(); + if (!this.vcr || !this.themedElementContent) { + return; + } this.compRef = this.vcr.createComponent(constructor, { projectableNodes: [this.themedElementContent.nativeElement.childNodes], }); diff --git a/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.spec.ts b/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.spec.ts index d1b598c7025..269fa838755 100644 --- a/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.spec.ts +++ b/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.spec.ts @@ -93,7 +93,7 @@ describe('ViewTrackerResolverService', () => { expect(emittedEvent.properties.dc_identifier).toBeUndefined(); }); - it('should handle missing dso gracefully (dc_identifier undefined)', () => { + it('should not emit tracking event when dso is missing', () => { const routeSnapshot = { data: { dso: { @@ -111,9 +111,7 @@ describe('ViewTrackerResolverService', () => { service.resolve(routeSnapshot, stateSnapshot); routerEvents$.next(new ResolveEnd(1, '/', '/', {} as any)); - expect(emittedEvent).toBeDefined(); - expect(emittedEvent.action).toBe('page_view'); - expect(emittedEvent.properties.dc_identifier).toBeUndefined(); + expect(emittedEvent).toBeUndefined(); }); it('should use custom dsoPath from route data when provided', () => { diff --git a/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts b/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts index 40afc6d2c5c..8ef22299896 100644 --- a/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts +++ b/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts @@ -25,6 +25,7 @@ export class ViewTrackerResolverService { const dsoPath = routeSnapshot.data.dsoPath || 'dso.payload'; // Fetch the resolvers passed via the route data this.router.events.pipe( filter(event => event instanceof ResolveEnd), + filter(() => !!this.getNestedProperty(routeSnapshot.data, dsoPath)), take(1), switchMap(() => this.referrerService.getReferrer().pipe(take(1)))) From 2a42d627815a5429caa1f737817bfe0ebcc24acf Mon Sep 17 00:00:00 2001 From: amadulhaxxani Date: Mon, 18 May 2026 11:08:29 +0200 Subject: [PATCH 2/3] Fix undefined object in view tracker resolver Ensure the resolved DSO object is available in the referrer observable chain and avoid subscribing when it's missing. The code now retrieves the object inside switchMap, returns EMPTY if the object is not present, and maps {object, referrer} into the subscriber. Added rxjs imports for EMPTY and map to support this flow and prevent potential undefined access in the subscribe handler. --- .../dspace/view-tracker-resolver.service.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts b/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts index 8ef22299896..318049457dd 100644 --- a/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts +++ b/src/app/statistics/angulartics/dspace/view-tracker-resolver.service.ts @@ -1,6 +1,6 @@ import { Injectable, } from '@angular/core'; import { Angulartics2 } from 'angulartics2'; -import { switchMap } from 'rxjs'; +import { EMPTY, map, switchMap } from 'rxjs'; import { filter, take } from 'rxjs/operators'; import { ReferrerService } from '../../../core/services/referrer.service'; @@ -25,12 +25,18 @@ export class ViewTrackerResolverService { const dsoPath = routeSnapshot.data.dsoPath || 'dso.payload'; // Fetch the resolvers passed via the route data this.router.events.pipe( filter(event => event instanceof ResolveEnd), - filter(() => !!this.getNestedProperty(routeSnapshot.data, dsoPath)), take(1), - switchMap(() => - this.referrerService.getReferrer().pipe(take(1)))) - .subscribe((referrer: string) => { + switchMap(() => { const object = this.getNestedProperty(routeSnapshot.data, dsoPath); + if (!object) { + return EMPTY; + } + return this.referrerService.getReferrer().pipe( + take(1), + map((referrer: string) => ({ object, referrer })), + ); + })) + .subscribe(({ object, referrer }: { object: any, referrer: string }) => { const dc_identifier = object?.firstMetadataValue?.('dc.identifier.uri'); this.angulartics2.eventTrack.next({ action: 'page_view', From 04755f73486bb9217adcee293171ce11c20e8ef8 Mon Sep 17 00:00:00 2001 From: amadulhaxxani Date: Mon, 18 May 2026 11:50:04 +0200 Subject: [PATCH 3/3] Remove relationships follow link from submission resolver Remove relationships follow link from submission resolver --- src/app/core/submission/resolver/submission-links-to-follow.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/core/submission/resolver/submission-links-to-follow.ts b/src/app/core/submission/resolver/submission-links-to-follow.ts index 35b6f360328..b05cc2dc418 100644 --- a/src/app/core/submission/resolver/submission-links-to-follow.ts +++ b/src/app/core/submission/resolver/submission-links-to-follow.ts @@ -14,7 +14,6 @@ export const SUBMISSION_LINKS_TO_FOLLOW: FollowLinkConfig