diff options
Diffstat (limited to 'frontend/src/app/_elements/folder')
3 files changed, 140 insertions, 53 deletions
diff --git a/frontend/src/app/_elements/folder/folder.component.css b/frontend/src/app/_elements/folder/folder.component.css index 9e7644b6..97c13299 100644 --- a/frontend/src/app/_elements/folder/folder.component.css +++ b/frontend/src/app/_elements/folder/folder.component.css @@ -105,8 +105,9 @@ .bottom-button { font-size: large; position: relative; + text-align: center; background-color: var(--ns-primary); - width: 10rem; + width: 12rem; height: 2.3rem; border-color: var(--ns-primary); border-style: solid; @@ -170,7 +171,8 @@ .folder-inside { width: 100%; - min-height: 40rem; + min-height: 33rem; + height: 100%; max-height: 100%; } diff --git a/frontend/src/app/_elements/folder/folder.component.html b/frontend/src/app/_elements/folder/folder.component.html index 97ae0d23..da182945 100644 --- a/frontend/src/app/_elements/folder/folder.component.html +++ b/frontend/src/app/_elements/folder/folder.component.html @@ -29,47 +29,48 @@ <button matSuffix class="btn-clear input-icon" (click)="clearSearchTerm()"><mat-icon>clear</mat-icon></button> </mat-form-field> </div> - <div id="search-options"> - <!-- <div id="collapseFilters" class="collapse collapse-horizontal"> + <div id="modelFilter" *ngIf="type == FolderType.Model && forExperiment"> + Filter: {{forExperiment.type}} + </div> + <!--<div id="search-options"> + <div id="collapseFilters" class="collapse collapse-horizontal"> <mat-icon class="text-offwhite ">timeline</mat-icon> Regresioni <mat-icon class="text-offwhite ">looks_two</mat-icon> Binarni klasifikacioni <mat-icon class="text-offwhite ">auto_awesome_motion</mat-icon> Multiklasifikacioni - </div> --> + </div> <button class="btn-clear icon-toggle" data-bs-toggle="collapse" data-bs-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters"> <mat-icon>filter_alt</mat-icon> </button> - <!-- <div id="collapseSort" class="collapse collapse-horizontal"> + <div id="collapseSort" class="collapse collapse-horizontal"> [sort options here TODO] - </div> --> + </div> <button class="btn-clear icon-toggle" data-bs-toggle="collapse" data-bs-target="#collapseSort" aria-expanded="false" aria-controls="collapseSort"> <mat-icon>sort</mat-icon> </button> - <!-- <button class="btn-clear icon-toggle separator" [ngClass]="{'icon-toggle-on': listView}" (click)="toggleListView()"> + <button class="btn-clear icon-toggle separator" [ngClass]="{'icon-toggle-on': listView}" (click)="toggleListView()"> <mat-icon>view_list</mat-icon> - </button> --> - </div> + </button> + </div>--> </div> <!--{{fileToDisplay ? fileToDisplay.name : 'No file selected.'}} {{selectedFileIndex}} {{hoveringOverFileIndex}}--> <div class="folder-inside bg-blur"> <div class="file-content" [ngClass]="{'form-hidden' : listView}"> <div class="file-bottom-buttons" *ngIf="selectedTab != TabType.NewFile"> - <button *ngIf="this.selectedFile && selectedTab == TabType.File" class="btn-clear file-button" (click)="deleteFile(this.selectedFile, $event)"> + <button *ngIf="this.selectedFile && selectedTab == TabType.File && privacy != Privacy.Public" class="btn-clear file-button" (click)="deleteFile(this.selectedFile, $event)"> <mat-icon matTooltip="Obriši" matTooltipPosition="right">delete</mat-icon> </button> <button *ngIf="this.selectedFile && selectedTab==TabType.File && FolderType.Dataset==this.type" class="btn-clear file-button" (click)="downloadFile(this.selectedFile,$event)" style="display: inline-block;"> <mat-icon matTooltip="Preuzmi" matTooltipPosition="before">download</mat-icon> </button> - - <!-- <button class="btn-clear file-button"> <mat-icon>zoom_out_map</mat-icon> </button> --> </div> - <app-form-model [ngClass]="{'form-hidden': type != FolderType.Model}" [forExperiment]="forExperiment" [hideProblemType]="(forExperiment ? true : false)" [forProblemType]="(forExperiment ? forExperiment.type : ProblemType.Regression)"></app-form-model> - <app-form-dataset [ngClass]="{'form-hidden': type != FolderType.Dataset}" [forExperiment]="forExperiment"></app-form-dataset> + <app-form-model [ngClass]="{'form-hidden': type != FolderType.Model}" [forExperiment]="forExperiment" [hideProblemType]="(forExperiment ? true : false)" [forProblemType]="(forExperiment ? forExperiment.type : ProblemType.Regression)" (editEvent)="onFileChange()"></app-form-model> + <app-form-dataset [ngClass]="{'form-hidden': type != FolderType.Dataset}" [forExperiment]="forExperiment" (editEvent)="onFileChange()"></app-form-dataset> </div> <div [ngClass]="{'form-hidden' : !listView}" class="list-view"> <div *ngFor="let file of filteredFiles; let i = index"> @@ -107,7 +108,7 @@ {{predictor.lastUpdated | date}} </div> <div class="mx-2 hover-show"> - <button class="btn-clear file-button" (click)="deleteFile(predictor, $event)"> + <button class="btn-clear file-button" (click)="deleteFile(predictor, $event, true)"> <mat-icon>delete</mat-icon> </button> </div> @@ -132,14 +133,30 @@ </div> </div> </button> - <button mat-button (click)="ok()" class="bottom-button text-offwhite rounded-bottom" *ngSwitchCase="false"> - <div class="f-row"> - <div>Ok</div> - <div class="icon-double pt-1"> - <mat-icon>check</mat-icon> - <mat-icon>check</mat-icon> + <ng-container *ngSwitchCase="false"> + <button mat-button (click)="ok()" class="bottom-button text-offwhite rounded-bottom" *ngIf="!selectedFileHasChanges"> + <div class="f-row"> + <div>Ok</div> + <div class="p-1 w-100" *ngIf="loadingAction"> + <app-spinner></app-spinner> + </div> + <div class="icon-double pt-1" *ngIf="!loadingAction"> + <mat-icon>check</mat-icon> + <mat-icon>check</mat-icon> + </div> </div> - </div> - </button> + </button> + <button mat-button (click)="updateFile()" class="bottom-button text-offwhite rounded-bottom" *ngIf="selectedFileHasChanges" [disabled]="loadingAction"> + <div class="f-row"> + <div *ngIf="!loadingAction">Sačuvaj izmene</div> + <div class="pt-1" *ngIf="!loadingAction"> + <mat-icon>edit</mat-icon> + </div> + <div class="pt-1 w-100" *ngIf="loadingAction"> + <app-spinner></app-spinner> + </div> + </div> + </button> + </ng-container> </div> </div>
\ No newline at end of file diff --git a/frontend/src/app/_elements/folder/folder.component.ts b/frontend/src/app/_elements/folder/folder.component.ts index 254298fb..beff6012 100644 --- a/frontend/src/app/_elements/folder/folder.component.ts +++ b/frontend/src/app/_elements/folder/folder.component.ts @@ -14,6 +14,7 @@ import { FormModelComponent } from '../form-model/form-model.component'; import { ActivatedRoute, Router } from '@angular/router'; import Predictor from 'src/app/_data/Predictor'; import FileSaver from 'file-saver'; +import isEqual from 'lodash.isequal'; @Component({ selector: 'app-folder', @@ -105,6 +106,7 @@ export class FolderComponent implements AfterViewInit { selectFile(file?: FolderFile) { this.formDataset.resetPagging(); this.selectedFile = file; + Object.assign(this.lastFileData, this.selectedFile); this.fileToDisplay = file; if (this.type == FolderType.Experiment && file) { this.router.navigate(['/experiment/' + file._id]); @@ -118,9 +120,9 @@ export class FolderComponent implements AfterViewInit { if (this.type == FolderType.Dataset) this.formDataset.loadExisting(); } - + goToExperimentPageWithPredictor(file: FolderFile, predictor: Predictor) { - this.router.navigate(['/experiment/' + file._id + "/" + predictor._id]); + this.router.navigate(['/experiment/p/' + predictor._id]); } createNewFile() { @@ -138,7 +140,7 @@ export class FolderComponent implements AfterViewInit { _initialized: boolean = false; refreshFiles(selectedDatasetId: string | null = null, selectedModelId: string | null = null) { - + this.tabsToShow.forEach(tab => { this.folders[tab] = []; }); @@ -221,7 +223,7 @@ export class FolderComponent implements AfterViewInit { this.predictorsForExp[exp._id].forEach(pred => { const model = this.folders[TabType.MyModels].find(model => model._id == pred.modelId); pred.name = model?.name!; - pred.lastUpdated = model?.lastUpdated!; + //pred.lastUpdated = model?.lastUpdated!; }) /* ------------------------------------------------ */ this.searchTermsChanged(); @@ -267,7 +269,12 @@ export class FolderComponent implements AfterViewInit { searchTermsChanged() { this.filteredFiles.length = 0; if (!this.files) return; - this.filteredFiles.push(...this.files.filter((file) => file.name.toLowerCase().includes(this.searchTerm.toLowerCase()))); + this.filteredFiles.push(...this.files.filter((file) => { + return (file.name.toLowerCase().includes(this.searchTerm.toLowerCase()) + && (!this.forExperiment + || this.type != FolderType.Model + || (this.type == FolderType.Model && (<Model>file).type == this.forExperiment.type))) + })); /*if (this.selectedFile) { if (!this.filteredFiles.includes(this.selectedFile)) { if (this.hoverTab === TabType.None && this.getFolderType(this.selectedTab) === this.type) { @@ -282,41 +289,102 @@ export class FolderComponent implements AfterViewInit { listView: boolean = true; - deleteFile(file: FolderFile, event: Event) { - event.stopPropagation(); - this.filteredFiles.splice(this.filteredFiles.indexOf(file), 1); - this.files.splice(this.files.indexOf(file), 1); + loadingAction = false; + selectedFileHasChanges = false; + lastFileData = {}; + + onFileChange() { + console.log(this.selectedFile, this.lastFileData) + setTimeout(() => { + this.selectedFileHasChanges = !((this.selectedTab == TabType.NewFile) || isEqual(this.selectedFile, this.lastFileData)); + }); + } + + updateFile() { + const file = this.selectedFile; + this.loadingAction = true; switch (this.type) { case FolderType.Dataset: - this.datasetsService.deleteDataset(<Dataset>file).subscribe((response) => { - Shared.openDialog("Obaveštenje", "Uspešno ste obrisali odabrani izvor podataka."); - //this.filteredFiles.splice(this.files.indexOf(file), 1); - //this.refreshFiles(); + this.datasetsService.editDataset(<Dataset>file).subscribe((response) => { + this.fileUpdatedSuccess(); }); break; case FolderType.Model: - this.modelsService.deleteModel(<Model>file).subscribe((response) => { - Shared.openDialog("Obaveštenje", "Uspešno ste obrisali odabranu konfiguraciju neuronske mreže."); - //this.refreshFiles(); + this.modelsService.editModel(<Model>file).subscribe((response) => { + this.fileUpdatedSuccess(); }); break; + } + } + + fileUpdatedSuccess() { + this.loadingAction = false; + this.selectedFileHasChanges = false; + Object.assign(this.lastFileData, this.selectedFile); + this.refreshFiles(); + } + + deleteFile(file: FolderFile, event: Event, deletePredictor: boolean = false) { + event.stopPropagation(); + + switch (this.type) { + case FolderType.Dataset: + const dataset = <Dataset>file; + Shared.openYesNoDialog("Obriši izvor podataka", "Eksperimenti i trenirani modeli nad ovim izvorom podataka će takođe biti obrisani, da li ste sigurni da želite da obrišete izvor: " + dataset.name + "?", () => { + this.filteredFiles.splice(this.filteredFiles.indexOf(file), 1); + this.files.splice(this.files.indexOf(file), 1); + this.loadingAction = true; + this.datasetsService.deleteDataset(dataset).subscribe((response) => { + this.loadingAction = false; + }); + }) + break; + case FolderType.Model: + const model = <Model>file; + Shared.openYesNoDialog("Obriši konfiguraciju neuronske mreže", "Trenirani modeli za ovu konfiguraciju će takođe biti obrisani, da li ste sigurni da želite da obrišete konfiguraciju: " + model.name + "?", () => { + this.filteredFiles.splice(this.filteredFiles.indexOf(file), 1); + this.files.splice(this.files.indexOf(file), 1); + this.loadingAction = true; + this.modelsService.deleteModel(<Model>file).subscribe((response) => { + this.loadingAction = false; + }); + }) + + break; case FolderType.Experiment: - // this.experimentsService.deleteExperiment(<Model>file).subscribe((response) => { - // console.log(response); - // }); - //todo delete za predictor + if (deletePredictor) { + const predictor = <Predictor>file; + Shared.openYesNoDialog("Obriši trenirani model", "Da li ste sigurni da želite da obrišete trenirani model: " + predictor.name + "?", () => { + this.filteredFiles.splice(this.filteredFiles.indexOf(file), 1); + this.files.splice(this.files.indexOf(file), 1); + this.loadingAction = true; + this.predictorsService.deletePredictor(predictor).subscribe((response) => { + this.loadingAction = false; + }); + }); + } else { + const experiment = <Experiment>file; + Shared.openYesNoDialog("Obriši eksperiment", "Trenirani modeli za ovaj eksperiment će takođe biti obrisani, da li ste sigurni da želite da obrišete eksperiment: " + experiment.name + "?", () => { + this.filteredFiles.splice(this.filteredFiles.indexOf(file), 1); + this.files.splice(this.files.indexOf(file), 1); + this.loadingAction = true; + this.experimentsService.deleteExperiment(experiment).subscribe((response) => { + this.loadingAction = false; + }); + }); + } break; } } downloadFile(file: FolderFile, event: Event) { event.stopPropagation(); - if (this.type==FolderType.Dataset) { - const fileId=(<Dataset>file).fileId; - const name=(<Dataset>file).name; - const ext=(<Dataset>file).extension; - if(fileId!=undefined) - this.datasetsService.downloadFile(fileId).subscribe((response)=>{ - FileSaver.saveAs(response,name+ext); + if (this.type == FolderType.Dataset) { + const fileId = (<Dataset>file).fileId; + const name = (<Dataset>file).name; + const ext = (<Dataset>file).extension; + if (fileId != undefined) + this.datasetsService.downloadFile(fileId).subscribe((response) => { + FileSaver.saveAs(response, name + ext); }); @@ -333,7 +401,7 @@ export class FolderComponent implements AfterViewInit { this.datasetsService.stealDataset(<Dataset>file).subscribe((response) => { Shared.openDialog("Obaveštenje", "Uspešno ste dodali javni izvor podataka u vašu kolekciju."); this.refreshFiles(null); - }, (error:any) => { + }, (error: any) => { if (error.error == "Dataset with this name already exists") { Shared.openDialog("Obaveštenje", "Izvor podataka sa ovim imenom postoji u vašoj kolekciji."); } @@ -343,7 +411,7 @@ export class FolderComponent implements AfterViewInit { this.modelsService.stealModel(<Model>file).subscribe((response) => { Shared.openDialog("Obaveštenje", "Uspešno ste dodali javnu konfiguraciju neuronske mreže u vašu kolekciju."); this.refreshFiles(null); - }, (error:any) => { + }, (error: any) => { if (error.error == "Model already exisits or validation size is not between 0-1") { Shared.openDialog("Obaveštenje", "Model sa ovim imenom postoji u vašoj kolekciji."); } |