Commit fc881ca5 authored by Gert Paimla's avatar Gert Paimla

dataset importer validators

parent f245747b
......@@ -13,7 +13,7 @@ export class LogService {
constructor(private snackBar: MatSnackBar) {
}
public handleError<T>(operation = 'operation', result?: T) {
public handleError<T>(operation = 'operation', result?: T): (error: T) => Observable<T> {
return (error: T): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.warn(error); // log to console instead
......@@ -23,19 +23,25 @@ export class LogService {
}
public logStatus(val: unknown, msg: string) {
public logStatus(val: unknown, msg: string): void {
if (!this.isProduction) {
console.warn(msg, val);
}
}
public snackBarError(error: HttpErrorResponse, time: number) {
this.snackBar.open(error.name + ': ' + error.status + ' ' + error.statusText, 'Close', {
duration: time,
});
public snackBarError(error: HttpErrorResponse, time = 5000): void {
if (error.error.hasOwnProperty('detail')) {
this.snackBar.open(`${error.statusText}: ${error.error.detail}`, 'Close', {
duration: time,
});
} else {
this.snackBar.open(error.name + ': ' + error.status + ' ' + error.statusText, 'Close', {
duration: time,
});
}
}
public snackBarMessage(msg: string, time: number) {
public snackBarMessage(msg: string, time: number): void {
this.snackBar.open(msg, 'Close', {
duration: time,
});
......
......@@ -16,9 +16,17 @@
<mat-error *ngIf="importerForm?.get('newNameFormControl')?.hasError('required')">
Dataset name is <strong>required</strong>
</mat-error>
<mat-error *ngIf="importerForm?.get('newNameFormControl')?.hasError('notLowerCase')">
Uppercase characters are not allowed
</mat-error>
<mat-error *ngIf="importerForm?.get('newNameFormControl')?.hasError('wildCard')">
Wildcards are not allowed in Index operations
</mat-error>
<mat-error *ngIf="importerForm?.get('newNameFormControl')?.hasError('colon')">
':' symbols are not allowed in Index names
</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Separator" autocomplete="off" formControlName="separatorFormControl">
<mat-hint>CSV only
......
......@@ -2,7 +2,7 @@ import {Component, OnDestroy, OnInit} from '@angular/core';
import {LiveErrorStateMatcher} from '../../../shared/CustomerErrorStateMatchers';
import {ProjectStore} from '../../../core/projects/project.store';
import {Project} from '../../../shared/types/Project';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {AbstractControl, FormControl, FormGroup, ValidationErrors, Validators} from '@angular/forms';
import {ErrorStateMatcher} from '@angular/material/core';
import {MatDialogRef} from '@angular/material/dialog';
import {ProjectService} from '../../../core/projects/project.service';
......@@ -13,6 +13,22 @@ import {DatasetImporterService} from '../../../core/tools/dataset-importer/datas
import {FileValidator} from 'ngx-material-file-input';
import {HttpErrorResponse, HttpEventType, HttpResponse} from '@angular/common/http';
function indexNameValidator(control: AbstractControl): null | ValidationErrors {
if (typeof control.value === 'string') {
const controlValue = control.value;
if (controlValue.toLowerCase() !== controlValue) {
return {notLowerCase: true};
}
if (controlValue.includes('*')){
return {wildCard: true};
}
if (controlValue.includes(':')){
return {colon: true};
}
}
return null;
}
@Component({
selector: 'app-create-dataset-dialog',
templateUrl: './create-dataset-dialog.component.html',
......@@ -22,7 +38,7 @@ export class CreateDatasetDialogComponent implements OnInit, OnDestroy {
readonly maxSize = 1048576000000; // 976 gigabytes
importerForm = new FormGroup({
descriptionFormControl: new FormControl('', [Validators.required]),
newNameFormControl: new FormControl('', [Validators.required]),
newNameFormControl: new FormControl('', [Validators.required, indexNameValidator]),
separatorFormControl: new FormControl(''),
fileFormControl: new FormControl(undefined,
[Validators.required, FileValidator.maxContentSize(this.maxSize)]),
......@@ -43,7 +59,7 @@ export class CreateDatasetDialogComponent implements OnInit, OnDestroy {
private projectStore: ProjectStore) {
}
ngOnInit() {
ngOnInit(): void {
this.projectStore.getCurrentProject().pipe(takeUntil(this.destroyed$)).subscribe(project => {
if (project) {
this.currentProject = project;
......@@ -55,7 +71,7 @@ export class CreateDatasetDialogComponent implements OnInit, OnDestroy {
onSubmit(formData: {
descriptionFormControl: string; newNameFormControl: string; separatorFormControl: string;
fileFormControl: { files: (string | Blob)[]; };
}) {
}): void {
const postData = new FormData();
postData.set('description', formData.descriptionFormControl);
postData.set('index', formData.newNameFormControl);
......@@ -65,7 +81,7 @@ export class CreateDatasetDialogComponent implements OnInit, OnDestroy {
this.importerService.createIndex(postData, this.currentProject.id).pipe(
takeUntil(this.destroyed$)).subscribe(response => {
if (response instanceof HttpErrorResponse) {
this.logService.snackBarError(response, 2000);
this.logService.snackBarError(response);
} else if (response.type === HttpEventType.UploadProgress) {
this.uploadedBytes = response.loaded || 0;
this.totalBytes = response.total || 0;
......@@ -80,7 +96,7 @@ export class CreateDatasetDialogComponent implements OnInit, OnDestroy {
this.dialogRef.close();
}
ngOnDestroy() {
ngOnDestroy(): void {
this.destroyed$.next(true);
this.destroyed$.complete();
}
......
......@@ -50,7 +50,7 @@ export class DatasetImporterComponent implements OnInit, OnDestroy {
private logService: LogService) {
}
ngOnInit() {
ngOnInit(): void {
this.tableData.sort = this.sort;
this.tableData.paginator = this.paginator;
// check for updates after 30s every 30s
......@@ -81,7 +81,7 @@ export class DatasetImporterComponent implements OnInit, OnDestroy {
});
}
setUpPaginator() {
setUpPaginator(): void {
// If the user changes the sort order, reset back to the first page.
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
......@@ -105,12 +105,12 @@ export class DatasetImporterComponent implements OnInit, OnDestroy {
});
}
ngOnDestroy() {
ngOnDestroy(): void {
this.destroyed$.next(true);
this.destroyed$.complete();
}
openCreateDialog() {
openCreateDialog(): void {
const dialogRef = this.dialog.open(CreateDatasetDialogComponent, {
maxHeight: '650px',
width: '700px',
......@@ -127,21 +127,21 @@ export class DatasetImporterComponent implements OnInit, OnDestroy {
/** Whether the number of selected elements matches the total number of rows. */
isAllSelected() {
isAllSelected(): boolean {
const numSelected = this.selectedRows.selected.length;
const numRows = this.tableData.data.length;
return numSelected === numRows;
}
/** Selects all rows if they are not all selected; otherwise clear selection. */
masterToggle() {
masterToggle(): void {
this.isAllSelected() ?
this.selectedRows.clear() :
this.tableData.data.forEach(row => this.selectedRows.select(row));
}
onDelete(dataset: DatasetImporter, index: number) {
onDelete(dataset: DatasetImporter, index: number): void {
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
data: {confirmText: 'Delete', mainText: 'Are you sure you want to delete this Dataset?'}
});
......@@ -157,7 +157,7 @@ export class DatasetImporterComponent implements OnInit, OnDestroy {
});
}
onDeleteAllSelected() {
onDeleteAllSelected(): void {
if (this.selectedRows.selected.length > 0) {
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
data: {
......@@ -181,7 +181,7 @@ export class DatasetImporterComponent implements OnInit, OnDestroy {
}
}
removeSelectedRows() {
removeSelectedRows(): void {
this.selectedRows.selected.forEach((selectedDataset: DatasetImporter) => {
const index: number = this.tableData.data.findIndex(x => x.id === selectedDataset.id);
this.tableData.data.splice(index, 1);
......@@ -191,13 +191,13 @@ export class DatasetImporterComponent implements OnInit, OnDestroy {
}
applyFilter(filterValue: EventTarget | null, field: string) {
applyFilter(filterValue: EventTarget | null, field: string): void {
this.filteringValues[field] = (filterValue as HTMLInputElement).value ? (filterValue as HTMLInputElement).value : '';
this.filterQueriesToString();
this.filteredSubject.next();
}
filterQueriesToString() {
filterQueriesToString(): void {
this.inputFilterQuery = '';
for (const field in this.filteringValues) {
this.inputFilterQuery += `&${field}=${this.filteringValues[field]}`;
......
......@@ -4,7 +4,7 @@
export const environment = {
// apiUrl: 'https://rest-dev.texta.ee/api/v1',
apiHost: 'https://rest-dev.texta.ee',
apiHost: 'http://localhost',
apiBasePath: '/api/v1',
production: false
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment