diff --git a/.changeset/chilly-goats-cough.md b/.changeset/chilly-goats-cough.md new file mode 100644 index 00000000..c4fc8c14 --- /dev/null +++ b/.changeset/chilly-goats-cough.md @@ -0,0 +1,5 @@ +--- +'@openstapps/app': minor +--- + +Detail views now won't load data again if it is being navigated to from a list item diff --git a/frontend/app/src/app/modules/assessments/detail/assessments-detail.component.ts b/frontend/app/src/app/modules/assessments/detail/assessments-detail.component.ts index c935c230..0ce6359c 100644 --- a/frontend/app/src/app/modules/assessments/detail/assessments-detail.component.ts +++ b/frontend/app/src/app/modules/assessments/detail/assessments-detail.component.ts @@ -17,7 +17,7 @@ import {Component, DestroyRef, inject, Input, OnInit, ViewChild} from '@angular/ import {ActivatedRoute} from '@angular/router'; import {AssessmentsProvider} from '../assessments.provider'; import {DataDetailComponent, ExternalDataLoadEvent} from '../../data/detail/data-detail.component'; -import {NavController, ViewWillEnter} from '@ionic/angular'; +import {NavController} from '@ionic/angular'; import {DataRoutingService} from '../../data/data-routing.service'; import {SCAssessment} from '@openstapps/core'; import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; @@ -27,7 +27,7 @@ import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; templateUrl: 'assessments-detail.html', styleUrls: ['assessments-detail.scss'], }) -export class AssessmentsDetailComponent implements ViewWillEnter, OnInit { +export class AssessmentsDetailComponent implements OnInit { destroy$ = inject(DestroyRef); constructor( @@ -67,8 +67,4 @@ export class AssessmentsDetailComponent implements ViewWillEnter, OnInit { event.resolve(this.item); }); } - - async ionViewWillEnter() { - await this.detailComponent.ionViewWillEnter(); - } } diff --git a/frontend/app/src/app/modules/assessments/list/assessments-simple-data-list.component.ts b/frontend/app/src/app/modules/assessments/list/assessments-simple-data-list.component.ts index 30a7dd5a..a6e61692 100644 --- a/frontend/app/src/app/modules/assessments/list/assessments-simple-data-list.component.ts +++ b/frontend/app/src/app/modules/assessments/list/assessments-simple-data-list.component.ts @@ -61,6 +61,7 @@ export class AssessmentsSimpleDataListComponent implements OnInit { queryParams: { token: this.activatedRoute.snapshot.queryParamMap.get('token'), }, + state: {item: thing}, }); }); } diff --git a/frontend/app/src/app/modules/assessments/page/assessments-page.component.ts b/frontend/app/src/app/modules/assessments/page/assessments-page.component.ts index 759ea087..1fc11fc7 100644 --- a/frontend/app/src/app/modules/assessments/page/assessments-page.component.ts +++ b/frontend/app/src/app/modules/assessments/page/assessments-page.component.ts @@ -71,6 +71,7 @@ export class AssessmentsPageComponent implements OnInit, AfterViewInit { queryParams: { token: this.activatedRoute.snapshot.queryParamMap.get('token'), }, + state: {item: thing}, }); }); diff --git a/frontend/app/src/app/modules/catalog/catalog.component.ts b/frontend/app/src/app/modules/catalog/catalog.component.ts index 2a1fa921..5b76dfa3 100644 --- a/frontend/app/src/app/modules/catalog/catalog.component.ts +++ b/frontend/app/src/app/modules/catalog/catalog.component.ts @@ -65,7 +65,7 @@ export class CatalogComponent implements OnInit { .itemSelectListener() .pipe(takeUntilDestroyed()) .subscribe(item => { - void this.router.navigate(['data-detail', item.uid]); + void this.router.navigate(['data-detail', item.uid], {state: {item}}); }); } diff --git a/frontend/app/src/app/modules/dashboard/dashboard.component.html b/frontend/app/src/app/modules/dashboard/dashboard.component.html index 36a6ded3..b3e9df5d 100644 --- a/frontend/app/src/app/modules/dashboard/dashboard.component.html +++ b/frontend/app/src/app/modules/dashboard/dashboard.component.html @@ -26,6 +26,7 @@ {{ 'dashboard.schedule.title' | translate }} diff --git a/frontend/app/src/app/modules/dashboard/dashboard.component.ts b/frontend/app/src/app/modules/dashboard/dashboard.component.ts index b5fa34b5..08b01c68 100644 --- a/frontend/app/src/app/modules/dashboard/dashboard.component.ts +++ b/frontend/app/src/app/modules/dashboard/dashboard.component.ts @@ -76,7 +76,7 @@ export class DashboardComponent implements OnInit, OnDestroy { .itemSelectListener() .pipe(takeUntilDestroyed()) .subscribe(item => { - void this.router.navigate(['data-detail', item.uid]); + void this.router.navigate(['data-detail', item.uid], {state: {item}}); }); } diff --git a/frontend/app/src/app/modules/dashboard/sections/mensa-section/mensa-section-content.component.html b/frontend/app/src/app/modules/dashboard/sections/mensa-section/mensa-section-content.component.html index 33dacbd0..7801db5d 100644 --- a/frontend/app/src/app/modules/dashboard/sections/mensa-section/mensa-section-content.component.html +++ b/frontend/app/src/app/modules/dashboard/sections/mensa-section/mensa-section-content.component.html @@ -18,7 +18,6 @@ diff --git a/frontend/app/src/app/modules/data/detail/data-detail.component.spec.ts b/frontend/app/src/app/modules/data/detail/data-detail.component.spec.ts index 91469523..c75b6dfc 100644 --- a/frontend/app/src/app/modules/data/detail/data-detail.component.spec.ts +++ b/frontend/app/src/app/modules/data/detail/data-detail.component.spec.ts @@ -111,8 +111,8 @@ describe('DataDetailComponent', () => { expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(sampleThing.uid, false); }); - it('should get a data item when the view is entered', () => { - comp.ionViewWillEnter(); + it('should get a data item when initialized', () => { + comp.ngOnInit(); expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(sampleThing.uid, false); }); }); diff --git a/frontend/app/src/app/modules/data/detail/data-detail.component.ts b/frontend/app/src/app/modules/data/detail/data-detail.component.ts index 0d880722..263a992b 100644 --- a/frontend/app/src/app/modules/data/detail/data-detail.component.ts +++ b/frontend/app/src/app/modules/data/detail/data-detail.component.ts @@ -12,9 +12,9 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {Component, ContentChild, EventEmitter, Input, Output, TemplateRef} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; -import {ModalController, ViewWillEnter} from '@ionic/angular'; +import {Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; +import {ModalController} from '@ionic/angular'; import {LangChangeEvent, TranslateService} from '@ngx-translate/core'; import {SCLanguageCode, SCSaveableThing, SCThings, SCUuid} from '@openstapps/core'; import {DataProvider, DataScope} from '../data.provider'; @@ -37,7 +37,7 @@ export interface ExternalDataLoadEvent { styleUrls: ['data-detail.scss'], templateUrl: 'data-detail.html', }) -export class DataDetailComponent implements ViewWillEnter { +export class DataDetailComponent implements OnInit { /** * The associated item * @@ -84,21 +84,19 @@ export class DataDetailComponent implements ViewWillEnter { return (thing as SCSaveableThing).data !== undefined; } - /** - * - * @param route the route the page was accessed from - * @param dataProvider the data provider - * @param favoritesService the favorites provider - * @param modalController the modal controller - * @param translateService he translate provider - */ constructor( protected readonly route: ActivatedRoute, + router: Router, private readonly dataProvider: DataProvider, private readonly favoritesService: FavoritesService, readonly modalController: ModalController, translateService: TranslateService, ) { + this.inputItem = router.getCurrentNavigation()?.extras.state?.item; + if (!this.inputItem) { + // TODO: remove + console.warn('Did you forget to pass a state?'); + } this.language = translateService.currentLang as SCLanguageCode; translateService.onLangChange.subscribe((event: LangChangeEvent) => { this.language = event.lang as SCLanguageCode; @@ -138,10 +136,7 @@ export class DataDetailComponent implements ViewWillEnter { } } - /** - * Initialize - */ - async ionViewWillEnter() { + async ngOnInit() { const uid = this.route.snapshot.paramMap.get('uid') || ''; await this.getItem(uid ?? '', false); // fallback to the saved item (from favorites) diff --git a/frontend/app/src/app/modules/data/list/search-page.component.ts b/frontend/app/src/app/modules/data/list/search-page.component.ts index 22a4af8c..adfa8bab 100644 --- a/frontend/app/src/app/modules/data/list/search-page.component.ts +++ b/frontend/app/src/app/modules/data/list/search-page.component.ts @@ -342,7 +342,7 @@ export class SearchPageComponent implements OnInit { .pipe(takeUntilDestroyed(this.destroy$)) .subscribe(item => { if (this.itemRouting) { - void this.router.navigate(['/data-detail', item.uid]); + void this.router.navigate(['/data-detail', item.uid], {state: {item}}); } }); } diff --git a/frontend/app/src/app/modules/data/list/simple-data-list.component.ts b/frontend/app/src/app/modules/data/list/simple-data-list.component.ts index 7cf789cd..36e2dc1e 100644 --- a/frontend/app/src/app/modules/data/list/simple-data-list.component.ts +++ b/frontend/app/src/app/modules/data/list/simple-data-list.component.ts @@ -61,7 +61,7 @@ export class SimpleDataListComponent implements OnInit { .itemSelectListener() .pipe(takeUntilDestroyed(this.destroy$)) .subscribe(item => { - void this.router.navigate(['/data-detail', item.uid]); + void this.router.navigate(['/data-detail', item.uid], {state: {item}}); }); } } diff --git a/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.component.ts b/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.component.ts index 11c2eca5..d9cc8475 100644 --- a/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.component.ts +++ b/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.component.ts @@ -40,7 +40,7 @@ export class DateSeriesDetailContentComponent implements OnInit { .itemSelectListener() .pipe(takeUntilDestroyed()) .subscribe(item => { - void router.navigate(['/data-detail', item.uid]); + void router.navigate(['/data-detail', item.uid], {state: {item}}); }); } diff --git a/frontend/app/src/app/modules/data/types/place/place-detail-content.component.ts b/frontend/app/src/app/modules/data/types/place/place-detail-content.component.ts index 79f35af7..f376815f 100644 --- a/frontend/app/src/app/modules/data/types/place/place-detail-content.component.ts +++ b/frontend/app/src/app/modules/data/types/place/place-detail-content.component.ts @@ -59,7 +59,7 @@ export class PlaceDetailContentComponent implements OnInit { .itemSelectListener() .pipe(takeUntilDestroyed()) .subscribe(item => { - void router.navigate(['/data-detail', item.uid]); + void router.navigate(['/data-detail', item.uid], {state: {item}}); }); } diff --git a/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts b/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts index b709e7d5..15bd2bd0 100644 --- a/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts +++ b/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts @@ -75,7 +75,7 @@ export class PlaceMensaDetailComponent implements AfterViewInit { .itemSelectListener() .pipe(takeUntilDestroyed(this.destroy$)) .subscribe(item => { - void this.router.navigate(['/data-detail', item.uid]); + void this.router.navigate(['/data-detail', item.uid], {state: {item}}); }); } diff --git a/frontend/app/src/app/modules/favorites/favorites-page.component.ts b/frontend/app/src/app/modules/favorites/favorites-page.component.ts index ee549979..167f863a 100644 --- a/frontend/app/src/app/modules/favorites/favorites-page.component.ts +++ b/frontend/app/src/app/modules/favorites/favorites-page.component.ts @@ -112,12 +112,15 @@ export class FavoritesPageComponent extends SearchPageComponent implements OnIni .subscribe(item => { if (this.itemRouting) { if ([SCThingType.Book, SCThingType.Periodical, SCThingType.Article].includes(item.type)) { - void this.router.navigate([ - 'hebis-detail', - (item.origin && 'originalId' in item.origin && item.origin['originalId']) || '', - ]); + void this.router.navigate( + [ + 'hebis-detail', + (item.origin && 'originalId' in item.origin && item.origin['originalId']) || '', + ], + {state: {item}}, + ); } else { - void this.router.navigate(['data-detail', item.uid]); + void this.router.navigate(['data-detail', item.uid], {state: {item}}); } } }); diff --git a/frontend/app/src/app/modules/hebis/daia-availability/daia-availability.component.ts b/frontend/app/src/app/modules/hebis/daia-availability/daia-availability.component.ts index fac26db8..89ec1fbe 100644 --- a/frontend/app/src/app/modules/hebis/daia-availability/daia-availability.component.ts +++ b/frontend/app/src/app/modules/hebis/daia-availability/daia-availability.component.ts @@ -12,16 +12,11 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {Component, OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; -import {TranslateService} from '@ngx-translate/core'; +import {Component, inject, OnInit} from '@angular/core'; import {SCUuid} from '@openstapps/core'; -import {FavoritesService} from '../../favorites/favorites.service'; -import {DataProvider} from '../../data/data.provider'; import {DataDetailComponent} from '../../data/detail/data-detail.component'; import {DaiaDataProvider} from '../daia-data.provider'; import {DaiaHolding} from '../protocol/response'; -import {ModalController} from '@ionic/angular'; import {groupByStable} from '@openstapps/collection-utils'; /** @@ -37,28 +32,10 @@ export class DaiaAvailabilityComponent extends DataDetailComponent implements On holdingsByDepartments?: Map; - /** - * - * @param route the route the page was accessed from - * @param dataProvider the data provider - * @param favoritesService the favorites provider - * @param modalController the modal controller - * @param translateService he translate provider - * @param daiaDataProvider DaiaDataProvider - */ - constructor( - route: ActivatedRoute, - dataProvider: DataProvider, - favoritesService: FavoritesService, - modalController: ModalController, - translateService: TranslateService, - private daiaDataProvider: DaiaDataProvider, - ) { - super(route, dataProvider, favoritesService, modalController, translateService); - } + private daiaDataProvider = inject(DaiaDataProvider); /** - * Initialize + * @override */ async ngOnInit() { const uid = this.route.snapshot.paramMap.get('uid'); diff --git a/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts b/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts index 9923d456..05845805 100644 --- a/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts +++ b/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts @@ -107,8 +107,8 @@ describe('HebisDetailComponent', () => { expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith(sampleThing.uid, false); }); - it('should get a data item when the view is entered', () => { - comp.ionViewWillEnter(); + it('should get a data item when initialized', () => { + comp.ngOnInit(); expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith(sampleThing.uid, false); }); }); diff --git a/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.ts b/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.ts index d4644bd8..b62e7bec 100644 --- a/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.ts +++ b/frontend/app/src/app/modules/hebis/hebis-detail/hebis-detail.component.ts @@ -12,16 +12,11 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {Component} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; -import {TranslateService} from '@ngx-translate/core'; +import {Component, inject, OnInit} from '@angular/core'; import {SCUuid} from '@openstapps/core'; import {HebisDataProvider} from '../hebis-data.provider'; -import {FavoritesService} from '../../favorites/favorites.service'; -import {DataProvider} from '../../data/data.provider'; import {DataDetailComponent} from '../../data/detail/data-detail.component'; import {DaiaHolding} from '../protocol/response'; -import {ModalController} from '@ionic/angular'; /** * A Component to display an SCThing detailed @@ -31,33 +26,15 @@ import {ModalController} from '@ionic/angular'; styleUrls: ['hebis-detail.scss'], templateUrl: 'hebis-detail.html', }) -export class HebisDetailComponent extends DataDetailComponent { +export class HebisDetailComponent extends DataDetailComponent implements OnInit { holdings: DaiaHolding[]; - /** - * - * @param route the route the page was accessed from - * @param dataProvider the data provider - * @param favoritesService the favorites provider - * @param modalController the modal controller - * @param translateService he translate provider - * @param hebisDataProvider HebisDataProvider - */ - constructor( - route: ActivatedRoute, - dataProvider: DataProvider, - favoritesService: FavoritesService, - modalController: ModalController, - translateService: TranslateService, - private hebisDataProvider: HebisDataProvider, - ) { - super(route, dataProvider, favoritesService, modalController, translateService); - } + private hebisDataProvider = inject(HebisDataProvider); /** - * Initialize + * @override */ - async ionViewWillEnter() { + async ngOnInit() { const uid = this.route.snapshot.paramMap.get('uid') || ''; await this.getItem(uid ?? '', false); } @@ -68,9 +45,11 @@ export class HebisDetailComponent extends DataDetailComponent { * @param _forceReload Ignore any cached data */ async getItem(uid: SCUuid, _forceReload: boolean) { - this.hebisDataProvider.hebisSearch({query: uid, page: 0}).then(result => { - // eslint-disable-next-line unicorn/no-null - this.item = (result.data && result.data[0]) || null; - }); + this.item = await (this.inputItem ?? + this.hebisDataProvider.hebisSearch({query: uid, page: 0}).then( + result => + // eslint-disable-next-line unicorn/no-null + (result.data && result.data[0]) || null, + )); } } diff --git a/frontend/app/src/app/modules/hebis/list/hebis-search-page.component.ts b/frontend/app/src/app/modules/hebis/list/hebis-search-page.component.ts index eb79648f..fcdfd233 100644 --- a/frontend/app/src/app/modules/hebis/list/hebis-search-page.component.ts +++ b/frontend/app/src/app/modules/hebis/list/hebis-search-page.component.ts @@ -13,19 +13,12 @@ * this program. If not, see . */ import {Component, Input, OnInit} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; -import {AlertController, AnimationController} from '@ionic/angular'; -import {NGXLogger} from 'ngx-logger'; import {combineLatest} from 'rxjs'; import {debounceTime, distinctUntilChanged, startWith} from 'rxjs/operators'; -import {ContextMenuService} from '../../menu/context/context-menu.service'; -import {SettingsProvider} from '../../settings/settings.provider'; -import {DataRoutingService} from '../../data/data-routing.service'; import {SearchPageComponent} from '../../data/list/search-page.component'; import {HebisDataProvider} from '../hebis-data.provider'; -import {PositionService} from '../../map/position.service'; -import {ConfigProvider} from '../../config/config.provider'; import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; +import {DataProvider} from '../../data/data.provider'; /** * HebisSearchPageComponent queries things and shows list of things as search results and filter as context menu @@ -34,6 +27,7 @@ import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; selector: 'stapps-hebissearch-page', templateUrl: 'hebis-search-page.html', styleUrls: ['../../data/list/search-page.scss'], + providers: [{provide: DataProvider, useClass: HebisDataProvider}], }) export class HebisSearchPageComponent extends SearchPageComponent implements OnInit { /** @@ -46,47 +40,6 @@ export class HebisSearchPageComponent extends SearchPageComponent implements OnI */ page = 0; - /** - * Injects the providers and creates subscriptions - * @param alertController AlertController - * @param dataProvider HebisProvider - * @param contextMenuService ContextMenuService - * @param settingsProvider SettingsProvider - * @param logger An angular logger - * @param dataRoutingService DataRoutingService - * @param router Router - * @param route Active Route - * @param positionService PositionService - * @param configProvider ConfigProvider - */ - constructor( - protected readonly alertController: AlertController, - protected dataProvider: HebisDataProvider, - protected readonly contextMenuService: ContextMenuService, - protected readonly settingsProvider: SettingsProvider, - protected readonly logger: NGXLogger, - protected dataRoutingService: DataRoutingService, - protected router: Router, - route: ActivatedRoute, - protected positionService: PositionService, - configProvider: ConfigProvider, - animationController: AnimationController, - ) { - super( - alertController, - dataProvider, - contextMenuService, - settingsProvider, - logger, - dataRoutingService, - router, - route, - positionService, - configProvider, - animationController, - ); - } - /** * Fetches items with set query configuration * @param append If true fetched data gets appended to existing, override otherwise (default false) @@ -103,7 +56,7 @@ export class HebisSearchPageComponent extends SearchPageComponent implements OnI searchOptions.query = this.queryText; } - return this.dataProvider.hebisSearch(searchOptions).then( + return (this.dataProvider as HebisDataProvider).hebisSearch(searchOptions).then( async result => { /*this.singleTypeResponse = result.facets.find(facet => facet.field === 'type')?.buckets @@ -176,10 +129,10 @@ export class HebisSearchPageComponent extends SearchPageComponent implements OnI .pipe(takeUntilDestroyed(this.destroy$)) .subscribe(async item => { if (this.itemRouting) { - void this.router.navigate([ - 'hebis-detail', - (item.origin && 'originalId' in item.origin && item.origin['originalId']) || '', - ]); + void this.router.navigate( + ['hebis-detail', (item.origin && 'originalId' in item.origin && item.origin['originalId']) || ''], + {state: {item}}, + ); } }); } diff --git a/frontend/app/src/app/modules/map/page/map-page.component.ts b/frontend/app/src/app/modules/map/page/map-page.component.ts index 373a9892..1dedb91a 100644 --- a/frontend/app/src/app/modules/map/page/map-page.component.ts +++ b/frontend/app/src/app/modules/map/page/map-page.component.ts @@ -158,7 +158,7 @@ export class MapPageComponent implements OnInit { if (this.items.length > 1) { await Promise.all([this.modalController.dismiss(), this.showItem(item.uid)]); } else { - void this.router.navigate(['/data-detail', item.uid]); + void this.router.navigate(['/data-detail', item.uid], {state: {item}}); } }); this.positionService diff --git a/frontend/app/src/app/modules/news/item/news-item.html b/frontend/app/src/app/modules/news/item/news-item.html index 73185de1..9f333998 100644 --- a/frontend/app/src/app/modules/news/item/news-item.html +++ b/frontend/app/src/app/modules/news/item/news-item.html @@ -15,6 +15,7 @@ diff --git a/frontend/app/src/app/util/section.component.html b/frontend/app/src/app/util/section.component.html index 18e62b92..98453149 100644 --- a/frontend/app/src/app/util/section.component.html +++ b/frontend/app/src/app/util/section.component.html @@ -15,7 +15,7 @@ - +