Skip to content

Commit

Permalink
feat(uploader): changes showing error, add file icon (#1013)
Browse files Browse the repository at this point in the history
* feat(upload): show errors on top as one message box

* feat(upload): always use 'message' appearance for error box

* feat(upload): show file extension icon

* feat(upload): custom extension type icon

* feat(upload): correct color

* feat(upload): correct style

* feat(upload): set max height list

* feat(upload): set max height list

* feat(upload): hide upload button if all files uploaded

* feat(upload): validator errors on max file limit reached during adding new file

Co-authored-by: [email protected] <[email protected]>
  • Loading branch information
2 people authored and GitHub Enterprise committed Sep 22, 2023
1 parent c57a631 commit c4c592e
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,22 @@
Add File
</button>

<nx-error *ngIf="testForm.controls['documents'].hasError('required')"
>Required!</nx-error
>
<nx-error
*ngIf="testForm.controls['documents'].hasError('NxFileUploadMaxFileNumber')"
>
There were
{{testForm.controls['documents'].getError('NxFileUploadMaxFileNumber').actual
| json}} files added, but the maximum is
{{testForm.controls['documents'].getError('NxFileUploadMaxFileNumber').max
| json}}
<nx-error *ngIf="testForm.controls['documents']?.errors">
<div class="nx-font-weight-bold">Error</div>
<ul>
<li *ngIf="testForm.controls['documents'].hasError('required')">
Required!
</li>
<li
*ngIf="testForm.controls['documents'].hasError('NxFileUploadMaxFileNumber')"
>
There were
{{testForm.controls['documents'].getError('NxFileUploadMaxFileNumber').actual
| json}} files added, but the maximum is
{{testForm.controls['documents'].getError('NxFileUploadMaxFileNumber').max
| json}}
</li>
</ul>
</nx-error>
</nx-file-uploader>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,21 @@
</button>
</nx-file-uploader-drop-zone>

<nx-error *ngIf="testForm.controls['documents'].hasError('required')"
>Required!</nx-error
>
<nx-error
*ngIf="testForm.controls['documents'].hasError('NxFileUploadFileTypeNotAccepted')"
>
File
{{testForm.controls['documents'].getError('NxFileUploadFileTypeNotAccepted').fileName
| json}} can not be uploaded. This file type is not supported!
<nx-error *ngIf="testForm.controls['documents']?.errors">
<div class="nx-font-weight-bold">Error</div>
<ul>
<li *ngIf="testForm.controls['documents'].hasError('required')">
Required!
</li>
<li
*ngIf="testForm.controls['documents'].hasError('NxFileUploadFileTypeNotAccepted')"
>
File
{{testForm.controls['documents'].getError('NxFileUploadFileTypeNotAccepted').fileName
| json}} can not be uploaded. This file type is not
supported!
</li>
</ul>
</nx-error>
</nx-file-uploader>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,21 @@
</button>
</nx-file-uploader-drop-zone>

<nx-error *ngIf="testForm.controls['documents'].hasError('required')"
>Required!</nx-error
>
<nx-error
*ngIf="testForm.controls['documents'].hasError('NxFileUploadFileTypeNotAccepted')"
>
File
{{testForm.controls['documents'].getError('NxFileUploadFileTypeNotAccepted').fileName
| json}} can not be uploaded. This file type is not supported!
<nx-error *ngIf="testForm.controls['documents']?.errors">
<div class="nx-font-weight-bold">Error</div>
<ul>
<li *ngIf="testForm.controls['documents'].hasError('required')">
Required!
</li>
<li
*ngIf="testForm.controls['documents'].hasError('NxFileUploadFileTypeNotAccepted')"
>
File
{{testForm.controls['documents'].getError('NxFileUploadFileTypeNotAccepted').fileName
| json}} can not be uploaded. This file type is not
supported!
</li>
</ul>
</nx-error>
</nx-file-uploader>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,25 @@
Add File
</button>

<nx-error *ngIf="testForm.controls['documents'].hasError('required')"
>Required!</nx-error
>
<nx-error *ngIf="testForm.controls['documents'].hasError('serverError')"
>An error occured while uploading.</nx-error
>
<nx-error
*ngIf="testForm.controls['documents'].hasError('NxFileUploadMaxFileSize')"
>
File
{{testForm.controls['documents'].getError('NxFileUploadMaxFileSize').fileName
| json}} can not be uploaded. File size exceeds size limit!
<nx-error *ngIf="testForm.controls['documents'].errors">
<div class="nx-font-weight-bold">Error</div>
<ul>
<li *ngIf="testForm.controls['documents'].hasError('required')">
Required!
</li>
<li
*ngIf="testForm.controls['documents'].hasError('serverError')"
>
An error occured while uploading.
</li>
<li
*ngIf="testForm.controls['documents'].hasError('NxFileUploadMaxFileSize')"
>
File
{{testForm.controls['documents'].getError('NxFileUploadMaxFileSize').fileName
| json}} can not be uploaded. File size exceeds size limit!
</li>
</ul>
</nx-error>
</nx-file-uploader>
</form>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Directive, HostListener, Input } from '@angular/core';
import { Directive, HostBinding, HostListener, Input } from '@angular/core';

import { NxFileUploaderComponent } from './file-uploader.component';

Expand All @@ -23,4 +23,8 @@ export class NxFileUploaderTriggerDirective {
_onClick() {
this._fileUpload.uploadFiles();
}

@HostBinding('style.visibility') get visibility() {
return this._fileUpload.allFilesUploaded ? 'hidden' : 'unset';
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<ng-content select="nx-error" *ngIf="errorState || errors.length"></ng-content>

<ng-content select="nx-label"></ng-content>
<ng-content select="[nxFileUploadHint]"></ng-content>
<ng-content select="nx-file-uploader-drop-zone"></ng-content>
Expand Down Expand Up @@ -29,8 +31,6 @@
</div>
</ng-container>

<ng-content select="nx-error" *ngIf="errorState || errors.length"></ng-content>

<ng-template #defaultFileRow let-templateContext="templateContext" let-file="file">
<nx-file-upload-name [name]="file?.name"></nx-file-upload-name>

Expand Down
12 changes: 12 additions & 0 deletions projects/ng-aquila/src/file-uploader/file-uploader.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@

::ng-deep nx-error.nx-error--message {
margin: nx-spacer(xs) 0;

ul {
margin-left: 28px;
margin-top: 6px;
}
li {
line-height: nx-spacer(m);
}
}
}

.nx-file-uploader--file-list {
max-height: 400px;
overflow-y: auto;
}
.nx-file-uploader--file-row {
display: flex;
flex-wrap: wrap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ abstract class FileUploaderTest {
maxFileNumber!: number;
accept: any;
strictAcceptValidation = false;
disableCommonValidator = false;
noBlockingValidators = false;
}

describe('NxFileUploaderComponent', () => {
Expand Down Expand Up @@ -406,6 +406,18 @@ describe('NxFileUploaderComponent', () => {
expect(testInstance.form.controls.documents.hasError('NxFileUploadFileTypeNotAccepted')).toBeTrue();
});

it('invalid when file number reached max then click add button', () => {
createTestComponent(ReactiveFileUpload);
testInstance.maxFileNumber = 2;
fixture.detectChanges();

createAndAddFile('test.png', 'some type');
createAndAddFile('test.png', 'some type');
createAndAddFile('test.png', 'some type');
fixture.detectChanges();
expect(testInstance.form.controls.documents.hasError('NxFileUploadMaxFileNumber')).toBeTrue();
});

describe('getFileExtension', () => {
it('should return the file extension', () => {
expect(getFileExtension('test.png')).toBe('.png');
Expand Down Expand Up @@ -538,10 +550,10 @@ describe('NxFileUploaderComponent', () => {
});
});

describe('disable validators', () => {
it('should has require validation error even if disableCommonValidator is true', () => {
describe('no blocking validators', () => {
it('should has require validation error even if noBlockingValidators is true', () => {
createTestComponent(ReactiveFileUpload);
fixture.componentInstance.disableCommonValidator = true;
fixture.componentInstance.noBlockingValidators = true;

const submitButton = fixture.nativeElement.querySelector('#submit-button') as HTMLButtonElement;
testInstance.required = true;
Expand All @@ -551,10 +563,10 @@ describe('NxFileUploaderComponent', () => {
expect(testInstance.form.controls.documents.hasError('required')).toBeTrue();
});

it('should not has max fileNumber validator error if disableCommonValidator is true', () => {
it('should not has max fileNumber validator error if noBlockingValidators is true', () => {
createTestComponent(ReactiveFileUpload);
testInstance.maxFileNumber = 2;
fixture.componentInstance.disableCommonValidator = true;
fixture.componentInstance.noBlockingValidators = true;
fixture.detectChanges();

createAndAddFile('test.png', 'some type');
Expand All @@ -564,9 +576,9 @@ describe('NxFileUploaderComponent', () => {
expect(testInstance.form.controls.documents.hasError('NxFileUploadMaxFileNumber')).toBeFalse();
});

it('should not has file type validator error if disableCommonValidator is true', () => {
it('should not has file type validator error if noBlockingValidators is true', () => {
createTestComponent(ReactiveFileUpload);
fixture.componentInstance.disableCommonValidator = true;
fixture.componentInstance.noBlockingValidators = true;

testInstance.accept = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
fixture.detectChanges();
Expand All @@ -575,9 +587,9 @@ describe('NxFileUploaderComponent', () => {
expect(testInstance.form.controls.documents.hasError('NxFileUploadFileTypeNotAccepted')).toBeFalse();
});

it('should not has file size validator error if disableCommonValidator is true', () => {
it('should not has file size validator error if noBlockingValidators is true', () => {
createTestComponent(ReactiveFileUpload);
fixture.componentInstance.disableCommonValidator = true;
fixture.componentInstance.noBlockingValidators = true;
testInstance.maxFileSize = 1024;
fixture.detectChanges();

Expand Down Expand Up @@ -675,7 +687,7 @@ class BasicFileUpload extends FileUploaderTest {
multiple
[maxFileNumber]="maxFileNumber"
[accept]="accept"
[noBlockingValidators]="disableCommonValidator"
[noBlockingValidators]="noBlockingValidators"
[strictAcceptValidation]="strictAcceptValidation"
>
<nx-label size="small">Required file to upload</nx-label>
Expand Down Expand Up @@ -703,7 +715,7 @@ class ReactiveFileUpload extends FileUploaderTest {
maxFileSize: any;
queueList: any;
maxFileNumber: any;
disableCommonValidator = false;
noBlockingValidators = false;

constructor() {
super();
Expand Down
22 changes: 19 additions & 3 deletions projects/ng-aquila/src/file-uploader/file-uploader.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import {
ViewChild,
ViewChildren,
} from '@angular/core';
import { ControlValueAccessor, FormControl, FormGroupDirective, NgControl, NgForm, ValidatorFn } from '@angular/forms';
import { NxErrorComponent, NxLabelComponent } from '@aposin/ng-aquila/base';
import { AbstractControl, ControlValueAccessor, FormControl, FormGroupDirective, NgControl, NgForm, ValidationErrors, ValidatorFn } from '@angular/forms';
import { ERROR_DEFAULT_OPTIONS, NxErrorComponent, NxLabelComponent } from '@aposin/ng-aquila/base';
import { ErrorStateMatcher } from '@aposin/ng-aquila/utils';
import { fromEvent, Observable, Subject, Subscription } from 'rxjs';
import { filter, map, startWith, take, takeUntil } from 'rxjs/operators';
Expand Down Expand Up @@ -57,6 +57,14 @@ let nextId = 0;
'[attr.aria-invalid]': 'errorState',
'[class.has-error]': 'errorState',
},
providers: [
{
provide: ERROR_DEFAULT_OPTIONS,
useValue: {
appearance: 'message',
},
},
],
})
export class NxFileUploaderComponent implements ControlValueAccessor, AfterContentInit, OnChanges, OnDestroy, DoCheck, OnInit, AfterViewInit {
/** @docs-private */
Expand Down Expand Up @@ -404,6 +412,7 @@ export class NxFileUploaderComponent implements ControlValueAccessor, AfterConte
const reachMaxFileNumber = this.maxFileNumber && (this.value?.length || 0) === this.maxFileNumber;
if (reachMaxFileNumber) {
this.setMaxFileNumberError(this.maxFileNumber);
this._resetValidators(true);
return;
}
this.nativeInputFile.nativeElement.click();
Expand Down Expand Up @@ -645,7 +654,9 @@ export class NxFileUploaderComponent implements ControlValueAccessor, AfterConte
actual: totalFilesNum,
});
if (!this.noBlockingValidators && this.ngControl?.control) {
this.validatorFnArray.push(NxFileUploaderValidators.maxFileNumber(totalFilesNum, this.maxFileNumber));
this.validatorFnArray.push((control: AbstractControl): ValidationErrors | null => ({
NxFileUploadMaxFileNumber: { max: this.maxFileNumber, actual: totalFilesNum },
}));
}
}

Expand Down Expand Up @@ -680,4 +691,9 @@ export class NxFileUploaderComponent implements ControlValueAccessor, AfterConte
reason,
});
}

/** weather all files is uplaoded */
get allFilesUploaded(): boolean {
return this.value?.every(f => f.isUploaded) || false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,25 @@
:host {
@include type-style(file-uploader-file-name);
}
.extension {
position: relative;
top: 4px;
display: inline-flex;
}
.extension-icon {
font-size: 22px;
}
.extension-label {
position: absolute;
text-transform: uppercase;
-webkit-user-select: none;
user-select: none;
line-height: normal;
font-weight: bold;
padding: 1px 3px;
right: 4px;
bottom: 4px;
border-radius: 2px 0 0 2px;
font-size: 6px;
color: white;
}
Loading

0 comments on commit c4c592e

Please sign in to comment.