aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/app/_elements/folder
diff options
context:
space:
mode:
authorTAMARA JERINIC <tamara.jerinic@gmail.com>2022-05-20 00:06:49 +0200
committerTAMARA JERINIC <tamara.jerinic@gmail.com>2022-05-20 00:06:49 +0200
commit638f410ad569c632c8dab6cdf66d6b5fd90d5b0c (patch)
treea8f0bbffbdb397a0e7a151feb374b0cc05da1983 /frontend/src/app/_elements/folder
parent78c346b1296d2820e943e2918e4d3e9e57093e8f (diff)
parent863881a77f00810f3298aaf6fc451edfe733d121 (diff)
Merge branch 'redesign' of http://gitlab.pmf.kg.ac.rs/igrannonica/neuronstellar into redesign
Diffstat (limited to 'frontend/src/app/_elements/folder')
-rw-r--r--frontend/src/app/_elements/folder/folder.component.css6
-rw-r--r--frontend/src/app/_elements/folder/folder.component.html61
-rw-r--r--frontend/src/app/_elements/folder/folder.component.ts126
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.");
}