From f26b34fa966f9d42a29400cf2ef4f2d2daa3ebe0 Mon Sep 17 00:00:00 2001 From: "swapnil.verma" Date: Wed, 18 Dec 2024 11:41:39 +0530 Subject: [PATCH] [MNT-24575] Addressed Code review comments --- .../folder-information.component.html | 60 ++++++++-------- .../folder-information.component.scss | 12 ++-- .../folder-information.component.spec.ts | 25 +++++-- .../folder-information.component.ts | 68 +++++++++---------- .../content-management.service.spec.ts | 39 ++++++++++- .../lib/store/effects/node.effects.spec.ts | 38 +++++++++++ 6 files changed, 161 insertions(+), 81 deletions(-) diff --git a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.html b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.html index 5387fa3512..08fdbe364c 100644 --- a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.html +++ b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.html @@ -1,36 +1,32 @@ -
-
-
- {{ 'APP.FOLDER_INFO.ICON' | translate }} -
-
{{ folderDetails.name }}
+
+ {{ 'APP.FOLDER_INFO.ICON' | translate }} +
{{ folderDetails.name }}
+
+ +
+
+
{{ 'APP.FOLDER_INFO.SIZE' | translate }}
+
{{ folderDetails.size }}
+
+ +
+
{{ 'APP.FOLDER_INFO.LOCATION' | translate }}
+
{{ folderDetails.location }}
+
+ +
+
{{ 'APP.FOLDER_INFO.CREATED' | translate }}
+
{{ folderDetails.created | adfTimeAgo }}
-
-
-
{{ 'APP.FOLDER_INFO.SIZE' | translate }}
-
{{ folderDetails.size }}
-
- -
-
{{ 'APP.FOLDER_INFO.LOCATION' | translate }}
-
{{ folderDetails.location }}
-
- -
-
{{ 'APP.FOLDER_INFO.CREATED' | translate }}
-
{{ folderDetails.created | adfTimeAgo }}
-
- -
-
{{ 'APP.FOLDER_INFO.MODIFIED' | translate }}
-
{{ folderDetails.modified | adfTimeAgo }}
-
+
+
{{ 'APP.FOLDER_INFO.MODIFIED' | translate }}
+
{{ folderDetails.modified | adfTimeAgo }}
diff --git a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.scss b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.scss index faab957cfd..b2173e9dcd 100644 --- a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.scss +++ b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.scss @@ -1,12 +1,10 @@ .app-folder-info { - .aca-folder-info { - &-container { - display: flex; - flex-direction: column; - border: 1px solid var(--theme-border-color); - border-radius: 12px; - } + display: flex; + flex-direction: column; + border: 1px solid var(--theme-border-color); + border-radius: 12px; + .aca-folder-info { &-header { display: flex; flex-direction: row; diff --git a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.spec.ts b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.spec.ts index 448dfcf09f..00a5a3c60b 100644 --- a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.spec.ts +++ b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.spec.ts @@ -27,16 +27,17 @@ import { FolderInformationComponent } from './folder-information.component'; import { DIALOG_COMPONENT_DATA, RedirectAuthService } from '@alfresco/adf-core'; import { ContentService, NodesApiService } from '@alfresco/adf-content-services'; import { By } from '@angular/platform-browser'; -import { EMPTY, of, Subject } from 'rxjs'; +import { EMPTY, Observable, of, Subject } from 'rxjs'; import { LibTestingModule } from '@alfresco/aca-shared'; +import { JobIdBodyEntry, SizeDetails, SizeDetailsEntry, Node } from '@alfresco/js-api'; describe('FolderInformationComponent', () => { let fixture: ComponentFixture; let nodeService: NodesApiService; - let initiateFolderSizeCalculationSpy: jasmine.Spy; - let getFolderSizeInfoSpy: jasmine.Spy; - const mockSub = new Subject<{ entry: { jobId: string } }>(); + let initiateFolderSizeCalculationSpy: jasmine.Spy<(nodeId: string) => Observable>; + let getFolderSizeInfoSpy: jasmine.Spy<(nodeId: string, jobId: string) => Observable>; + const mockSub = new Subject(); const dialogData = { name: 'mock-folder', id: 'mock-folder-id', @@ -45,9 +46,20 @@ describe('FolderInformationComponent', () => { }, createdAt: new Date(2024, 1, 1, 11, 11), modifiedAt: new Date(2024, 2, 2, 22, 22) + } as Node; + const mockSizeDetailsEntry: SizeDetailsEntry = { + entry: { + id: 'mock-id', + sizeInBytes: '1', + calculatedAt: 'mock-date', + numberOfFiles: 1, + status: SizeDetails.StatusEnum.COMPLETE, + jobId: 'mock-job-id' + } }; const getValueFromElement = (id: string): string => fixture.debugElement.query(By.css(`[data-automation-id="${id}"]`)).nativeElement.textContent; + beforeEach(() => { TestBed.configureTestingModule({ imports: [FolderInformationComponent, LibTestingModule], @@ -86,7 +98,8 @@ describe('FolderInformationComponent', () => { }); it('should make repeated calls to get folder size info, if the response returned from the API is IN_PROGRESS', fakeAsync(() => { - getFolderSizeInfoSpy.and.returnValue(of({ entry: { status: 'IN_PROGRESS' } })); + mockSizeDetailsEntry.entry.status = SizeDetails.StatusEnum.IN_PROGRESS; + getFolderSizeInfoSpy.and.returnValue(of(mockSizeDetailsEntry)); fixture.detectChanges(); expect(getFolderSizeInfoSpy).not.toHaveBeenCalled(); mockSub.next({ entry: { jobId: 'mock-job-id' } }); @@ -95,7 +108,7 @@ describe('FolderInformationComponent', () => { expect(getFolderSizeInfoSpy).toHaveBeenCalledTimes(2); tick(5000); expect(getFolderSizeInfoSpy).toHaveBeenCalledTimes(3); - getFolderSizeInfoSpy.and.returnValue(of({ entry: { status: 'COMPLETE' } })); + mockSizeDetailsEntry.entry.status = SizeDetails.StatusEnum.COMPLETE; tick(5000); expect(getFolderSizeInfoSpy).toHaveBeenCalledTimes(4); tick(5000); diff --git a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.ts b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.ts index 1a65e73d2d..65dc223065 100644 --- a/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.ts +++ b/projects/aca-content/src/lib/dialogs/folder-details/folder-information.component.ts @@ -23,19 +23,19 @@ */ import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; -import { CommonModule, NgIf } from '@angular/common'; +import { CommonModule, NgOptimizedImage } from '@angular/common'; import { DIALOG_COMPONENT_DATA, LocalizedDatePipe, TimeAgoPipe } from '@alfresco/adf-core'; -import { JobIdBodyEntry, Node, SizeDetailsEntry } from '@alfresco/js-api'; +import { JobIdBodyEntry, Node, SizeDetails } from '@alfresco/js-api'; import { MatDividerModule } from '@angular/material/divider'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { ContentService, NodesApiService } from '@alfresco/adf-content-services'; -import { concatMap, expand, first } from 'rxjs/operators'; +import { concatMap, expand, first, switchMap } from 'rxjs/operators'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { EMPTY, timer } from 'rxjs'; const MEMORY_UNIT_LIST = ['bytes', 'KB', 'MB', 'GB', 'TB']; -interface FolderDetails { +class FolderDetails { name: string; size: string; location: string; @@ -47,7 +47,7 @@ interface FolderDetails { @Component({ selector: 'app-folder-info', standalone: true, - imports: [CommonModule, MatDividerModule, TimeAgoPipe, NgIf, TranslateModule, LocalizedDatePipe, LocalizedDatePipe], + imports: [CommonModule, MatDividerModule, TimeAgoPipe, TranslateModule, LocalizedDatePipe, NgOptimizedImage], templateUrl: './folder-information.component.html', styleUrls: ['./folder-information.component.scss'], encapsulation: ViewEncapsulation.None, @@ -61,7 +61,7 @@ export class FolderInformationComponent implements OnInit { private readonly destroyRef = inject(DestroyRef); data: Node = inject(DIALOG_COMPONENT_DATA); - folderDetails: FolderDetails; + folderDetails: FolderDetails = new FolderDetails(); ngOnInit() { this.folderDetails.name = this.data.name; @@ -73,38 +73,38 @@ export class FolderInformationComponent implements OnInit { this.nodesService .initiateFolderSizeCalculation(this.data.id) - .pipe(first()) - .subscribe((jobIdEntry: JobIdBodyEntry) => { - this.nodesService - .getFolderSizeInfo(this.data.id, jobIdEntry.entry.jobId) - .pipe( - expand((result: SizeDetailsEntry) => - result.entry.status === 'IN_PROGRESS' + .pipe( + first(), + switchMap((jobIdEntry: JobIdBodyEntry) => { + return this.nodesService.getFolderSizeInfo(this.data.id, jobIdEntry.entry.jobId).pipe( + expand((result) => + result.entry.status === SizeDetails.StatusEnum.IN_PROGRESS ? timer(5000).pipe(concatMap(() => this.nodesService.getFolderSizeInfo(this.data.id, jobIdEntry.entry.jobId))) : EMPTY ), takeUntilDestroyed(this.destroyRef) - ) - .subscribe((folderInfo: SizeDetailsEntry) => { - let size = parseFloat(folderInfo.entry.sizeInBytes); - let unitIndex = 0; - let isMoreThanBytes = false; - while (size > 1000) { - isMoreThanBytes = true; - size = size / 1000; - unitIndex++; - } - const params = { - sizeInBytes: parseFloat(folderInfo.entry.sizeInBytes).toLocaleString('en'), - sizeInLargeUnit: size.toFixed(2), - unit: MEMORY_UNIT_LIST[unitIndex], - count: folderInfo.entry.numberOfFiles - }; - this.folderDetails.size = this.translateService.instant( - isMoreThanBytes ? 'APP.FOLDER_INFO.CALCULATED_SIZE_LARGE' : 'APP.FOLDER_INFO.CALCULATED_SIZE_NORMAL', - params - ); - }); + ); + }) + ) + .subscribe((folderInfo) => { + let size = parseFloat(folderInfo.entry.sizeInBytes); + let unitIndex = 0; + let isMoreThanBytes = false; + while (size > 1000) { + isMoreThanBytes = true; + size = size / 1000; + unitIndex++; + } + const params = { + sizeInBytes: parseFloat(folderInfo.entry.sizeInBytes).toLocaleString('en'), + sizeInLargeUnit: size.toFixed(2), + unit: MEMORY_UNIT_LIST[unitIndex], + count: folderInfo.entry.numberOfFiles + }; + this.folderDetails.size = this.translateService.instant( + isMoreThanBytes ? 'APP.FOLDER_INFO.CALCULATED_SIZE_LARGE' : 'APP.FOLDER_INFO.CALCULATED_SIZE_NORMAL', + params + ); }); } } diff --git a/projects/aca-content/src/lib/services/content-management.service.spec.ts b/projects/aca-content/src/lib/services/content-management.service.spec.ts index c0e6f0a88d..6f29e7127a 100644 --- a/projects/aca-content/src/lib/services/content-management.service.spec.ts +++ b/projects/aca-content/src/lib/services/content-management.service.spec.ts @@ -53,10 +53,10 @@ import { AppHookService, AppSettingsService, ContentApiService } from '@alfresco import { Store } from '@ngrx/store'; import { ContentManagementService } from './content-management.service'; import { NodeActionsService } from './node-actions.service'; -import { NotificationService, TranslationService } from '@alfresco/adf-core'; +import { DialogComponent, DialogSize, NotificationService, TranslationService } from '@alfresco/adf-core'; import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MatSnackBarModule, MatSnackBarRef, SimpleSnackBar } from '@angular/material/snack-bar'; -import { Node, NodeEntry, VersionPaging } from '@alfresco/js-api'; +import { Node, NodeEntry, UserInfo, VersionPaging } from '@alfresco/js-api'; import { DocumentListService, FileModel, @@ -67,6 +67,7 @@ import { NodesApiService, ViewVersion } from '@alfresco/adf-content-services'; +import { FolderInformationComponent } from '../dialogs/folder-details/folder-information.component'; describe('ContentManagementService', () => { let dialog: MatDialog; @@ -1847,4 +1848,38 @@ describe('ContentManagementService', () => { expect(store.dispatch).toHaveBeenCalledWith(new NavigateRouteAction(['/libraries'])); })); }); + + describe('folderInformationDialog', () => { + it('should open folder information dialog', () => { + spyOn(dialog, 'open'); + + const fakeNode: NodeEntry = { + entry: { + id: 'folder-node-id', + name: 'mock-folder-name', + nodeType: 'fake-node-type', + isFolder: true, + isFile: false, + modifiedAt: new Date(), + modifiedByUser: new UserInfo(), + createdAt: new Date(), + createdByUser: new UserInfo() + } + }; + + contentManagementService.showFolderInformation(fakeNode); + expect(dialog.open).toHaveBeenCalledWith(DialogComponent, { + data: { + title: 'APP.FOLDER_INFO.TITLE', + confirmButtonTitle: 'APP.FOLDER_INFO.DONE', + isCancelButtonHidden: true, + isCloseButtonHidden: false, + dialogSize: DialogSize.Large, + contentComponent: FolderInformationComponent, + componentData: fakeNode.entry + }, + width: '700px' + }); + }); + }); }); diff --git a/projects/aca-content/src/lib/store/effects/node.effects.spec.ts b/projects/aca-content/src/lib/store/effects/node.effects.spec.ts index e2b8d38f75..e6d5696b37 100644 --- a/projects/aca-content/src/lib/store/effects/node.effects.spec.ts +++ b/projects/aca-content/src/lib/store/effects/node.effects.spec.ts @@ -34,6 +34,7 @@ import { DeleteNodesAction, EditFolderAction, ExpandInfoDrawerAction, + FolderInformationAction, FullscreenViewerAction, ManageAspectsAction, ManagePermissionsAction, @@ -59,6 +60,7 @@ import { NavigationEnd, Router, ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { MatDialogModule } from '@angular/material/dialog'; import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { NodeEntry, UserInfo } from '@alfresco/js-api'; describe('NodeEffects', () => { let store: Store; @@ -564,4 +566,40 @@ describe('NodeEffects', () => { expect(store.dispatch).toHaveBeenCalledWith(new NavigateUrlAction('personal-files/details/node-id?location=test-page')); }); }); + + describe('folderInformation$', () => { + it('should call folder information dialog', () => { + const node: any = { entry: { isFile: true } }; + spyOn(contentService, 'showFolderInformation').and.stub(); + + store.dispatch(new FolderInformationAction(node)); + + expect(contentService.showFolderInformation).toHaveBeenCalled(); + }); + + it('should call folder information dialog from the active folder selection', fakeAsync(() => { + spyOn(contentService, 'showFolderInformation').and.stub(); + + const node: NodeEntry = { + entry: { + id: 'folder-node-id', + name: 'mock-folder-name', + nodeType: 'fake-node-type', + isFolder: true, + isFile: false, + modifiedAt: new Date(), + modifiedByUser: new UserInfo(), + createdAt: new Date(), + createdByUser: new UserInfo() + } + }; + store.dispatch(new SetSelectedNodesAction([node])); + + tick(100); + + store.dispatch(new FolderInformationAction(null)); + + expect(contentService.showFolderInformation).toHaveBeenCalledWith(node); + })); + }); });