Pull request #88: RED-910: Show a dialog if a file already exists

Merge in RED/ui from RED-910 to master

* commit '32f29c946f8f664e46151abde3f43274f4a9f18f':
  fixed lint err
  Show a dialog if a file already exists
  Fixed sync width directive
This commit is contained in:
Timo Bejan 2021-01-09 13:43:05 +01:00
commit c738fafec7
11 changed files with 144 additions and 16 deletions

View File

@ -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,

View File

@ -3,6 +3,7 @@
:host {
display: flex;
height: 30px;
flex: 1;
> div {
align-items: center;

View File

@ -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 };
});
}
}

View File

@ -0,0 +1,17 @@
<section class="dialog">
<div class="dialog-header heading-l" translate="overwrite-files-dialog.title"></div>
<div class="dialog-content">
<p [innerHTML]="'overwrite-files-dialog.question' | translate: { filename: filename }"></p>
<mat-checkbox [checked]="remember" (change)="remember = !remember" color="primary">
{{ 'overwrite-files-dialog.options.remember' | translate }}
</mat-checkbox>
</div>
<div class="dialog-actions">
<div class="all-caps-label primary pointer" (click)="selectOption('overwrite')" translate="overwrite-files-dialog.options.overwrite"></div>
<div class="all-caps-label primary pointer" (click)="selectOption('no-overwrite')" translate="overwrite-files-dialog.options.no-overwrite"></div>
<div class="all-caps-label cancel" (click)="cancel()" translate="overwrite-files-dialog.options.cancel"></div>
</div>
</section>

View File

@ -0,0 +1,7 @@
mat-checkbox {
margin-top: 16px;
}
.dialog-actions > div:not(:last-child) {
margin-right: 32px;
}

View File

@ -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<OverwriteFilesDialogComponent>,
@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 });
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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<number> {
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;
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() {

View File

@ -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')

View File

@ -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": "<b>{{filename}}</b> already exists. What do you want to do?",
"options": {
"overwrite": "Overwrite",
"no-overwrite": "Keep old file",
"cancel": "Cancel all uploads",
"remember": "Remember option"
}
}
}