[ACA-4681] Added file auto download feature to DocumentList component (#8423)

* [ACA-4681] Added feature in DocumentListComponent to auto download a file if it exceeds a pre defined file size threshold

* [ACA-4681] Added test cases for file auto download feature in document list (NOT WORKING)

* [ACA-4681] Fixed unit tests for file auto download feature of document list

* [ACA-4681] Removed unused variables from app.config.json

* [ACA-4681] Resolved code review findings. Local constants are no longer upper case only (used camelCase instead). FileAutoDownload component template now uses mat-dialog provided directives and components. Removed file-auto-download.component.scss. Removed unused methods from file-auto-download.component.ts

* [ACA-4681] Added licence info to file-auto-download-actions.enum.ts

* [ACA-4681] Added license info to file-auto-download.component.ts

* [ACA-4681] Removed empty constructor

* [ACA-4681] Updated appConfig property name from "preview-config" to "viewer".

* [ACA-4681] Added JSDoc for FileAutoDownloadActionsEnum

* [ACA-4681] Updated ADF demo shell application to use "viewer" appConfig object instead of "preview-config"

* [ACA-4681] Resolved lint issues

* [ACA-4681] Removed dependency from NodeActionsService inside DocumentListComponent. FileAutoDownload component now directly triggers the file download, instead of emitting FileAutoDownloadActionsEnum.Download.

* [ACA-4681] Removed unused async. Updated import statement

* [ACA-4681] Added FileAutoDownloadComponent to public-api.ts
This commit is contained in:
swapnil-verma-gl 2023-04-04 13:01:23 +05:30 committed by GitHub
parent 2bd72f71d5
commit fc3ad78004
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 247 additions and 7 deletions

View File

@ -1476,5 +1476,9 @@
"ai:labels",
"ai:textLines"
]
},
"viewer": {
"enableFileAutoDownload": true,
"fileAutoDownloadSizeThresholdInMB": 15
}
}

View File

@ -653,6 +653,18 @@
</mat-form-field>
</form>
<section>
<mat-slide-toggle
color="primary" [(ngModel)]="enableFileAutoDownload" id="enableFileAutoDownload" (change)="onEnableFileAutoDownloadChange()">
Enable FileAutoDownload
</mat-slide-toggle>
</section>
<section *ngIf="enableFileAutoDownload">
<mat-form-field>
<input matInput type="number" [(ngModel)]="fileAutoDownloadSizeThresholdInMB" (change)="onFileAutoDownloadSizeThresholdChange()">
</mat-form-field>
</section>
<h5>Upload</h5>
<section *ngIf="acceptedFilesTypeShow">
<mat-form-field floatPlaceholder="float">

View File

@ -251,6 +251,9 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
selectedNodes = [];
enableFileAutoDownload: boolean = this.appConfig.get('viewer.enableFileAutoDownload', true);
fileAutoDownloadSizeThresholdInMB: number = this.appConfig.get('viewer.fileAutoDownloadSizeThresholdInMB', 15);
constructor(private notificationService: NotificationService,
private uploadService: UploadService,
private contentService: ContentService,
@ -777,4 +780,14 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
this.selectedNodes = [];
}
onEnableFileAutoDownloadChange() {
const previewConfig = this.appConfig?.config['viewer'];
previewConfig['enableFileAutoDownload'] = this.enableFileAutoDownload;
}
onFileAutoDownloadSizeThresholdChange() {
const previewConfig = this.appConfig?.config['viewer'];
previewConfig['fileAutoDownloadSizeThresholdInMB'] = this.fileAutoDownloadSizeThresholdInMB;
}
}

View File

@ -790,6 +790,27 @@ This will give the following output:
![Custom loading](../../docassets/images/custom-loading.png)
### File Auto downloading
In case of files exceeding a predefined file size, the document list component can be configured to automatically download those file when trying to preview them.
This can help in reducing server load, and ensuring quick access to such files. After turning this feature on, whenever the user tries to preview a file with a large
file size, the Document List component will first preview a dialog, asking for confirmation from the user on whether they want to download the file, or cancel the preview altogether.
In order to configure the Document List to automatically download the files, the following environment variables would need to be set up in app.config.json -
```
"viewer": {
"enableFileAutoDownload": true,
"fileAutoDownloadSizeThresholdInMB": 15
}
```
Here, `"enableFileAutoDownload": true,` would enable the file auto download feature on the Document List component. Setting this flag to false disables this feature, and always
triggers a file preview when trying to view a file, regardless of its size.
The second configuration here, `"fileAutoDownloadSizeThresholdInMB": 15` specifies the file size threshold (in MB), after which the Document List component will start downloading the file.
In the example provided above, any file greater than 15MB in size would trigger the auto download functionality. Files lower than 15MB in size would continue to preview normally.
## See also
- [Datatable component](../../core/components/datatable.component.md)

View File

@ -27,7 +27,7 @@ import {
DataTableModule,
ObjectDataTableAdapter,
ShowHeaderMode,
ThumbnailService
ThumbnailService, AppConfigService
} from '@alfresco/adf-core';
import { ContentService } from '../../common/services/content.service';
@ -62,6 +62,12 @@ import { ShareDataRow } from '../data/share-data-row.model';
import { DocumentLoaderNode } from '../models/document-folder.model';
import { matIconRegistryMock } from '../../testing/mat-icon-registry-mock';
import { domSanitizerMock } from '../../testing/dom-sanitizer-mock';
import { MatDialog } from '@angular/material/dialog';
import { FileAutoDownloadComponent } from './file-auto-download/file-auto-download.component';
const mockDialog = {
open: jasmine.createSpy('open')
};
describe('DocumentList', () => {
@ -71,6 +77,7 @@ describe('DocumentList', () => {
let customResourcesService: CustomResourcesService;
let thumbnailService: ThumbnailService;
let contentService: ContentService;
let appConfigService: AppConfigService;
let fixture: ComponentFixture<DocumentListComponent>;
let element: HTMLElement;
let eventMock: any;
@ -84,7 +91,10 @@ describe('DocumentList', () => {
TranslateModule.forRoot(),
ContentTestingModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{ provide: MatDialog, useValue: mockDialog }
]
});
beforeEach(() => {
@ -102,6 +112,7 @@ describe('DocumentList', () => {
customResourcesService = TestBed.inject(CustomResourcesService);
thumbnailService = TestBed.inject(ThumbnailService);
contentService = TestBed.inject(ContentService);
appConfigService = TestBed.inject(AppConfigService);
spyFolder = spyOn(documentListService, 'getFolder').and.returnValue(of({ list: {} }));
spyFolderNode = spyOn(documentListService, 'getFolderNode').and.returnValue(of(new NodeEntry({ entry: {} })));
@ -1567,6 +1578,30 @@ describe('DocumentList', () => {
}), undefined);
});
it('should display fileAutoDownload dialog if node size exceeds appConfig.viewer.fileAutoDownloadSizeThresholdInMB', async () => {
appConfigService.config = {
...appConfigService.config,
'viewer': {
'enableFileAutoDownload': true,
'fileAutoDownloadSizeThresholdInMB': 10
}
};
documentList.navigationMode = DocumentListComponent.SINGLE_CLICK_NAVIGATION;
const node = { entry: {
...mockNode1,
content: {
...mockNode1.content,
sizeInBytes: 104857600
}
} };
documentList.onNodeClick(node);
fixture.detectChanges();
await fixture.whenStable();
expect(mockDialog.open).toHaveBeenCalledWith(FileAutoDownloadComponent, { disableClose: true, data: node });
});
describe('Preselect nodes', () => {
beforeEach(() => {

View File

@ -66,6 +66,10 @@ import { LockService } from '../services/lock.service';
import { DocumentLoaderNode } from '../models/document-folder.model';
import { takeUntil } from 'rxjs/operators';
import { ADF_DOCUMENT_PARENT_COMPONENT } from './document-list.token';
import { MatDialog } from '@angular/material/dialog';
import { FileAutoDownloadComponent } from './file-auto-download/file-auto-download.component';
const BYTES_TO_MB_CONVERSION_VALUE = 1048576;
@Component({
selector: 'adf-document-list',
@ -367,7 +371,8 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
private alfrescoApiService: AlfrescoApiService,
private nodeService: NodesApiService,
private dataTableService: DataTableService,
private lockService: LockService) {
private lockService: LockService,
private dialog: MatDialog) {
this.nodeService.nodeUpdated.subscribe((node) => {
this.dataTableService.rowUpdate.next({id: node.id, obj: {entry: node}});
@ -758,9 +763,18 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
onPreviewFile(node: NodeEntry) {
if (node) {
const sizeInMB = node.entry?.content?.sizeInBytes / BYTES_TO_MB_CONVERSION_VALUE;
const fileAutoDownloadFlag: boolean = this.appConfig.get('viewer.enableFileAutoDownload', true);
const sizeThreshold: number = this.appConfig.get('viewer.fileAutoDownloadSizeThresholdInMB', 15);
if (fileAutoDownloadFlag && sizeInMB && sizeInMB > sizeThreshold) {
this.dialog.open(FileAutoDownloadComponent, { disableClose: true, data: node });
} else {
this.preview.emit(new NodeEntityEvent(node));
}
}
}
onNodeClick(nodeEntry: NodeEntry) {
const domEvent = new CustomEvent('node-click', {

View File

@ -0,0 +1,24 @@
<div mat-dialog-title>
<h3>{{ 'ADF-DOCUMENT-LIST.FILE_AUTO_DOWNLOAD_DIALOG.HEADER' | translate }}</h3>
</div>
<mat-dialog-content>
{{ 'ADF-DOCUMENT-LIST.FILE_AUTO_DOWNLOAD_DIALOG.LABEL' | translate }}
</mat-dialog-content>
<mat-dialog-actions align="end">
<button
mat-button
mat-dialog-close
id="cancelButton"
[attr.aria-label]="'ADF-DOCUMENT-LIST.FILE_AUTO_DOWNLOAD_DIALOG.ACTIONS.CANCEL' | translate">
{{ 'ADF-DOCUMENT-LIST.FILE_AUTO_DOWNLOAD_DIALOG.ACTIONS.CANCEL' | translate }}
</button>
<button
mat-button
mat-dialog-close
id="downloadButton"
color="primary"
[attr.aria-label]="'ADF-DOCUMENT-LIST.FILE_AUTO_DOWNLOAD_DIALOG.ACTIONS.DOWNLOAD' | translate"
[adfNodeDownload]="node">
{{ 'ADF-DOCUMENT-LIST.FILE_AUTO_DOWNLOAD_DIALOG.ACTIONS.DOWNLOAD' | translate }}
</button>
</mat-dialog-actions>

View File

@ -0,0 +1,76 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FileAutoDownloadComponent } from './file-auto-download.component';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { By } from '@angular/platform-browser';
import { CoreTestingModule } from '@alfresco/adf-core';
import { TranslateModule } from '@ngx-translate/core';
import { NO_ERRORS_SCHEMA } from '@angular/core';
const mockDialog = {
close: jasmine.createSpy('close')
};
describe('FileAutoDownloadComponent', () => {
let matDialogRef: MatDialogRef<FileAutoDownloadComponent>;
let fixture: ComponentFixture<FileAutoDownloadComponent>;
const getButton = (buttonId: string) => {
return fixture.debugElement.query(By.css(buttonId)).nativeElement;
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [FileAutoDownloadComponent],
imports: [
TranslateModule.forRoot(),
CoreTestingModule
],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{ provide: MatDialogRef, useValue: mockDialog },
{ provide: MAT_DIALOG_DATA, useValue: null }
]
});
fixture = TestBed.createComponent(FileAutoDownloadComponent);
matDialogRef = TestBed.inject(MatDialogRef);
fixture.detectChanges();
});
it('should emit FileAutoDownloadActionsEnum.CANCEL and close dialog when clicking on the cancel button', async () => {
const waitButton = getButton('#cancelButton');
waitButton.dispatchEvent(new Event('click'));
await fixture.detectChanges();
await fixture.whenStable();
expect(matDialogRef.close).toHaveBeenCalled();
});
it('should emit FileAutoDownloadActionsEnum.DOWNLOAD and close dialog when clicking on the wait button', async () => {
const waitButton = getButton('#downloadButton');
waitButton.dispatchEvent(new Event('click'));
await fixture.detectChanges();
await fixture.whenStable();
expect(matDialogRef.close).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,28 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { NodeEntry } from '@alfresco/js-api';
@Component({
selector: 'adf-file-auto-download',
templateUrl: './file-auto-download.component.html'
})
export class FileAutoDownloadComponent {
constructor(@Inject(MAT_DIALOG_DATA) public node: NodeEntry) {}
}

View File

@ -35,6 +35,8 @@ import { LibraryRoleColumnComponent } from './components/library-role-column/lib
import { LibraryNameColumnComponent } from './components/library-name-column/library-name-column.component';
import { NameColumnComponent } from './components/name-column/name-column.component';
import { FilterHeaderComponent } from './components/filter-header/filter-header.component';
import { FileAutoDownloadComponent } from './components/file-auto-download/file-auto-download.component';
import { ContentDirectiveModule } from '../directives/content-directive.module';
@NgModule({
imports: [
@ -45,7 +47,8 @@ import { FilterHeaderComponent } from './components/filter-header/filter-header.
MaterialModule,
UploadModule,
EditJsonDialogModule,
SearchModule
SearchModule,
ContentDirectiveModule
],
declarations: [
DocumentListComponent,
@ -56,7 +59,8 @@ import { FilterHeaderComponent } from './components/filter-header/filter-header.
NameColumnComponent,
ContentActionComponent,
ContentActionListComponent,
FilterHeaderComponent
FilterHeaderComponent,
FileAutoDownloadComponent
],
exports: [
DocumentListComponent,

View File

@ -25,6 +25,7 @@ export * from './components/library-status-column/library-status-column.componen
export * from './components/name-column/name-column.component';
export * from './components/filter-header/filter-header.component';
export * from './components/trashcan-name-column/trashcan-name-column.component';
export * from './components/file-auto-download/file-auto-download.component';
// data
export * from './data/share-datatable-adapter';

View File

@ -73,7 +73,15 @@
"REMOVE": "Remove",
"DOWNLOAD": "Download"
},
"LOADER_LABEL": "Document list loader"
"LOADER_LABEL": "Document list loader",
"FILE_AUTO_DOWNLOAD_DIALOG": {
"HEADER": "Preview loading unresponsive",
"LABEL": "Download to view this document, or cancel to continue without preview.",
"ACTIONS": {
"CANCEL": "Cancel",
"DOWNLOAD": "Download"
}
}
},
"ALFRESCO_DOCUMENT_LIST": {
"BUTTON": {