From 64f2d861f2e9c0f14a315673173f604af8122e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Fri, 8 Jan 2021 23:03:30 +0200 Subject: [PATCH 1/3] Fixed sync width directive --- .../table-col-name.component.scss | 1 + .../src/app/utils/sync-width.directive.ts | 27 ++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/apps/red-ui/src/app/components/table-col-name/table-col-name.component.scss b/apps/red-ui/src/app/components/table-col-name/table-col-name.component.scss index 425f255c3..2db26872e 100644 --- a/apps/red-ui/src/app/components/table-col-name/table-col-name.component.scss +++ b/apps/red-ui/src/app/components/table-col-name/table-col-name.component.scss @@ -3,6 +3,7 @@ :host { display: flex; height: 30px; + flex: 1; > div { align-items: center; diff --git a/apps/red-ui/src/app/utils/sync-width.directive.ts b/apps/red-ui/src/app/utils/sync-width.directive.ts index 1f389a8c6..1c7dae6c2 100644 --- a/apps/red-ui/src/app/utils/sync-width.directive.ts +++ b/apps/red-ui/src/app/utils/sync-width.directive.ts @@ -15,6 +15,22 @@ export class SyncWidthDirective implements AfterViewChecked { this.matchWidth(); } + private get _sampleRow(): { tableRow: Element; length: number } { + const tableRows = document.getElementsByClassName(this.redactionSyncWidth); + let length = 0; + let tableRow: Element; + + for (let idx = 0; idx < tableRows.length; ++idx) { + const row = tableRows.item(idx); + if (row.children.length > length) { + length = row.children.length; + tableRow = row; + } + } + + return { tableRow, length }; + } + @debounce(0) matchWidth() { const headerItems = this.el.nativeElement.children; @@ -22,13 +38,18 @@ export class SyncWidthDirective implements AfterViewChecked { if (!tableRows || !tableRows.length) return; - const tableRow = tableRows[0]; - if (tableRow.children.length !== headerItems.length) return; + const { tableRow, length } = this._sampleRow; - for (let idx = 0; idx < headerItems.length - 1; ++idx) { + const hasExtraColumns = headerItems.length !== length ? 1 : 0; + + for (let idx = 0; idx < length - hasExtraColumns - 1; ++idx) { headerItems[idx].style.width = `${tableRow.children[idx].getBoundingClientRect().width}px`; headerItems[idx].style.minWidth = `${tableRow.children[idx].getBoundingClientRect().width}px`; } + + for (let idx = length - hasExtraColumns - 1; idx < headerItems.length; ++idx) { + headerItems[idx].style.minWidth = `0`; + } } @HostListener('window:resize') From 0ed0c70bf4da8db2e705b6c701b7a823230b4276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Sat, 9 Jan 2021 02:43:54 +0200 Subject: [PATCH 2/3] Show a dialog if a file already exists --- apps/red-ui/src/app/app.module.ts | 2 ++ apps/red-ui/src/app/dialogs/dialog.service.ts | 15 +++++++++ .../overwrite-files-dialog.component.html | 17 ++++++++++ .../overwrite-files-dialog.component.scss | 7 +++++ .../overwrite-files-dialog.component.ts | 28 +++++++++++++++++ .../project-overview-screen.component.ts | 12 ++++--- .../upload/file-drop/file-drop.component.ts | 8 +++-- .../src/app/upload/file-upload.service.ts | 31 ++++++++++++++++--- apps/red-ui/src/assets/i18n/en.json | 12 ++++++- 9 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.html create mode 100644 apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.scss create mode 100644 apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.ts diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index b07e4ce16..5a8d2ae4e 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -104,6 +104,7 @@ import { RuleSetActionsComponent } from './components/rule-set-actions/rule-set- import { RuleSetViewSwitchComponent } from './components/rule-set-view-switch/rule-set-view-switch.component'; import { MatSliderModule } from '@angular/material/slider'; import { PendingChangesGuard } from './utils/can-deactivate.guard'; +import { OverwriteFilesDialogComponent } from './dialogs/overwrite-files-dialog/overwrite-files-dialog.component'; export function HttpLoaderFactory(httpClient: HttpClient) { return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json'); @@ -276,6 +277,7 @@ const matImports = [ ProjectOverviewScreenComponent, AddEditProjectDialogComponent, ConfirmationDialogComponent, + OverwriteFilesDialogComponent, FilePreviewScreenComponent, PdfViewerComponent, AssignOwnerDialogComponent, diff --git a/apps/red-ui/src/app/dialogs/dialog.service.ts b/apps/red-ui/src/app/dialogs/dialog.service.ts index 6c39092b4..edf13c942 100644 --- a/apps/red-ui/src/app/dialogs/dialog.service.ts +++ b/apps/red-ui/src/app/dialogs/dialog.service.ts @@ -22,6 +22,7 @@ import { ManualAnnotationService } from '../screens/file/service/manual-annotati import { ProjectWrapper } from '../state/model/project.wrapper'; import { AddEditDictionaryDialogComponent } from '../screens/admin/dictionary-listing-screen/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component'; import { AddEditRuleSetDialogComponent } from '../screens/admin/rule-sets-listing-screen/add-edit-rule-set-dialog/add-edit-rule-set-dialog.component'; +import { OverwriteFilesDialogComponent } from './overwrite-files-dialog/overwrite-files-dialog.component'; const dialogConfig = { width: '662px', @@ -331,4 +332,18 @@ export class DialogService { return ref; } + + openOverwriteFileDialog(filename: string): Promise<{ option?: 'overwrite' | 'no-overwrite'; remember?: boolean; cancel?: boolean }> { + const ref = this._dialog.open(OverwriteFilesDialogComponent, { + ...dialogConfig, + data: filename + }); + + return ref + .afterClosed() + .toPromise() + .then((res) => { + return res || { cancel: true }; + }); + } } diff --git a/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.html b/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.html new file mode 100644 index 000000000..962a5daa9 --- /dev/null +++ b/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.html @@ -0,0 +1,17 @@ +
+
+ +
+

+ + + {{ 'overwrite-files-dialog.options.remember' | translate }} + +
+ +
+
+
+
+
+
diff --git a/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.scss b/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.scss new file mode 100644 index 000000000..d2bca127f --- /dev/null +++ b/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.scss @@ -0,0 +1,7 @@ +mat-checkbox { + margin-top: 16px; +} + +.dialog-actions > div:not(:last-child) { + margin-right: 32px; +} diff --git a/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.ts b/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.ts new file mode 100644 index 000000000..0f0d93a51 --- /dev/null +++ b/apps/red-ui/src/app/dialogs/overwrite-files-dialog/overwrite-files-dialog.component.ts @@ -0,0 +1,28 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'redaction-overwrite-files-dialog', + templateUrl: './overwrite-files-dialog.component.html', + styleUrls: ['./overwrite-files-dialog.component.scss'] +}) +export class OverwriteFilesDialogComponent implements OnInit { + public remember = false; + + constructor( + private readonly _translateService: TranslateService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public filename: string + ) {} + + ngOnInit(): void {} + + cancel() { + this.dialogRef.close(); + } + + selectOption(option: 'overwrite' | 'no-overwrite') { + this.dialogRef.close({ option, remember: this.remember }); + } +} 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 1df08a03c..bf8d37810 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 @@ -212,13 +212,15 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { event.preventDefault(); } - uploadFiles(files: File[] | FileList) { - this._uploadFiles(convertFiles(files, this.appStateService.activeProjectId)); + async uploadFiles(files: File[] | FileList) { + await this._uploadFiles(convertFiles(files, this.appStateService.activeProjectId)); } - private _uploadFiles(files: FileUploadModel[]) { - this._fileUploadService.uploadFiles(files); - this._uploadStatusOverlayService.openStatusOverlay(); + private async _uploadFiles(files: FileUploadModel[]) { + const fileCount = await this._fileUploadService.uploadFiles(files); + if (fileCount) { + this._uploadStatusOverlayService.openStatusOverlay(); + } this._changeDetectorRef.detectChanges(); } diff --git a/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts b/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts index 193f8558a..663dbe54b 100644 --- a/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts +++ b/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts @@ -44,9 +44,11 @@ export class FileDropComponent implements OnInit { event.preventDefault(); } - uploadFiles(files: FileUploadModel[]) { - this._fileUploadService.uploadFiles(files); - this._uploadStatusOverlayService.openStatusOverlay(); + async uploadFiles(files: FileUploadModel[]) { + const fileCount = await this._fileUploadService.uploadFiles(files); + if (fileCount) { + this._uploadStatusOverlayService.openStatusOverlay(); + } this._dialogRef.detach(); this._changeDetectorRef.detectChanges(); } diff --git a/apps/red-ui/src/app/upload/file-upload.service.ts b/apps/red-ui/src/app/upload/file-upload.service.ts index d02960f80..dbd377a24 100644 --- a/apps/red-ui/src/app/upload/file-upload.service.ts +++ b/apps/red-ui/src/app/upload/file-upload.service.ts @@ -6,6 +6,7 @@ import { FileManagementControllerService } from '@redaction/red-ui-http'; import { interval, Subscription } from 'rxjs'; import { AppConfigKey, AppConfigService } from '../app-config/app-config.service'; import { TranslateService } from '@ngx-translate/core'; +import { DialogService } from '../dialogs/dialog.service'; @Injectable({ providedIn: 'root' @@ -23,7 +24,8 @@ export class FileUploadService { private readonly _applicationRef: ApplicationRef, private readonly _translateService: TranslateService, private readonly _appConfigService: AppConfigService, - private readonly _fileManagementControllerService: FileManagementControllerService + private readonly _fileManagementControllerService: FileManagementControllerService, + private readonly _dialogService: DialogService ) { interval(2500).subscribe((val) => { this._handleUploads(); @@ -39,20 +41,41 @@ export class FileUploadService { } } - uploadFiles(files: FileUploadModel[]) { + async uploadFiles(files: FileUploadModel[]): Promise { const maxSizeMB = this._appConfigService.getConfig(AppConfigKey.MAX_FILE_SIZE_MB, 50); const maxSizeBytes = maxSizeMB * 1024 * 1024; - files.forEach((file) => { + const projectFiles = this._appStateService.activeProject.files; + let option: 'overwrite' | 'no-overwrite' | undefined = undefined; + for (let idx = 0; idx < files.length; ++idx) { + const file = files[idx]; + let currentOption = option; + if (!!projectFiles.find((pf) => pf.filename === file.file.name)) { + if (!option) { + const res = await this._dialogService.openOverwriteFileDialog(file.file.name); + if (res.cancel) { + return; + } + currentOption = res.option; + option = res.remember ? currentOption : undefined; + } + + if (currentOption === 'no-overwrite') { + files.splice(idx, 1); + --idx; + continue; + } + } if (file.size > maxSizeBytes) { file.completed = true; file.error = { message: this._translateService.instant('upload-status.error.file-size', { size: maxSizeMB }) }; file.sizeError = true; } - }); + } this.files.push(...files); files.forEach((newFile) => { this.scheduleUpload(newFile); }); + return files.length; } stopAllUploads() { diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 79b16d29f..d546729e5 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -695,5 +695,15 @@ "rule-editor": "Rule Editor", "watermark": "Watermark", "pending-changes-guard": "WARNING: You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.", - "reset-filters": "Reset Filters" + "reset-filters": "Reset Filters", + "overwrite-files-dialog": { + "title": "File already exists!", + "question": "{{filename}} already exists. What do you want to do?", + "options": { + "overwrite": "Overwrite", + "no-overwrite": "Keep old file", + "cancel": "Cancel all uploads", + "remember": "Remember option" + } + } } From 32f29c946f8f664e46151abde3f43274f4a9f18f Mon Sep 17 00:00:00 2001 From: Timo Date: Sat, 9 Jan 2021 14:37:31 +0200 Subject: [PATCH 3/3] fixed lint err --- apps/red-ui/src/app/upload/file-upload.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/red-ui/src/app/upload/file-upload.service.ts b/apps/red-ui/src/app/upload/file-upload.service.ts index dbd377a24..6e363299a 100644 --- a/apps/red-ui/src/app/upload/file-upload.service.ts +++ b/apps/red-ui/src/app/upload/file-upload.service.ts @@ -45,7 +45,7 @@ export class FileUploadService { const maxSizeMB = this._appConfigService.getConfig(AppConfigKey.MAX_FILE_SIZE_MB, 50); const maxSizeBytes = maxSizeMB * 1024 * 1024; const projectFiles = this._appStateService.activeProject.files; - let option: 'overwrite' | 'no-overwrite' | undefined = undefined; + let option: 'overwrite' | 'no-overwrite' | undefined; for (let idx = 0; idx < files.length; ++idx) { const file = files[idx]; let currentOption = option;