ACS-7407: upload as standalone

This commit is contained in:
Denys Vuika
2024-07-25 13:18:18 -04:00
parent ebe458cc19
commit f85957c892
15 changed files with 165 additions and 159 deletions

View File

@@ -22,7 +22,6 @@ import { CoreModule, SearchTextModule, provideTranslations } from '@alfresco/adf
import { MaterialModule } from './material.module';
import { TagModule } from './tag/tag.module';
import { DocumentListModule } from './document-list/document-list.module';
import { UploadModule } from './upload/upload.module';
import { SearchModule } from './search/search.module';
import { BREADCRUMB_DIRECTIVES } from './breadcrumb/breadcrumb.module';
import { CONTENT_VERSION_DIRECTIVES } from './version-manager/version-manager.module';
@@ -47,6 +46,7 @@ import { CategoriesManagementComponent } from './category';
import { TreeComponent } from './tree';
import { NewVersionUploaderDialogComponent } from './new-version-uploader';
import { VersionCompatibilityDirective } from './version-compatibility';
import { CONTENT_UPLOAD_DIRECTIVES } from './upload';
@NgModule({
imports: [
@@ -59,7 +59,7 @@ import { VersionCompatibilityDirective } from './version-compatibility';
...CONTENT_DIALOG_DIRECTIVES,
SearchModule,
DocumentListModule,
UploadModule,
...CONTENT_UPLOAD_DIRECTIVES,
MaterialModule,
DropdownSitesComponent,
...BREADCRUMB_DIRECTIVES,
@@ -85,7 +85,7 @@ import { VersionCompatibilityDirective } from './version-compatibility';
...CONTENT_PIPES,
TagModule,
DocumentListModule,
UploadModule,
...CONTENT_UPLOAD_DIRECTIVES,
SearchModule,
DropdownSitesComponent,
...BREADCRUMB_DIRECTIVES,

View File

@@ -19,7 +19,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { mockFile, mockNode } from '../mock';
import { ContentTestingModule } from '../testing/content.testing.module';
import { UploadVersionButtonComponent } from '../upload';
import { NewVersionUploaderDataAction } from './models';
import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog';
@@ -44,7 +43,6 @@ describe('NewVersionUploaderDialog', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ContentTestingModule, NewVersionUploaderDialogComponent],
declarations: [UploadVersionButtonComponent],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: { node: mockNode, showVersionsOnly, file: mockFile } },
{

View File

@@ -16,7 +16,19 @@
*/
import { UserPreferencesService } from '@alfresco/adf-core';
import { ChangeDetectorRef, Component, Input, Output, EventEmitter, OnDestroy, OnInit, ViewChild, HostBinding, ElementRef, ViewEncapsulation } from '@angular/core';
import {
ChangeDetectorRef,
Component,
Input,
Output,
EventEmitter,
OnDestroy,
OnInit,
ViewChild,
HostBinding,
ElementRef,
ViewEncapsulation
} from '@angular/core';
import { Subscription, merge, Subject } from 'rxjs';
import { FileUploadingListComponent } from './file-uploading-list.component';
import { Direction } from '@angular/cdk/bidi';
@@ -24,9 +36,17 @@ import { takeUntil, delay } from 'rxjs/operators';
import { UploadService } from '../../common/services/upload.service';
import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import { FileUploadDeleteEvent, FileUploadCompleteEvent } from '../../common/events/file.event';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { FileUploadingListRowComponent } from './file-uploading-list-row.component';
import { A11yModule } from '@angular/cdk/a11y';
@Component({
selector: 'adf-file-uploading-dialog',
standalone: true,
imports: [CommonModule, MatButtonModule, TranslateModule, MatIconModule, FileUploadingListComponent, FileUploadingListRowComponent, A11yModule],
templateUrl: './file-uploading-dialog.component.html',
styleUrls: ['./file-uploading-dialog.component.scss'],
encapsulation: ViewEncapsulation.None
@@ -53,15 +73,11 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
@HostBinding('attr.adfUploadDialogRight')
public get isPositionRight(): boolean {
return (this.direction === 'ltr' && this.position === 'right')
|| (this.direction === 'rtl' && this.position === 'left')
|| null;
return (this.direction === 'ltr' && this.position === 'right') || (this.direction === 'rtl' && this.position === 'left') || null;
}
@HostBinding('attr.adfUploadDialogLeft')
public get isPositionLeft(): boolean {
return (this.direction === 'ltr' && this.position === 'left')
|| (this.direction === 'rtl' && this.position === 'right')
|| null;
return (this.direction === 'ltr' && this.position === 'left') || (this.direction === 'rtl' && this.position === 'right') || null;
}
filesUploadingList: FileModel[] = [];
@@ -81,25 +97,18 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
private uploadService: UploadService,
private changeDetector: ChangeDetectorRef,
private userPreferencesService: UserPreferencesService,
private elementRef: ElementRef) {
}
private elementRef: ElementRef
) {}
ngOnInit() {
this.dialogActive
.pipe(
delay(100),
takeUntil(this.onDestroy$)
)
.subscribe(() => {
this.dialogActive.pipe(delay(100), takeUntil(this.onDestroy$)).subscribe(() => {
const element: any = this.elementRef.nativeElement.querySelector('#upload-dialog');
if (element) {
element.focus();
}
});
this.listSubscription = this.uploadService.queueChanged
.pipe(takeUntil(this.onDestroy$))
.subscribe(fileList => {
this.listSubscription = this.uploadService.queueChanged.pipe(takeUntil(this.onDestroy$)).subscribe((fileList) => {
this.filesUploadingList = fileList;
if (this.filesUploadingList.length && !this.isDialogActive) {
@@ -110,34 +119,25 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
}
});
this.counterSubscription = merge(
this.uploadService.fileUploadComplete,
this.uploadService.fileUploadDeleted
)
this.counterSubscription = merge(this.uploadService.fileUploadComplete, this.uploadService.fileUploadDeleted)
.pipe(takeUntil(this.onDestroy$))
.subscribe((event: FileUploadCompleteEvent | FileUploadDeleteEvent) => {
this.totalCompleted = event.totalComplete;
this.changeDetector.detectChanges();
});
this.errorSubscription = this.uploadService.fileUploadError
.pipe(takeUntil(this.onDestroy$))
.subscribe(event => {
this.errorSubscription = this.uploadService.fileUploadError.pipe(takeUntil(this.onDestroy$)).subscribe((event) => {
this.totalErrors = event.totalError;
this.changeDetector.detectChanges();
});
this.fileUploadSubscription = this.uploadService.fileUpload
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
this.fileUploadSubscription = this.uploadService.fileUpload.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
this.changeDetector.detectChanges();
});
this.uploadService.fileDeleted
.pipe(takeUntil(this.onDestroy$))
.subscribe(objId => {
this.uploadService.fileDeleted.pipe(takeUntil(this.onDestroy$)).subscribe((objId) => {
if (this.filesUploadingList) {
const uploadedFile = this.filesUploadingList.find((file) => file.data ? file.data.entry.id === objId : false);
const uploadedFile = this.filesUploadingList.find((file) => (file.data ? file.data.entry.id === objId : false));
if (uploadedFile) {
uploadedFile.status = FileUploadStatus.Cancelled;
this.changeDetector.detectChanges();
@@ -145,7 +145,8 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
}
});
this.userPreferencesService.select('textOrientation')
this.userPreferencesService
.select('textOrientation')
.pipe(takeUntil(this.onDestroy$))
.subscribe((textOrientation: Direction) => {
this.direction = textOrientation;
@@ -221,6 +222,6 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
}
hasUploadInProgress(): boolean {
return (!this.uploadList?.isUploadCompleted() && !this.uploadList?.isUploadCancelled());
return !this.uploadList?.isUploadCompleted() && !this.uploadList?.isUploadCancelled();
}
}

View File

@@ -14,7 +14,7 @@
<span *ngIf="isUploadVersion()" class="adf-file-uploading-row__version" tabindex="0" >
<mat-chip-option color="primary"
[attr.aria-label]="'ADF_FILE_UPLOAD.ARIA-LABEL.VERSION' | translate: { version: versionNumber }"
[title]="'version' + versionNumber" disabled
[title]="'version' + versionNumber" [disabled]="true"
>{{ versionNumber }}</mat-chip-option>
</span>

View File

@@ -17,9 +17,31 @@
import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { FileSizePipe, IconComponent } from '@alfresco/adf-core';
import { MatChipsModule } from '@angular/material/chips';
import { TranslateModule } from '@ngx-translate/core';
import { ToggleIconDirective } from '../directives/toggle-icon.directive';
import { MatButtonModule } from '@angular/material/button';
import { FileUploadErrorPipe } from '../pipes/file-upload-error.pipe';
@Component({
selector: 'adf-file-uploading-list-row',
standalone: true,
imports: [
CommonModule,
MatIconModule,
MatListModule,
IconComponent,
MatChipsModule,
TranslateModule,
ToggleIconDirective,
FileSizePipe,
MatButtonModule,
FileUploadErrorPipe
],
templateUrl: './file-uploading-list-row.component.html',
styleUrls: ['./file-uploading-list-row.component.scss'],
encapsulation: ViewEncapsulation.None

View File

@@ -15,23 +15,17 @@
* limitations under the License.
*/
import {
TranslationService
} from '@alfresco/adf-core';
import { TranslationService } from '@alfresco/adf-core';
import { UploadService } from '../../common/services/upload.service';
import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import {
Component,
ContentChild,
Input,
Output,
TemplateRef,
EventEmitter
} from '@angular/core';
import { Component, ContentChild, Input, Output, TemplateRef, EventEmitter } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'adf-file-uploading-list',
standalone: true,
imports: [CommonModule],
templateUrl: './file-uploading-list.component.html',
styleUrls: ['./file-uploading-list.component.scss']
})
@@ -46,10 +40,7 @@ export class FileUploadingListComponent {
@Output()
error = new EventEmitter<any>();
constructor(
private uploadService: UploadService,
private translateService: TranslationService) {
}
constructor(private uploadService: UploadService, private translateService: TranslationService) {}
/**
* Cancel file upload
@@ -79,14 +70,14 @@ export class FileUploadingListComponent {
this.uploadService.cancelUpload(file);
}
this.files = this.files.filter(entry => entry !== file);
this.files = this.files.filter((entry) => entry !== file);
}
/**
* Calls the appropriate methods for each file, depending on state
*/
cancelAllFiles(): void {
const filesToCancel = this.files.filter(file => this.isUploadingFile(file));
const filesToCancel = this.files.filter((file) => this.isUploadingFile(file));
if (filesToCancel.length > 0) {
this.uploadService.cancelUpload(...filesToCancel);
@@ -103,10 +94,7 @@ export class FileUploadingListComponent {
!this.isUploadCancelled() &&
Boolean(this.files.length) &&
!this.files.some(
({ status }) =>
status === FileUploadStatus.Starting ||
status === FileUploadStatus.Progress ||
status === FileUploadStatus.Pending
({ status }) => status === FileUploadStatus.Starting || status === FileUploadStatus.Progress || status === FileUploadStatus.Pending
)
);
}
@@ -120,22 +108,14 @@ export class FileUploadingListComponent {
return (
!!this.files.length &&
this.files.every(
({ status }) =>
status === FileUploadStatus.Aborted ||
status === FileUploadStatus.Cancelled ||
status === FileUploadStatus.Deleted
({ status }) => status === FileUploadStatus.Aborted || status === FileUploadStatus.Cancelled || status === FileUploadStatus.Deleted
)
);
}
private cancelNodeVersionInstances(file: FileModel) {
this.files
.filter(
(item) =>
item.options.newVersion &&
item.data.entry.id === file.data.entry.id
)
.filter((item) => item.options.newVersion && item.data.entry.id === file.data.entry.id)
.map((item) => {
item.status = FileUploadStatus.Deleted;
});
@@ -145,23 +125,15 @@ export class FileUploadingListComponent {
let messageError: string = null;
if (files.length === 1) {
messageError = this.translateService.instant(
'FILE_UPLOAD.MESSAGES.REMOVE_FILE_ERROR',
{ fileName: files[0].name }
);
messageError = this.translateService.instant('FILE_UPLOAD.MESSAGES.REMOVE_FILE_ERROR', { fileName: files[0].name });
} else {
messageError = this.translateService.instant(
'FILE_UPLOAD.MESSAGES.REMOVE_FILES_ERROR',
{ total: files.length }
);
messageError = this.translateService.instant('FILE_UPLOAD.MESSAGES.REMOVE_FILES_ERROR', { total: files.length });
}
this.error.emit(messageError);
}
private isUploadingFile(file: FileModel): boolean {
return file.status === FileUploadStatus.Pending ||
file.status === FileUploadStatus.Starting ||
file.status === FileUploadStatus.Progress;
return file.status === FileUploadStatus.Pending || file.status === FileUploadStatus.Starting || file.status === FileUploadStatus.Progress;
}
}

View File

@@ -25,9 +25,15 @@ import { Subject } from 'rxjs';
import { PermissionModel } from '../../document-list/models/permissions.model';
import { UploadBase } from './base-upload/upload-base';
import { NodeAllowableOperationSubject } from '../../interfaces/node-allowable-operation-subject.interface';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
@Component({
selector: 'adf-upload-button',
standalone: true,
imports: [CommonModule, MatButtonModule, TranslateModule, MatIconModule],
templateUrl: './upload-button.component.html',
styleUrls: ['./upload-button.component.scss'],
viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadButtonComponent) }],

View File

@@ -23,9 +23,12 @@ import { AllowableOperationsEnum } from '../../common/models/allowable-operation
import { ContentService } from '../../common/services/content.service';
import { FileModel } from '../../common/models/file.model';
import { Node } from '@alfresco/js-api';
import { FileDraggableDirective } from '../directives/file-draggable.directive';
@Component({
selector: 'adf-upload-drag-area',
standalone: true,
imports: [FileDraggableDirective],
templateUrl: './upload-drag-area.component.html',
styleUrls: ['./upload-drag-area.component.scss'],
host: { class: 'adf-upload-drag-area' },

View File

@@ -21,25 +21,33 @@ import { Node } from '@alfresco/js-api';
import { UploadButtonComponent } from './upload-button.component';
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
import { FileModel } from '../../common/models/file.model';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
@Component({
selector: 'adf-upload-version-button',
standalone: true,
imports: [CommonModule, MatButtonModule, TranslateModule, MatIconModule],
templateUrl: './upload-button.component.html',
styleUrls: ['./upload-button.component.scss'],
viewProviders: [
{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadVersionButtonComponent) }
],
viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadVersionButtonComponent) }],
encapsulation: ViewEncapsulation.None,
host: { class: 'adf-upload-version-button' }
})
export class UploadVersionButtonComponent extends UploadButtonComponent implements OnChanges, OnInit {
/** (**Required**) The node to be versioned. */
@Input()
node: Node;
protected createFileModel(file: File): FileModel {
const fileModel = super.createFileModel(file, this.rootFolderId, ((file as any).webkitRelativePath || '').replace(/\/[^/]*$/, ''), this.node.id);
const fileModel = super.createFileModel(
file,
this.rootFolderId,
((file as any).webkitRelativePath || '').replace(/\/[^/]*$/, ''),
this.node.id
);
if (!this.isFileAcceptable(fileModel)) {
const message = this.translationService.instant('FILE_UPLOAD.VERSION.MESSAGES.INCOMPATIBLE_VERSION');

View File

@@ -21,6 +21,8 @@ import { FileDraggableDirective, INPUT_FOCUS_CSS_CLASS } from '../directives/fil
@Component({
selector: 'adf-test-component',
standalone: true,
imports: [FileDraggableDirective],
template: `
<div id="test-container" [adf-file-draggable]="true">
<div id="test-content"></div>
@@ -42,10 +44,7 @@ describe('FileDraggableDirective', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
TestComponent,
FileDraggableDirective
]
imports: [TestComponent]
});
fixture = TestBed.createComponent(TestComponent);
@@ -61,7 +60,8 @@ describe('FileDraggableDirective', () => {
fixture.destroy();
});
const createEvent = (eventName: string): DragEvent => new DragEvent(eventName, {
const createEvent = (eventName: string): DragEvent =>
new DragEvent(eventName, {
bubbles: true,
cancelable: true,
dataTransfer: new DataTransfer()

View File

@@ -24,10 +24,10 @@ export const INPUT_FOCUS_CSS_CLASS = 'adf-file-draggable-input-focus';
export const DROP_EFFECT = 'copy';
@Directive({
selector: '[adf-file-draggable]'
selector: '[adf-file-draggable]',
standalone: true
})
export class FileDraggableDirective implements OnInit, OnDestroy {
files: File[];
/** Enables/disables drag-and-drop functionality. */

View File

@@ -21,9 +21,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
@Component({
selector: 'adf-test-component',
template: `
<button id="testButton" adf-toggle-icon>test</button>
`
standalone: true,
imports: [ToggleIconDirective],
template: ` <button id="testButton" adf-toggle-icon>test</button> `
})
class TestComponent {
@ViewChild(ToggleIconDirective)
@@ -36,10 +36,7 @@ describe('ToggleIconDirective', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
TestComponent,
ToggleIconDirective
]
imports: [TestComponent]
});
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;

View File

@@ -19,6 +19,7 @@ import { Directive, HostListener } from '@angular/core';
@Directive({
selector: '[adf-toggle-icon]',
standalone: true,
exportAs: 'toggleIcon'
})
export class ToggleIconDirective {

View File

@@ -15,9 +15,7 @@
* limitations under the License.
*/
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MaterialModule } from '../material.module';
import { FileUploadingDialogComponent } from './components/file-uploading-dialog.component';
import { FileUploadingListRowComponent } from './components/file-uploading-list-row.component';
import { FileUploadingListComponent } from './components/file-uploading-list.component';
@@ -25,33 +23,24 @@ import { UploadButtonComponent } from './components/upload-button.component';
import { UploadVersionButtonComponent } from './components/upload-version-button.component';
import { UploadDragAreaComponent } from './components/upload-drag-area.component';
import { FileUploadErrorPipe } from './pipes/file-upload-error.pipe';
import { CoreModule, FileSizePipe } from '@alfresco/adf-core';
import { FileDraggableDirective } from './directives/file-draggable.directive';
import { ToggleIconDirective } from './directives/toggle-icon.directive';
import { A11yModule } from '@angular/cdk/a11y';
@NgModule({
imports: [CoreModule, CommonModule, MaterialModule, A11yModule, FileUploadErrorPipe, FileSizePipe],
declarations: [
FileDraggableDirective,
UploadDragAreaComponent,
UploadButtonComponent,
UploadVersionButtonComponent,
FileUploadingDialogComponent,
FileUploadingListComponent,
FileUploadingListRowComponent,
ToggleIconDirective
],
exports: [
FileDraggableDirective,
UploadDragAreaComponent,
UploadButtonComponent,
UploadVersionButtonComponent,
FileUploadingDialogComponent,
FileUploadingListComponent,
FileUploadingListRowComponent,
export const CONTENT_UPLOAD_DIRECTIVES = [
FileUploadErrorPipe,
ToggleIconDirective
]
FileDraggableDirective,
ToggleIconDirective,
UploadDragAreaComponent,
UploadButtonComponent,
UploadVersionButtonComponent,
FileUploadingListRowComponent,
FileUploadingListComponent,
FileUploadingDialogComponent
] as const;
/** @deprecated use `...CONTENT_UPLOAD_DIRECTIVES` instead or import standalone components directly */
@NgModule({
imports: [...CONTENT_UPLOAD_DIRECTIVES],
exports: [...CONTENT_UPLOAD_DIRECTIVES]
})
export class UploadModule {}

View File

@@ -28,13 +28,22 @@ import { FormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { UploadModule } from '../upload';
import { MatButtonModule } from '@angular/material/button';
import { UploadVersionButtonComponent } from '../upload';
@Component({
selector: 'adf-version-upload',
standalone: true,
imports: [CommonModule, MatRadioModule, FormsModule, TranslateModule, MatFormFieldModule, MatInputModule, UploadModule, MatButtonModule],
imports: [
CommonModule,
MatRadioModule,
FormsModule,
TranslateModule,
MatFormFieldModule,
MatInputModule,
MatButtonModule,
UploadVersionButtonComponent
],
templateUrl: './version-upload.component.html',
styleUrls: ['./version-upload.component.scss'],
encapsulation: ViewEncapsulation.None,