From f96c35649b2b0c31a0ae042e1167d45a75bb227e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Mon, 18 Jan 2021 22:20:58 +0200 Subject: [PATCH] Group files by project in upload overlay --- .../project-details.component.scss | 4 + .../project-overview-screen.component.ts | 4 +- .../file-drop/file-drop.component.ts | 2 +- .../upload-download/file-upload.service.ts | 28 +++++++ .../model/file-upload.model.ts | 1 + .../upload-status-overlay.component.html | 77 ++++++++++--------- .../upload-status-overlay.component.scss | 14 ++++ .../upload-status-overlay.component.ts | 2 +- apps/red-ui/src/app/utils/file-drop-utils.ts | 12 +-- .../src/app/utils/has-scrollbar.directive.ts | 3 +- 10 files changed, 102 insertions(+), 45 deletions(-) diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss index b8e66b45a..cb4f0bd9e 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss @@ -5,6 +5,10 @@ flex-direction: row; position: relative; + .heading-xl { + max-width: 88%; + } + redaction-circle-button { position: absolute; top: -5px; diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts index c8554c986..7d3f65853 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts @@ -225,7 +225,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { @HostListener('drop', ['$event']) onDrop(event: DragEvent) { - handleFileDrop(event, this.appStateService.activeProjectId, this._uploadFiles.bind(this)); + handleFileDrop(event, this.appStateService.activeProject, this._uploadFiles.bind(this)); } @HostListener('dragover', ['$event']) @@ -235,7 +235,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { } async uploadFiles(files: File[] | FileList) { - await this._uploadFiles(convertFiles(files, this.appStateService.activeProjectId)); + await this._uploadFiles(convertFiles(files, this.appStateService.activeProject)); } private async _uploadFiles(files: FileUploadModel[]) { diff --git a/apps/red-ui/src/app/upload-download/file-drop/file-drop.component.ts b/apps/red-ui/src/app/upload-download/file-drop/file-drop.component.ts index fc2fa014e..af1ef5946 100644 --- a/apps/red-ui/src/app/upload-download/file-drop/file-drop.component.ts +++ b/apps/red-ui/src/app/upload-download/file-drop/file-drop.component.ts @@ -35,7 +35,7 @@ export class FileDropComponent implements OnInit { @HostListener('drop', ['$event']) onDrop(event: DragEvent) { - handleFileDrop(event, this._appStateService.activeProjectId, this.uploadFiles.bind(this)); + handleFileDrop(event, this._appStateService.activeProject, this.uploadFiles.bind(this)); } @HostListener('dragover', ['$event']) diff --git a/apps/red-ui/src/app/upload-download/file-upload.service.ts b/apps/red-ui/src/app/upload-download/file-upload.service.ts index 60b9bb18d..bf628c6aa 100644 --- a/apps/red-ui/src/app/upload-download/file-upload.service.ts +++ b/apps/red-ui/src/app/upload-download/file-upload.service.ts @@ -14,6 +14,7 @@ import { DialogService } from '../dialogs/dialog.service'; export class FileUploadService { static readonly MAX_PARALLEL_UPLOADS = 5; files: FileUploadModel[] = []; + groupedFiles: { [key: string]: FileUploadModel[] } = {}; activeUploads = 0; private _pendingUploads: FileUploadModel[] = []; @@ -73,13 +74,39 @@ export class FileUploadService { } this.files.push(...files); files.forEach((newFile) => { + this._addFileToGroup(newFile); this.scheduleUpload(newFile); }); return files.length; } + private _addFileToGroup(file: FileUploadModel) { + if (!this.groupedFiles[file.projectId]) { + this.groupedFiles[file.projectId] = []; + } + this.groupedFiles[file.projectId].push(file); + } + + public filterFiles() { + for (const file of this.files) { + if (file.completed && !file.error) { + this.removeFile(file); + } + } + } + + private _removeFileFromGroup(file: FileUploadModel) { + const index = this.groupedFiles[file.projectId].indexOf(file); + this.groupedFiles[file.projectId].splice(index, 1); + } + + public get activeProjectKeys() { + return Object.keys(this.groupedFiles).filter((projectId) => this.groupedFiles[projectId].length > 0); + } + stopAllUploads() { this.files = []; + this.groupedFiles = {}; } private _handleUploads() { @@ -143,6 +170,7 @@ export class FileUploadService { removeFile(item: FileUploadModel) { const index = this.files.indexOf(item); if (index > -1) { + this._removeFileFromGroup(item); this.files.splice(index, 1); } } diff --git a/apps/red-ui/src/app/upload-download/model/file-upload.model.ts b/apps/red-ui/src/app/upload-download/model/file-upload.model.ts index 750f92b02..bdf33a0f9 100644 --- a/apps/red-ui/src/app/upload-download/model/file-upload.model.ts +++ b/apps/red-ui/src/app/upload-download/model/file-upload.model.ts @@ -7,4 +7,5 @@ export interface FileUploadModel { size: number; sizeError: any; projectId?: string; + projectName?: string; } diff --git a/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.html b/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.html index f0975a2fd..ac06bfc03 100644 --- a/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.html +++ b/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.html @@ -15,46 +15,53 @@
-
-
-
- {{ model.file?.name }} -
-
{{ model.progress }}%
-
- -
-
- -
+
+
+ {{ uploadService.groupedFiles[projectId][0].projectName }} ({{ + uploadService.groupedFiles[projectId].length + }})
-
-
- {{ model.error.message }} +
+
+
+ {{ model.file?.name }} +
+
{{ model.progress }}%
+
+ +
+
+ +
+
+
+ {{ model.error.message }} +
-
-
- -
-
- +
+
+ +
+
+ +
-
-
- +
+ +
diff --git a/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.scss b/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.scss index 3f1862cb0..f5d3da988 100644 --- a/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.scss +++ b/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.scss @@ -1,3 +1,17 @@ +@import '../../../assets/styles/red-variables'; +@import '../../../assets/styles/red-mixins'; + .red-upload-download-overlay { right: 10px; } + +.project-name-wrapper { + display: flex; + padding: 8px 20px 8px 8px; + background-color: $grey-4; + font-weight: 600; + + .project-name { + @include line-clamp(1); + } +} diff --git a/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.ts b/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.ts index 93377c748..eb3b7bc15 100644 --- a/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.ts +++ b/apps/red-ui/src/app/upload-download/upload-status-overlay/upload-status-overlay.component.ts @@ -22,7 +22,7 @@ export class UploadStatusOverlay implements OnInit { ngOnInit() { this.uploadStatusInterval = setInterval(() => { // keep only errors - this.uploadService.files = this.uploadService.files.filter((file) => !file.completed || file.error); + this.uploadService.filterFiles(); if (this.uploadService.files.length === 0) { this.closeDialog(); } diff --git a/apps/red-ui/src/app/utils/file-drop-utils.ts b/apps/red-ui/src/app/utils/file-drop-utils.ts index 4bbb28fbe..1ca3e28b8 100644 --- a/apps/red-ui/src/app/utils/file-drop-utils.ts +++ b/apps/red-ui/src/app/utils/file-drop-utils.ts @@ -1,6 +1,7 @@ import { FileUploadModel } from '../upload-download/model/file-upload.model'; +import { ProjectWrapper } from '../state/model/project.wrapper'; -export function handleFileDrop(event: DragEvent, projectId: string, uploadFiles: (files: FileUploadModel[]) => void) { +export function handleFileDrop(event: DragEvent, project: ProjectWrapper, uploadFiles: (files: FileUploadModel[]) => void) { event.preventDefault(); event.stopPropagation(); const { dataTransfer } = event; @@ -16,16 +17,16 @@ export function handleFileDrop(event: DragEvent, projectId: string, uploadFiles: } else { files = dataTransfer.files; dataTransfer.clearData(); - uploadFiles(convertFiles(files, projectId)); + uploadFiles(convertFiles(files, project)); } - const convertedFiles = convertFiles(files, projectId); + const convertedFiles = convertFiles(files, project); if (convertedFiles.length > 0) { uploadFiles(convertedFiles); } } -export function convertFiles(files: FileList | File[], projectId: string): FileUploadModel[] { +export function convertFiles(files: FileList | File[], project: ProjectWrapper): FileUploadModel[] { let uploadFiles: FileUploadModel[] = []; for (let i = 0; i < files.length; i++) { const file = files[i]; @@ -34,7 +35,8 @@ export function convertFiles(files: FileList | File[], projectId: string): FileU progress: 0, completed: false, error: null, - projectId: projectId, + projectId: project.projectId, + projectName: project.projectName, sizeError: false, retryCount: 0, size: file.size diff --git a/apps/red-ui/src/app/utils/has-scrollbar.directive.ts b/apps/red-ui/src/app/utils/has-scrollbar.directive.ts index 27a0174e3..0d439fba3 100644 --- a/apps/red-ui/src/app/utils/has-scrollbar.directive.ts +++ b/apps/red-ui/src/app/utils/has-scrollbar.directive.ts @@ -1,4 +1,4 @@ -import { AfterContentChecked, AfterContentInit, AfterViewChecked, Directive, ElementRef, HostBinding } from '@angular/core'; +import { AfterContentChecked, Directive, ElementRef, HostBinding } from '@angular/core'; @Directive({ selector: '[redactionHasScrollbar]', @@ -8,6 +8,7 @@ export class HasScrollbarDirective implements AfterContentChecked { constructor(private el: ElementRef) {} @HostBinding('class') class = ''; + ngAfterContentChecked() { this.class = this.hasScrollbar ? 'has-scrollbar' : ''; }