Skip to content

Commit 6e6de71

Browse files
samir-ayoubjhosefmarks
authored andcommitted
feat(upload): adiciona opção para envio de pastas
Adicionado a propriedade `p-directory` que possibilita o envio de pastas. Fixes DTHFUI-787
1 parent 20a36f9 commit 6e6de71

18 files changed

+836
-92
lines changed

projects/ui/src/lib/components/po-field/po-field.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { HttpClientModule } from '@angular/common/http';
55

66
import { PoButtonGroupModule } from '../po-button-group/index';
77
import { PoButtonModule } from '../po-button/index';
8+
import { PoContainerModule } from '../po-container/index';
89
import { PoDisclaimerModule } from './../po-disclaimer/po-disclaimer.module';
910
import { PoLoadingModule } from '../po-loading/index';
1011
import { PoModalModule } from '../po-modal/po-modal.module';
@@ -64,6 +65,7 @@ import { PoUrlComponent } from './po-url/po-url.component';
6465
HttpClientModule,
6566
PoButtonGroupModule,
6667
PoButtonModule,
68+
PoContainerModule,
6769
PoDisclaimerModule,
6870
PoLoadingModule,
6971
PoModalModule,

projects/ui/src/lib/components/po-field/po-upload/interfaces/po-upload-literals.interface.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,48 @@ export interface PoUploadLiterals {
2727
*/
2828
deleteFile?: string;
2929

30-
/** Texto exibido na área onde podem ser arrastados os arquivos ao utilizar a opção de *dragDrop*. */
30+
/** Texto indicativo para a área onde os arquivos devem ser arrastados quando utilizada a propriedade `p-drag-drop`. */
3131
dragFilesHere?: string;
3232

33-
/** Texto exibido na área onde podem ser arrastados os arquivos ao utilizar a opção de *dragDrop*. */
33+
/** Texto indicativo para a área onde os diretórios devem ser arrastados quando utilizada a propriedade `p-drag-drop`. */
34+
dragFoldersHere?: string;
35+
36+
/** Texto indicativo para a área onde os arquivos devem ser soltos quando utilizada a propriedade `p-drag-drop` */
3437
dropFilesHere?: string;
3538

39+
/** Texto indicativo para a área onde os diretórios devem ser soltos quando utilizada a propriedade `p-drag-drop`. */
40+
dropFoldersHere?: string;
41+
42+
/** Parâmetro *files* para o texto de exibição quando arrastado um arquivo para um local inválido com a opção de *dragDrop*. */
43+
files?: string;
44+
45+
/** Parâmetro *folders* para o texto de exibição quando arrastado um arquivo para um local inválido com a opção de *dragDrop*. */
46+
folders?: string;
47+
3648
/** Texto exibido caso o usuário arrastar um arquivo para um local inválido ao utilizar a opção de *dragDrop*. */
3749
invalidDropArea?: string;
3850

3951
/** Texto exibido no label do botão de seleção dos arquivos. */
4052
selectFile?: string;
4153

54+
/** Texto exibido no label do botão de seleção dos arquivos ao utilizar a propriedade `p-multiple`. */
55+
selectFiles?: string;
56+
57+
/** Texto exibido no label do botão de seleção dos arquivos ao utilizar a propriedade `p-directory`. */
58+
selectFolder?: string;
59+
4260
/**
4361
* Texto utilizado para indicar a possibilidade de seleção de arquivos na área onde podem ser arrastados os arquivos
4462
* ao utilizar a opção de *dragDrop*.
4563
*/
4664
selectFilesOnComputer?: string;
4765

66+
/**
67+
* Texto utilizado para indicar a possibilidade de seleção de diretório na área onde podem ser arrastados os arquivos
68+
* ao utilizar a opção de *dragDrop*.
69+
*/
70+
selectFolderOnComputer?: string;
71+
4872
/** Texto exibido no label do botão para iniciar o envio dos arquivos. */
4973
startSending?: string;
5074

projects/ui/src/lib/components/po-field/po-upload/po-upload-base.component.spec.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class PoUploadComponent extends PoUploadBaseComponent {
2828
}
2929

3030
sendFeedback() {}
31+
setDirectoryAttribute() {}
3132
}
3233

3334
describe('PoUploadBaseComponent:', () => {
@@ -431,6 +432,22 @@ describe('PoUploadBaseComponent:', () => {
431432
expect(component['updateExistsFileInFiles']).not.toHaveBeenCalled();
432433
});
433434

435+
it('insertFileInFiles: should call `files.push` with newFile if `directory` is true and `existsFileSameName` is false', () => {
436+
const files = [];
437+
component.directory = true;
438+
component.isMultiple = true;
439+
440+
spyOn(files, 'push');
441+
spyOn(component, <any> 'existsFileSameName').and.returnValue(false);
442+
spyOn(component, <any> 'updateExistsFileInFiles');
443+
444+
component['insertFileInFiles'](file, files);
445+
446+
expect(files.push).toHaveBeenCalledWith(file);
447+
expect(component['existsFileSameName']).toHaveBeenCalled();
448+
expect(component['updateExistsFileInFiles']).not.toHaveBeenCalled();
449+
});
450+
434451
it('insertFileInFiles: should call `updateExistsFileInFiles` when `existsFileSameName` is true', () => {
435452
const files = [];
436453

@@ -670,6 +687,96 @@ describe('PoUploadBaseComponent:', () => {
670687
expectPropertiesValues(component, 'hideSendButton', invalidValues, false);
671688
});
672689

690+
it('directory: should set `directory` with valid values', () => {
691+
const validValues = ['', true, 1, [], {}, 'true'];
692+
693+
expectPropertiesValues(component, 'directory', validValues, true);
694+
});
695+
696+
it('directory: should set `directory` to false with invalid values', () => {
697+
const invalidValues = [null, undefined, NaN, false, 0, 'false', 'teste'];
698+
699+
expectPropertiesValues(component, 'directory', invalidValues, false);
700+
});
701+
702+
it('directory: should apply true to `canHandleDirectory` if directory is true and `isIE` plus `isMobile` return false', () => {
703+
component.canHandleDirectory = undefined;
704+
705+
spyOn(utilsFunctions, <any>'isIE').and.returnValue(false);
706+
spyOn(utilsFunctions, <any>'isMobile').and.returnValue(false);
707+
708+
component.directory = true;
709+
710+
expect(component.canHandleDirectory).toBeTruthy();
711+
});
712+
713+
it('directory: should apply false to `canHandleDirectory` if directory is true but `isIE` returns true', () => {
714+
spyOn(utilsFunctions, <any>'isIE').and.returnValue(true);
715+
spyOn(utilsFunctions, <any>'isMobile').and.returnValue(false);
716+
717+
component.directory = true;
718+
719+
expect(component.canHandleDirectory).toBeFalsy();
720+
});
721+
722+
it('directory: should apply false to `canHandleDirectory` if directory is true but `isMobile` returns true', () => {
723+
spyOn(utilsFunctions, <any>'isIE').and.returnValue(false);
724+
spyOn(utilsFunctions, <any>'isMobile').and.returnValue(true);
725+
726+
component.directory = true;
727+
728+
expect(component.canHandleDirectory).toBeFalsy();
729+
});
730+
731+
it('directory: should apply false to `canHandleDirectory` if directory is false', () => {
732+
spyOn(utilsFunctions, <any>'isIE').and.returnValue(false);
733+
spyOn(utilsFunctions, <any>'isMobile').and.returnValue(false);
734+
735+
component.directory = false;
736+
737+
expect(component.canHandleDirectory).toBeFalsy();
738+
});
739+
740+
it(`directory: call 'setDirectoryAttribute' passing true as parameter`, () => {
741+
spyOn(utilsFunctions, <any>'isIE').and.returnValue(false);
742+
spyOn(utilsFunctions, <any>'isMobile').and.returnValue(false);
743+
spyOn(component, 'setDirectoryAttribute');
744+
745+
component.directory = true;
746+
747+
expect(component['canHandleDirectory']).toBe(true);
748+
expect(component.setDirectoryAttribute).toHaveBeenCalledWith(true);
749+
});
750+
751+
it(`directory: should call 'setDirectoryAttribute' passing false as parameter`, () => {
752+
spyOn(utilsFunctions, <any>'isIE').and.returnValue(false);
753+
spyOn(utilsFunctions, <any>'isMobile').and.returnValue(true);
754+
spyOn(component, 'setDirectoryAttribute');
755+
756+
component.directory = false;
757+
758+
expect(component['canHandleDirectory']).toBe(false);
759+
expect(component.setDirectoryAttribute).toHaveBeenCalledWith(false);
760+
});
761+
762+
it('isMultiple: should set `isMultiple` with `true` if valid values', () => {
763+
const validValues = ['', true, 1, [], {}, 'true'];
764+
765+
expectPropertiesValues(component, 'isMultiple', validValues, true);
766+
});
767+
768+
it('isMultiple: should set `isMultiple` with `false` if invalid values', () => {
769+
const invalidValues = [null, undefined, NaN, false, 0, 'false', 'teste'];
770+
771+
expectPropertiesValues(component, 'isMultiple', invalidValues, false);
772+
});
773+
774+
it('isMultiple: should return true if `diretory` is true', () => {
775+
component.directory = true;
776+
777+
expect(component.isMultiple).toBe(true);
778+
});
779+
673780
});
674781

675782
});

projects/ui/src/lib/components/po-field/po-upload/po-upload-base.component.ts

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AbstractControl, ControlValueAccessor, Validator } from '@angular/forms';
22
import { EventEmitter, Input, Output } from '@angular/core';
33

4-
import { browserLanguage, convertToBoolean, isEquals, poLocaleDefault } from '../../../utils/util';
4+
import { browserLanguage, convertToBoolean, isEquals, isIE, isMobile, poLocaleDefault } from '../../../utils/util';
55
import { requiredFailed } from '../validators';
66

77
import { PoUploadFile } from './po-upload-file';
@@ -12,15 +12,23 @@ import { PoUploadStatus } from './po-upload-status.enum';
1212

1313
export const poUploadLiteralsDefault = {
1414
en: <PoUploadLiterals> {
15+
files: 'files',
16+
folders: 'folders',
1517
selectFile: 'Select file',
18+
selectFiles: 'Select files',
19+
selectFolder: 'Select folder',
1620
deleteFile: 'Delete',
1721
cancel: 'Cancel',
1822
tryAgain: 'Try again',
1923
startSending: 'Start sending',
2024
dragFilesHere: 'Drag files here',
25+
dragFoldersHere: 'Drag folders here',
2126
selectFilesOnComputer: 'or select files on your computer',
27+
selectFolderOnComputer: 'or select folder on your computer',
2228
dropFilesHere: 'Drop files here',
23-
invalidDropArea: 'Files were not dropped in the correct area',
29+
dropFoldersHere: 'Drop folders here',
30+
invalidDropArea: '{0} were not dropped in the correct area',
31+
invalidFileType: 'Failed to load {0} file(s) as it is not the allowed file type.',
2432
invalidAmount: 'Failed to load {0} file(s), as it exceeds the limit amount of files.',
2533
invalidFormat: 'Failed to load {0} file(s), as it does not match the format(s): {1}.',
2634
invalidSize: 'Failed to load {0} files(s), as it is not the allowed size: from {1} to {2}.',
@@ -33,15 +41,23 @@ export const poUploadLiteralsDefault = {
3341
sentWithSuccess: 'Sent with success'
3442
},
3543
es: <PoUploadLiterals> {
44+
files: 'archivos',
45+
folders: 'carpetas',
3646
selectFile: 'Seleccionar archivo',
47+
selectFiles: 'Seleccionar archivos',
48+
selectFolder: 'Seleccionar carpeta',
3749
deleteFile: 'Borrar',
3850
cancel: 'Cancelar',
3951
tryAgain: 'Intentar de nuevo',
4052
startSending: 'Iniciar carga',
4153
dragFilesHere: 'Arrastra los archivos aquí',
54+
dragFoldersHere: 'Arrastra las carpetas aquí',
4255
selectFilesOnComputer: 'o selecciona los archivos en tu computadora',
56+
selectFolderOnComputer: 'o selecciona la carpeta en tu computadora',
4357
dropFilesHere: 'Deja los archivos aquí',
44-
invalidDropArea: 'Los archivos no se insertaron en la ubicación correcta',
58+
dropFoldersHere: 'Deja las carpetas aquí',
59+
invalidDropArea: 'Los {0} no se insertaron en la ubicación correcta',
60+
invalidFileType: 'Error al cargar {0} archivo (s) ya que no es el tipo de archivo permitido',
4561
invalidAmount: 'Error al cargar {0} archivo (s) ya que excede la cantidad limite de archivos.',
4662
invalidFormat: 'Error al cargar {0} archivo (s) ya que no coincide con el formato (s): {1}.',
4763
invalidSize: 'Error al cargar {0} archivo (s) ya que no cumple con el tamaño permitido: desde {1} hasta {2}.',
@@ -54,15 +70,23 @@ export const poUploadLiteralsDefault = {
5470
sentWithSuccess: 'Enviado con éxito'
5571
},
5672
pt: <PoUploadLiterals> {
73+
files: 'arquivos',
74+
folders: 'diretórios',
5775
selectFile: 'Selecionar arquivo',
76+
selectFiles: 'Selecionar arquivos',
77+
selectFolder: 'Selecionar pasta',
5878
deleteFile: 'Excluir',
5979
cancel: 'Cancelar',
6080
tryAgain: 'Tentar Novamente',
6181
startSending: 'Iniciar envio',
6282
dragFilesHere: 'Arraste os arquivos aqui',
83+
dragFoldersHere: 'Arraste as pastas aqui',
6384
selectFilesOnComputer: 'ou selecione os arquivos no computador',
85+
selectFolderOnComputer: 'ou selecione a pasta no computador',
6486
dropFilesHere: 'Solte os arquivos aqui',
65-
invalidDropArea: 'Os arquivos não foram inseridos no local correto',
87+
dropFoldersHere: 'Solte as pastas aqui',
88+
invalidDropArea: 'Os {0} não foram inseridos no local correto',
89+
invalidFileType: 'Falha ao carregar {0} arquivo (s), pois não é o tipo de arquivo permitido',
6690
invalidAmount: 'Falha ao carregar {0} arquivo(s), pois excede(m) a quantidade limite de arquivos.',
6791
invalidFormat: 'Falha ao carregar {0} arquivo(s), pois não corresponde(m) ao(s) formato(s): {1}.',
6892
invalidSize: 'Falha ao carregar {0} arquivo(s), pois não atende ao tamanho permitido: {1} até {2}.',
@@ -86,6 +110,7 @@ const poUploadMinFileSize = 0;
86110
*
87111
* O componente `po-upload` permite que o usuário envie arquivo(s) ao servidor e acompanhe o progresso.
88112
* Este componente também possibilita algumas configurações como:
113+
* – Envio de diretórios, onde ele acessa o diretório selecionado assim como seus sub-diretórios;
89114
* - Múltipla seleção, onde o usuário pode enviar mais de um arquivo ao servidor.
90115
* - Auto envio, onde o arquivo é enviado imediatamente após a seleção do usuário, não necessitando que o usuário
91116
* clique em enviar.
@@ -96,19 +121,22 @@ const poUploadMinFileSize = 0;
96121
*/
97122
export abstract class PoUploadBaseComponent implements ControlValueAccessor, Validator {
98123

124+
private _directory?: boolean;
99125
private _disabled?: boolean;
100126
private _dragDrop?: boolean = false;
101127
private _fileRestrictions?: PoUploadFileRestrictions;
102128
private _formField?: string;
103129
private _hideRestrictionsInfo?: boolean;
104130
private _hideSelectButton?: boolean;
105131
private _hideSendButton?: boolean;
132+
private _isMultiple?: boolean;
106133
private _literals?: any;
107134
private _required?: boolean;
108135

109136
allowedExtensions: string;
110137
currentFiles: Array<PoUploadFile>;
111138

139+
canHandleDirectory: boolean;
112140
onModelChange: any;
113141
onModelTouched: any;
114142

@@ -118,6 +146,30 @@ export abstract class PoUploadBaseComponent implements ControlValueAccessor, Val
118146
protected quantityNotAllowed = 0;
119147
protected sizeNotAllowed = 0;
120148

149+
/**
150+
* @optional
151+
*
152+
* @description
153+
*
154+
* Permite a seleção de diretórios contendo um ou mais arquivos para envio.
155+
*
156+
* > A habilitação desta propriedade se restringe apenas à seleção de diretórios.
157+
*
158+
* > Definição não suportada pelo browser **Internet Explorer**, todavia será possível a seleção de arquivos padrão.
159+
*
160+
* @default `false`
161+
*/
162+
@Input('p-directory') set directory(value: boolean) {
163+
this._directory = convertToBoolean(value);
164+
165+
this.canHandleDirectory = this._directory && !isIE() && !isMobile();
166+
this.setDirectoryAttribute(this.canHandleDirectory);
167+
}
168+
169+
get directory() {
170+
return this._directory;
171+
}
172+
121173
/**
122174
* @optional
123175
*
@@ -341,8 +393,16 @@ export abstract class PoUploadBaseComponent implements ControlValueAccessor, Val
341393
* @description
342394
*
343395
* Define se pode selecionar mais de um arquivo.
396+
*
397+
* > Se utilizada a `p-directory`, habilita-se automaticamente esta propriedade.
344398
*/
345-
@Input('p-multiple') isMultiple?: boolean;
399+
@Input('p-multiple') set isMultiple(value: boolean) {
400+
this._isMultiple = convertToBoolean(value);
401+
}
402+
403+
get isMultiple() {
404+
return this.canHandleDirectory ? true : this._isMultiple;
405+
}
346406

347407
/**
348408
* @optional
@@ -569,4 +629,6 @@ export abstract class PoUploadBaseComponent implements ControlValueAccessor, Val
569629
return files;
570630
}
571631

632+
abstract setDirectoryAttribute(value: boolean);
633+
572634
}

projects/ui/src/lib/components/po-field/po-upload/po-upload-drag-drop/po-upload-drag-drop-area-overlay/po-upload-drag-drop-area-overlay.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<po-upload-drag-drop-area #DragDropAreaFixed
44
class="po-upload-drag-drop-area-overlay"
5+
[p-directory-compatible]="directoryCompatible"
56
[p-disabled]="disabled"
67
[p-literals]="literals"
78
[p-overlay]="true">

projects/ui/src/lib/components/po-field/po-upload/po-upload-drag-drop/po-upload-drag-drop-area-overlay/po-upload-drag-drop-area-overlay.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export class PoUploadDragDropAreaOverlayComponent implements AfterViewInit {
1212

1313
@ViewChild('DragDropAreaFixed', { read: ElementRef, static: true }) DragDropAreaFixed: ElementRef;
1414

15+
@Input('p-directory-compatible') directoryCompatible: boolean;
16+
1517
@Input('p-disabled') disabled: boolean;
1618

1719
@Input('p-literals') literals: PoUploadLiterals;

0 commit comments

Comments
 (0)