From bfc62248b279bfe8b4e5ef252b8e0245fd7a89c1 Mon Sep 17 00:00:00 2001 From: Thuy Nguyen <145430420+nntthuy-axonivy@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:52:58 +0700 Subject: [PATCH 1/2] MARP-1455 Fix infinite product fetching (#241) --- .../market/repository/impl/CustomProductRepositoryImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/marketplace-service/src/main/java/com/axonivy/market/repository/impl/CustomProductRepositoryImpl.java b/marketplace-service/src/main/java/com/axonivy/market/repository/impl/CustomProductRepositoryImpl.java index 40e82370..9e21de2d 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/repository/impl/CustomProductRepositoryImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/repository/impl/CustomProductRepositoryImpl.java @@ -111,11 +111,15 @@ public List findAllProductsHaveDocument() { } private Page getResultAsPageable(Pageable pageable, Criteria criteria) { + int skip = (int) pageable.getOffset(); + int limit = pageable.getPageSize(); Aggregation aggregation = Aggregation.newAggregation( Aggregation.match(criteria), Aggregation.lookup(MongoDBConstants.PRODUCT_MARKETPLACE_COLLECTION, MongoDBConstants.ID, MongoDBConstants.ID, MongoDBConstants.MARKETPLACE_DATA), - Aggregation.sort(pageable.getSort()) + Aggregation.sort(pageable.getSort()), + Aggregation.skip(skip), + Aggregation.limit(limit) ); List entities = mongoTemplate.aggregate(aggregation, MongoDBConstants.PRODUCT_COLLECTION, From 9061409e4d97e82b62a014d4699030f0ec8f6f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=E1=BA=A7n=20V=C4=A9nh=20Thi=E1=BB=87n=20Ph=C3=BAc?= <143604440+tvtphuc-axonivy@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:19:50 +0700 Subject: [PATCH 2/2] MARP-1449 Portal Guide does not match with Portal version (#240) --- ...t-detail-information-tab.component.spec.ts | 58 +++++++++++++++++-- ...roduct-detail-information-tab.component.ts | 15 ++++- .../product-detail/product-detail.service.ts | 4 +- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.spec.ts b/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.spec.ts index c0fd9b7c..52760f93 100644 --- a/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.spec.ts +++ b/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ProductDetailInformationTabComponent } from './product-detail-information-tab.component'; import { of } from 'rxjs'; -import { SimpleChanges } from '@angular/core'; +import { SimpleChange, SimpleChanges } from '@angular/core'; import { ProductDetailService } from '../product-detail.service'; import { LanguageService } from '../../../../core/services/language/language.service'; import { ProductDetail } from '../../../../shared/models/product-detail.model'; @@ -20,7 +20,7 @@ describe('ProductDetailInformationTabComponent', () => { let productDetailService: jasmine.SpyObj; beforeEach(async () => { - const productDetailServiceSpy = jasmine.createSpyObj('ProductDetailService', ['getExteralDocumentForProductByVersion']); + const productDetailServiceSpy = jasmine.createSpyObj('ProductDetailService', ['getExternalDocumentForProductByVersion']); await TestBed.configureTestingModule({ imports: [ProductDetailInformationTabComponent, @@ -43,7 +43,7 @@ describe('ProductDetailInformationTabComponent', () => { }); it('should set externalDocumentLink and displayExternalDocName on valid version change', () => { - productDetailService.getExteralDocumentForProductByVersion.and.returnValue(of({ ...MOCK_EXTERNAL_DOCUMENT })); + productDetailService.getExternalDocumentForProductByVersion.and.returnValue(of({ ...MOCK_EXTERNAL_DOCUMENT })); component.productDetail = { id: TEST_ID, newestReleaseVersion: TEST_VERSION } as ProductDetail; component.selectedVersion = TEST_VERSION; @@ -64,7 +64,7 @@ describe('ProductDetailInformationTabComponent', () => { component.ngOnChanges(changes); - expect(productDetailService.getExteralDocumentForProductByVersion).toHaveBeenCalledWith(TEST_ID, TEST_VERSION); + expect(productDetailService.getExternalDocumentForProductByVersion).toHaveBeenCalledWith(TEST_ID, TEST_VERSION); expect(component.externalDocumentLink).toBe(TEST_DOC_URL); expect(component.displayExternalDocName).toBe(TEST_ARTIFACT_NAME); }); @@ -89,7 +89,7 @@ describe('ProductDetailInformationTabComponent', () => { component.ngOnChanges(changes); - expect(productDetailService.getExteralDocumentForProductByVersion).not.toHaveBeenCalled(); + expect(productDetailService.getExternalDocumentForProductByVersion).not.toHaveBeenCalled(); expect(component.externalDocumentLink).toBe(''); expect(component.displayExternalDocName).toBe(''); }); @@ -99,4 +99,52 @@ describe('ProductDetailInformationTabComponent', () => { const extractedValue = component.extractVersionValue(versionDisplayName); expect(extractedValue).toBe(TEST_VERSION); }); + + it('should check isProductChanged correct', () => { + component.productDetail = { id: TEST_ID, newestReleaseVersion: '11.3.0' } as ProductDetail; + const productChanged: SimpleChange = { + currentValue: component.productDetail, + previousValue: undefined, + firstChange: true, + isFirstChange: () => true + }; + + const result = component.isProductChanged(productChanged); + expect(result).toBe(false); + }); + + it('should check isProductChanged correct if the same value', () => { + component.productDetail = { id: TEST_ID, newestReleaseVersion: '11.3.0' } as ProductDetail; + const productChanged: SimpleChange = { + currentValue: component.productDetail, + previousValue: component.productDetail.newestReleaseVersion = '12.0.0-m266', + firstChange: true, + isFirstChange: () => true + }; + + const result = component.isProductChanged(productChanged); + expect(result).toBe(true); + }); + + it('should get correct externalDocumentLink by newestReleaseVersion', () => { + productDetailService.getExternalDocumentForProductByVersion.and.returnValue(of({ ...MOCK_EXTERNAL_DOCUMENT })); + component.productDetail = { id: TEST_ID, newestReleaseVersion: TEST_VERSION } as ProductDetail; + component.selectedVersion = TEST_VERSION; + const changes: SimpleChanges = { + selectedVersion: { + currentValue: TEST_VERSION, + previousValue: '8.0.0', + firstChange: false, + isFirstChange: () => false + }, + productDetail: { + currentValue: component.productDetail, + previousValue: component.productDetail.newestReleaseVersion = '12.0.0-m266', + firstChange: true, + isFirstChange: () => true + } + }; + component.ngOnChanges(changes); + expect(productDetailService.getExternalDocumentForProductByVersion).toHaveBeenCalledWith(TEST_ID, '12.0.0-m266'); + }); }); diff --git a/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.ts b/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.ts index 3127f16c..16335a22 100644 --- a/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.ts +++ b/marketplace-ui/src/app/modules/product/product-detail/product-detail-information-tab/product-detail-information-tab.component.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { Component, inject, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, inject, Input, OnChanges, SimpleChange, SimpleChanges } from '@angular/core'; import { TranslateModule } from '@ngx-translate/core'; import { ProductDetail } from '../../../../shared/models/product-detail.model'; import { LanguageService } from '../../../../core/services/language/language.service'; @@ -37,7 +37,7 @@ export class ProductDetailInformationTabComponent implements OnChanges { return; } const changedProduct = changes[PRODUCT_DETAIL]; - if (changedProduct && changedProduct.currentValue !== changedProduct.previousValue) { + if (this.isProductChanged(changedProduct)) { version = this.productDetail.newestReleaseVersion; } else { version = this.selectedVersion; @@ -47,7 +47,7 @@ export class ProductDetailInformationTabComponent implements OnChanges { return; } - this.productDetailService.getExteralDocumentForProductByVersion(this.productDetail.id, this.extractVersionValue(version)) + this.productDetailService.getExternalDocumentForProductByVersion(this.productDetail.id, this.extractVersionValue(version)) .subscribe({ next: response => { this.externalDocumentLink = response.relativeLink; @@ -66,4 +66,13 @@ export class ProductDetailInformationTabComponent implements OnChanges { extractVersionValue(versionDisplayName: string) { return versionDisplayName.replace(VERSION.displayPrefix, ''); } + + // To ensure the function always returns a boolean, you can explicitly coerce the result into a boolean using the !! operator or default it to false + // Adding !! in case of changedProduct is undefined, it will return false instead of returning undefined + isProductChanged(changedProduct: SimpleChange) { + return !!(changedProduct?.previousValue && + Object.keys(changedProduct.previousValue).length > 0 && + changedProduct.currentValue !== changedProduct.previousValue); + } + } diff --git a/marketplace-ui/src/app/modules/product/product-detail/product-detail.service.ts b/marketplace-ui/src/app/modules/product/product-detail/product-detail.service.ts index 603fe2fa..df0dfa9f 100644 --- a/marketplace-ui/src/app/modules/product/product-detail/product-detail.service.ts +++ b/marketplace-ui/src/app/modules/product/product-detail/product-detail.service.ts @@ -17,8 +17,8 @@ export class ProductDetailService { httpClient = inject(HttpClient); loadingService = inject(LoadingService); ratingBtnLabel: WritableSignal = signal(''); - - getExteralDocumentForProductByVersion(productId: string, version: string): Observable { + + getExternalDocumentForProductByVersion(productId: string, version: string): Observable { return this.httpClient.get( `${API_URI.EXTERNAL_DOCUMENT}/${productId}/${version}`, { context: new HttpContext().set(ForwardingError, true)} );