aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/api/api/Controllers/DatasetController.cs7
-rw-r--r--frontend/package-lock.json208
-rw-r--r--frontend/package.json2
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts37
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.ts2
-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
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.html63
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.ts74
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.html26
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.ts13
-rw-r--r--frontend/src/app/_elements/spinner/spinner.component.css78
-rw-r--r--frontend/src/app/_elements/spinner/spinner.component.html3
-rw-r--r--frontend/src/app/_elements/spinner/spinner.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/spinner/spinner.component.ts15
-rw-r--r--frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.css8
-rw-r--r--frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.html8
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.ts88
-rw-r--r--frontend/src/app/_pages/my-models/my-models.component.html43
-rw-r--r--frontend/src/app/_pages/my-models/my-models.component.ts59
-rw-r--r--frontend/src/app/_services/experiments.service.ts4
-rw-r--r--frontend/src/app/_services/models.service.ts2
-rw-r--r--frontend/src/app/app-routing.module.ts2
-rw-r--r--frontend/src/app/app.module.ts4
25 files changed, 598 insertions, 366 deletions
diff --git a/backend/api/api/Controllers/DatasetController.cs b/backend/api/api/Controllers/DatasetController.cs
index 849d9884..c93ac9db 100644
--- a/backend/api/api/Controllers/DatasetController.cs
+++ b/backend/api/api/Controllers/DatasetController.cs
@@ -251,9 +251,14 @@ namespace api.Controllers
return NotFound($"Dataset with ID = {id} or user with ID = {uploaderId} not found");
dataset.lastUpdated = DateTime.UtcNow;
-
_datasetService.Update(uploaderId, id, dataset);
+ if (!dataset.isPreProcess)
+ {
+ FileModel fileModel = _fileService.getFile(dataset.fileId);
+ _mlConnectionService.PreProcess(dataset, fileModel.path, uploaderId);
+ }
+
return Ok($"Dataset with ID = {id} updated");
}
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index ebe30390..5029a126 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -33,6 +33,7 @@
"d3-graphviz": "^2.6.1",
"file-saver": "^2.0.5",
"jquery": "^3.6.0",
+ "lodash.isequal": "^4.5.0",
"material-icons": "^1.10.8",
"mdb-angular-ui-kit": "^2.0.0",
"ng-multiselect-dropdown": "^0.3.8",
@@ -55,6 +56,7 @@
"@types/d3-graphviz": "^2.6.7",
"@types/file-saver": "^2.0.5",
"@types/jasmine": "~3.10.0",
+ "@types/lodash.isequal": "^4.5.6",
"@types/node": "^12.11.1",
"jasmine-core": "~4.0.0",
"karma": "~6.3.0",
@@ -435,6 +437,7 @@
},
"node_modules/@angular/compiler-cli": {
"version": "13.2.5",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.17.2",
@@ -463,6 +466,7 @@
},
"node_modules/@angular/compiler-cli/node_modules/@ampproject/remapping": {
"version": "2.1.2",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.0"
@@ -473,6 +477,7 @@
},
"node_modules/@angular/compiler-cli/node_modules/@babel/core": {
"version": "7.17.5",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.1.0",
@@ -501,6 +506,7 @@
},
"node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": {
"version": "6.3.0",
+ "dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -508,6 +514,7 @@
},
"node_modules/@angular/compiler-cli/node_modules/@babel/generator": {
"version": "7.17.3",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.17.0",
@@ -520,6 +527,7 @@
},
"node_modules/@angular/compiler-cli/node_modules/source-map": {
"version": "0.5.7",
+ "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -742,6 +750,7 @@
},
"node_modules/@babel/core": {
"version": "7.16.12",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.16.7",
@@ -770,6 +779,7 @@
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.0",
+ "dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -777,6 +787,7 @@
},
"node_modules/@babel/core/node_modules/source-map": {
"version": "0.5.7",
+ "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -784,6 +795,7 @@
},
"node_modules/@babel/generator": {
"version": "7.16.8",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.16.8",
@@ -796,6 +808,7 @@
},
"node_modules/@babel/generator/node_modules/source-map": {
"version": "0.5.7",
+ "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -2821,6 +2834,21 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/lodash": {
+ "version": "4.14.182",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
+ "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
+ "dev": true
+ },
+ "node_modules/@types/lodash.isequal": {
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.6.tgz",
+ "integrity": "sha512-Ww4UGSe3DmtvLLJm2F16hDwEQSv7U0Rr8SujLUA2wHI2D2dm8kPu6Et+/y303LfjTIwSBKXB/YTUcAKpem/XEg==",
+ "dev": true,
+ "dependencies": {
+ "@types/lodash": "*"
+ }
+ },
"node_modules/@types/mime": {
"version": "1.3.2",
"dev": true,
@@ -3243,6 +3271,7 @@
},
"node_modules/anymatch": {
"version": "3.1.2",
+ "dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
@@ -3493,6 +3522,7 @@
},
"node_modules/binary-extensions": {
"version": "2.2.0",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3580,6 +3610,7 @@
},
"node_modules/braces": {
"version": "3.0.2",
+ "dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.0.1"
@@ -3757,6 +3788,7 @@
},
"node_modules/chokidar": {
"version": "3.5.3",
+ "dev": true,
"funding": [
{
"type": "individual",
@@ -4699,6 +4731,7 @@
},
"node_modules/dependency-graph": {
"version": "0.11.0",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
@@ -4845,6 +4878,7 @@
},
"node_modules/encoding": {
"version": "0.1.13",
+ "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -4853,6 +4887,7 @@
},
"node_modules/encoding/node_modules/iconv-lite": {
"version": "0.6.3",
+ "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -5328,6 +5363,7 @@
},
"node_modules/fill-range": {
"version": "7.0.1",
+ "dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -5576,6 +5612,7 @@
},
"node_modules/glob-parent": {
"version": "5.1.2",
+ "dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@@ -6113,6 +6150,7 @@
},
"node_modules/is-binary-path": {
"version": "2.1.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
@@ -6162,6 +6200,7 @@
},
"node_modules/is-extglob": {
"version": "2.1.1",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -6176,6 +6215,7 @@
},
"node_modules/is-glob": {
"version": "4.0.3",
+ "dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -6199,6 +6239,7 @@
},
"node_modules/is-number": {
"version": "7.0.0",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@@ -6891,6 +6932,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
+ },
"node_modules/log-symbols": {
"version": "4.1.0",
"dev": true,
@@ -6987,6 +7033,7 @@
},
"node_modules/lru-cache": {
"version": "6.0.0",
+ "dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
@@ -6997,6 +7044,7 @@
},
"node_modules/magic-string": {
"version": "0.25.7",
+ "dev": true,
"license": "MIT",
"dependencies": {
"sourcemap-codec": "^1.4.4"
@@ -7539,6 +7587,7 @@
},
"node_modules/normalize-path": {
"version": "3.0.0",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -8175,6 +8224,7 @@
},
"node_modules/picomatch": {
"version": "2.3.1",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -8925,6 +8975,7 @@
},
"node_modules/readdirp": {
"version": "3.6.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
@@ -9199,7 +9250,7 @@
},
"node_modules/safer-buffer": {
"version": "2.1.2",
- "devOptional": true,
+ "dev": true,
"license": "MIT"
},
"node_modules/sass": {
@@ -9319,6 +9370,7 @@
},
"node_modules/semver": {
"version": "7.3.5",
+ "dev": true,
"license": "ISC",
"dependencies": {
"lru-cache": "^6.0.0"
@@ -9668,6 +9720,7 @@
},
"node_modules/sourcemap-codec": {
"version": "1.4.8",
+ "dev": true,
"license": "MIT"
},
"node_modules/spdy": {
@@ -10046,6 +10099,7 @@
},
"node_modules/to-regex-range": {
"version": "5.0.1",
+ "dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@@ -10127,6 +10181,7 @@
},
"node_modules/typescript": {
"version": "4.5.5",
+ "dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@@ -10748,6 +10803,7 @@
},
"node_modules/yallist": {
"version": "4.0.0",
+ "dev": true,
"license": "ISC"
},
"node_modules/yaml": {
@@ -11033,6 +11089,7 @@
},
"@angular/compiler-cli": {
"version": "13.2.5",
+ "dev": true,
"requires": {
"@babel/core": "^7.17.2",
"chokidar": "^3.0.0",
@@ -11048,12 +11105,14 @@
"dependencies": {
"@ampproject/remapping": {
"version": "2.1.2",
+ "dev": true,
"requires": {
"@jridgewell/trace-mapping": "^0.3.0"
}
},
"@babel/core": {
"version": "7.17.5",
+ "dev": true,
"requires": {
"@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.16.7",
@@ -11073,12 +11132,14 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0"
+ "version": "6.3.0",
+ "dev": true
}
}
},
"@babel/generator": {
"version": "7.17.3",
+ "dev": true,
"requires": {
"@babel/types": "^7.17.0",
"jsesc": "^2.5.1",
@@ -11086,7 +11147,8 @@
}
},
"source-map": {
- "version": "0.5.7"
+ "version": "0.5.7",
+ "dev": true
}
}
},
@@ -11197,6 +11259,7 @@
},
"@babel/core": {
"version": "7.16.12",
+ "dev": true,
"requires": {
"@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.8",
@@ -11216,15 +11279,18 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0"
+ "version": "6.3.0",
+ "dev": true
},
"source-map": {
- "version": "0.5.7"
+ "version": "0.5.7",
+ "dev": true
}
}
},
"@babel/generator": {
"version": "7.16.8",
+ "dev": true,
"requires": {
"@babel/types": "^7.16.8",
"jsesc": "^2.5.1",
@@ -11232,7 +11298,8 @@
},
"dependencies": {
"source-map": {
- "version": "0.5.7"
+ "version": "0.5.7",
+ "dev": true
}
}
},
@@ -12165,8 +12232,7 @@
},
"dependencies": {
"ws": {
- "version": "7.5.7",
- "requires": {}
+ "version": "7.5.7"
}
}
},
@@ -12178,8 +12244,7 @@
},
"@ngtools/webpack": {
"version": "13.2.5",
- "dev": true,
- "requires": {}
+ "dev": true
},
"@nodelib/fs.scandir": {
"version": "2.1.5",
@@ -12522,6 +12587,21 @@
"version": "7.0.9",
"dev": true
},
+ "@types/lodash": {
+ "version": "4.14.182",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
+ "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
+ "dev": true
+ },
+ "@types/lodash.isequal": {
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.6.tgz",
+ "integrity": "sha512-Ww4UGSe3DmtvLLJm2F16hDwEQSv7U0Rr8SujLUA2wHI2D2dm8kPu6Et+/y303LfjTIwSBKXB/YTUcAKpem/XEg==",
+ "dev": true,
+ "requires": {
+ "@types/lodash": "*"
+ }
+ },
"@types/mime": {
"version": "1.3.2",
"dev": true
@@ -12731,8 +12811,7 @@
},
"acorn-import-assertions": {
"version": "1.8.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"adjust-sourcemap-loader": {
"version": "4.0.0",
@@ -12830,6 +12909,7 @@
},
"anymatch": {
"version": "3.1.2",
+ "dev": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -12981,7 +13061,8 @@
"dev": true
},
"binary-extensions": {
- "version": "2.2.0"
+ "version": "2.2.0",
+ "dev": true
},
"bl": {
"version": "4.1.0",
@@ -13038,8 +13119,7 @@
"dev": true
},
"bootstrap": {
- "version": "5.1.3",
- "requires": {}
+ "version": "5.1.3"
},
"brace-expansion": {
"version": "1.1.11",
@@ -13050,6 +13130,7 @@
},
"braces": {
"version": "3.0.2",
+ "dev": true,
"requires": {
"fill-range": "^7.0.1"
}
@@ -13158,6 +13239,7 @@
},
"chokidar": {
"version": "3.5.3",
+ "dev": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -13179,8 +13261,7 @@
},
"circular-dependency-plugin": {
"version": "5.2.2",
- "dev": true,
- "requires": {}
+ "dev": true
},
"clean-stack": {
"version": "2.2.0",
@@ -13551,8 +13632,7 @@
},
"css-prefers-color-scheme": {
"version": "6.0.3",
- "dev": true,
- "requires": {}
+ "dev": true
},
"css-select": {
"version": "4.2.1",
@@ -13752,7 +13832,8 @@
"dev": true
},
"dependency-graph": {
- "version": "0.11.0"
+ "version": "0.11.0",
+ "dev": true
},
"destroy": {
"version": "1.0.4",
@@ -13851,6 +13932,7 @@
},
"encoding": {
"version": "0.1.13",
+ "dev": true,
"optional": true,
"requires": {
"iconv-lite": "^0.6.2"
@@ -13858,6 +13940,7 @@
"dependencies": {
"iconv-lite": {
"version": "0.6.3",
+ "dev": true,
"optional": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -14170,6 +14253,7 @@
},
"fill-range": {
"version": "7.0.1",
+ "dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
@@ -14318,6 +14402,7 @@
},
"glob-parent": {
"version": "5.1.2",
+ "dev": true,
"requires": {
"is-glob": "^4.0.1"
}
@@ -14514,8 +14599,7 @@
},
"icss-utils": {
"version": "5.1.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"ieee754": {
"version": "1.2.1",
@@ -14662,6 +14746,7 @@
},
"is-binary-path": {
"version": "2.1.0",
+ "dev": true,
"requires": {
"binary-extensions": "^2.0.0"
}
@@ -14685,13 +14770,15 @@
"dev": true
},
"is-extglob": {
- "version": "2.1.1"
+ "version": "2.1.1",
+ "dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0"
},
"is-glob": {
"version": "4.0.3",
+ "dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
@@ -14705,7 +14792,8 @@
"dev": true
},
"is-number": {
- "version": "7.0.0"
+ "version": "7.0.0",
+ "dev": true
},
"is-path-cwd": {
"version": "2.2.0",
@@ -15029,8 +15117,7 @@
},
"karma-jasmine-html-reporter": {
"version": "1.7.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"karma-source-map-support": {
"version": "1.4.0",
@@ -15138,6 +15225,11 @@
"version": "4.0.8",
"dev": true
},
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
+ },
"log-symbols": {
"version": "4.1.0",
"dev": true,
@@ -15198,12 +15290,14 @@
},
"lru-cache": {
"version": "6.0.0",
+ "dev": true,
"requires": {
"yallist": "^4.0.0"
}
},
"magic-string": {
"version": "0.25.7",
+ "dev": true,
"requires": {
"sourcemap-codec": "^1.4.4"
}
@@ -15538,7 +15632,8 @@
}
},
"normalize-path": {
- "version": "3.0.0"
+ "version": "3.0.0",
+ "dev": true
},
"normalize-range": {
"version": "0.1.2",
@@ -15953,7 +16048,8 @@
"version": "1.0.0"
},
"picomatch": {
- "version": "2.3.1"
+ "version": "2.3.1",
+ "dev": true
},
"pify": {
"version": "2.3.0",
@@ -16043,8 +16139,7 @@
},
"postcss-custom-media": {
"version": "8.0.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-custom-properties": {
"version": "12.1.4",
@@ -16098,13 +16193,11 @@
},
"postcss-font-variant": {
"version": "5.0.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-gap-properties": {
"version": "3.0.3",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-image-set-function": {
"version": "4.0.6",
@@ -16124,8 +16217,7 @@
},
"postcss-initial": {
"version": "4.0.1",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-lab-function": {
"version": "4.1.1",
@@ -16146,18 +16238,15 @@
},
"postcss-logical": {
"version": "5.0.4",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-media-minmax": {
"version": "5.0.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-modules-extract-imports": {
"version": "3.0.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-modules-local-by-default": {
"version": "4.0.0",
@@ -16191,13 +16280,11 @@
},
"postcss-overflow-shorthand": {
"version": "3.0.3",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-page-break": {
"version": "3.0.4",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-place": {
"version": "7.0.4",
@@ -16254,8 +16341,7 @@
},
"postcss-replace-overflow-wrap": {
"version": "4.0.0",
- "dev": true,
- "requires": {}
+ "dev": true
},
"postcss-selector-not": {
"version": "5.0.0",
@@ -16383,6 +16469,7 @@
},
"readdirp": {
"version": "3.6.0",
+ "dev": true,
"requires": {
"picomatch": "^2.2.1"
}
@@ -16554,7 +16641,7 @@
},
"safer-buffer": {
"version": "2.1.2",
- "devOptional": true
+ "dev": true
},
"sass": {
"version": "1.49.0",
@@ -16598,8 +16685,7 @@
},
"ajv-keywords": {
"version": "3.5.2",
- "dev": true,
- "requires": {}
+ "dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -16620,6 +16706,7 @@
},
"semver": {
"version": "7.3.5",
+ "dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
@@ -16865,7 +16952,8 @@
}
},
"sourcemap-codec": {
- "version": "1.4.8"
+ "version": "1.4.8",
+ "dev": true
},
"spdy": {
"version": "4.0.2",
@@ -17035,8 +17123,7 @@
},
"ajv-keywords": {
"version": "3.5.2",
- "dev": true,
- "requires": {}
+ "dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -17090,6 +17177,7 @@
},
"to-regex-range": {
"version": "5.0.1",
+ "dev": true,
"requires": {
"is-number": "^7.0.0"
}
@@ -17138,7 +17226,8 @@
"dev": true
},
"typescript": {
- "version": "4.5.5"
+ "version": "4.5.5",
+ "dev": true
},
"ua-parser-js": {
"version": "0.7.31",
@@ -17297,8 +17386,7 @@
},
"ajv-keywords": {
"version": "3.5.2",
- "dev": true,
- "requires": {}
+ "dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -17492,8 +17580,7 @@
},
"ws": {
"version": "8.2.3",
- "dev": true,
- "requires": {}
+ "dev": true
},
"xlsx": {
"version": "0.18.5",
@@ -17511,7 +17598,8 @@
"version": "5.0.8"
},
"yallist": {
- "version": "4.0.0"
+ "version": "4.0.0",
+ "dev": true
},
"yaml": {
"version": "1.10.2",
diff --git a/frontend/package.json b/frontend/package.json
index 1596072d..5d32208b 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -36,6 +36,7 @@
"d3-graphviz": "^2.6.1",
"file-saver": "^2.0.5",
"jquery": "^3.6.0",
+ "lodash.isequal": "^4.5.0",
"material-icons": "^1.10.8",
"mdb-angular-ui-kit": "^2.0.0",
"ng-multiselect-dropdown": "^0.3.8",
@@ -58,6 +59,7 @@
"@types/d3-graphviz": "^2.6.7",
"@types/file-saver": "^2.0.5",
"@types/jasmine": "~3.10.0",
+ "@types/lodash.isequal": "^4.5.6",
"@types/node": "^12.11.1",
"jasmine-core": "~4.0.0",
"karma": "~6.3.0",
diff --git a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts
index 89a76a44..7d21129c 100644
--- a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts
@@ -41,32 +41,33 @@ export class LineChartComponent implements AfterViewInit {
}
}
update(myEpochs: number[], myAcc: number[], myLoss: number[], myMae: number[], myMse: number[], myValAcc:number[],myValLoss:number[],myValMae:number[],myValMse:number[]) {
- this.dataAcc.length = 0;
- this.dataAcc.push(...myAcc);
-
+
this.dataEpoch.length = 0;
this.dataEpoch.push(...myEpochs);
- this.dataMAE.length = 0;
- this.dataMAE.push(...myMae);
+ this.dataAcc.length = 0;
+ this.dataAcc.push(...myAcc);
this.dataLOSS.length = 0;
this.dataLOSS.push(...myLoss);
- this.dataMSE.length = 0;
- this.dataMSE.push(...myValAcc);
+ this.dataMAE.length = 0;
+ this.dataMAE.push(...myMae);
this.dataMSE.length = 0;
- this.dataMSE.push(...myValLoss);
+ this.dataMSE.push(...myMse);
- this.dataMSE.length = 0;
- this.dataMSE.push(...myValMae);
+ this.dataValAcc.length = 0;
+ this.dataValAcc.push(...myValAcc);
- this.dataMSE.length = 0;
- this.dataMSE.push(...myValMse);
+ this.dataValLoss.length = 0;
+ this.dataValLoss.push(...myValLoss);
- this.dataMSE.length = 0;
- this.dataMSE.push(...myMse);
+ this.dataValMAE.length = 0;
+ this.dataValMAE.push(...myValMae);
+
+ this.dataValMSE.length = 0;
+ this.dataValMSE.push(...myValMse);
this.myChart.update();
}
@@ -89,7 +90,7 @@ export class LineChartComponent implements AfterViewInit {
},
{
label: 'Val_Accuracy',
- data: this.dataMSE,
+ data: this.dataValAcc,
borderWidth: 1
},
{
@@ -99,7 +100,7 @@ export class LineChartComponent implements AfterViewInit {
},
{
label: 'Val_Loss',
- data: this.dataMSE,
+ data: this.dataValLoss,
borderWidth: 1
},
{
@@ -109,7 +110,7 @@ export class LineChartComponent implements AfterViewInit {
},
{
label: 'Val_MAE',
- data: this.dataMSE,
+ data: this.dataValMAE,
borderWidth: 1
},
{
@@ -119,7 +120,7 @@ export class LineChartComponent implements AfterViewInit {
},
{
label: 'Val_MSE',
- data: this.dataMSE,
+ data: this.dataValMSE,
borderWidth: 1
}
]
diff --git a/frontend/src/app/_elements/column-table/column-table.component.ts b/frontend/src/app/_elements/column-table/column-table.component.ts
index fa418e23..9a8cbeee 100644
--- a/frontend/src/app/_elements/column-table/column-table.component.ts
+++ b/frontend/src/app/_elements/column-table/column-table.component.ts
@@ -85,7 +85,7 @@ export class ColumnTableComponent implements AfterViewInit {
loadDataset(dataset: Dataset) {
console.log("LOADED DATASET");
- if (this.route.snapshot.paramMap.get("id") == null) {
+ if (this.route.snapshot.paramMap.get("id") == null && this.route.snapshot.paramMap.get("predictorId") == null) {
this.dataset = dataset;
this.setColumnTypeInitial();
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.");
}
diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.html b/frontend/src/app/_elements/form-dataset/form-dataset.component.html
index 7be838f1..78bb4bd1 100644
--- a/frontend/src/app/_elements/form-dataset/form-dataset.component.html
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.html
@@ -1,49 +1,48 @@
<div class="folderBox" *ngIf="dataset">
-
- <div class="topBar">
- <div class="kolona mb-3">
- <div class="fileButton">
- <button type="button" mat-raised-button (click)="fileInput.click()"><span *ngIf="!firstInput">Dodaj izvor podataka</span><span *ngIf="firstInput">{{filename}}</span></button>
- </div>
- </div>
+ <div class="topBar">
+ <div class="kolona mb-3">
+ <div class="fileButton">
+ <button type="button" mat-raised-button (click)="fileInput.click()"><span *ngIf="!firstInput">Dodaj izvor podataka</span><span *ngIf="firstInput">{{filename}}</span></button>
+ </div>
+ </div>
- <div class="kolona">
- <div role="group">
- <mat-form-field class="example-full-width" appearance="fill">
- <mat-label>Naziv</mat-label>
- <input type="text" matInput value="{{dataset?.name}}" [(ngModel)]="dataset.name">
+ <div class="kolona">
+ <div role="group">
+ <mat-form-field class="example-full-width" appearance="fill">
+ <mat-label>Naziv</mat-label>
+ <input type="text" matInput value="{{dataset?.name}}" [(ngModel)]="dataset.name" (change)="editEvent.emit()">
- <mat-error *ngIf="nameFormControl.hasError('required')">
- Naziv je <strong>obavezan</strong>
- </mat-error>
- </mat-form-field>
- </div>
- </div>
- <div class="kolona">
- <mat-form-field appearance="fill">
- <mat-label>Delimiter</mat-label>
- <mat-select id="delimiterOptions" [(ngModel)]="dataset.delimiter" (selectionChange)="update()" value=",">
- <mat-option *ngFor="let option of delimiterOptions" [value]="option">
- {{ option }}
- </mat-option>
- </mat-select>
- </mat-form-field>
- </div>
+ <mat-error *ngIf="nameFormControl.hasError('required')">
+ Naziv je <strong>obavezan</strong>
+ </mat-error>
+ </mat-form-field>
+ </div>
+ </div>
+ <div class="kolona">
+ <mat-form-field appearance="fill">
+ <mat-label>Delimiter</mat-label>
+ <mat-select id="delimiterOptions" [(ngModel)]="dataset.delimiter" (selectionChange)="update(); editEvent.emit();" value=",">
+ <mat-option *ngFor="let option of delimiterOptions" [value]="option">
+ {{ option }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
</div>
-
+ </div>
+
<div class="row" style="margin-right: 0;">
<div class="file-container" [ngClass]="{'dottedClass': !tableData.hasInput}">
<i class="material-icons-outlined icon-display" [ngClass]="{'hidden': tableData.hasInput}">file_upload</i>
-
- <input class="file" id="file-upload" (change)="changeListener($event)" #fileInput type="file" accept=".csv">
+
+ <input class="file" id="file-upload" (change)="changeListener($event)" (valueChange)="dataset.isPreProcess = false; editEvent.emit()" #fileInput type="file" accept=".csv">
<div class="mt-5 datatable">
<div [ngClass]="{'hidden': (!existingFlag)}" class="text-center">
- <button mat-button (click)="goBack()"><mat-icon>keyboard_arrow_left</mat-icon></button>
+ <button mat-button (click)="goBack()"><mat-icon>keyboard_arrow_left</mat-icon></button>
<div style="display: inline;">{{(this.begin/10)+1}}...{{getPage()}}</div>
<button mat-button (click)="goForward()"><mat-icon>keyboard_arrow_right</mat-icon></button>
</div>
diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.ts b/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
index 19c0083c..35d68526 100644
--- a/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
@@ -24,11 +24,12 @@ export class FormDatasetComponent {
files: File[] = [];
rowsNumber: number = 0;
colsNumber: number = 0;
- begin:number=0;
- step:number=10;
- existingFlag:boolean=false;
+ begin: number = 0;
+ step: number = 10;
+ existingFlag: boolean = false;
@Input() dataset: Dataset; //dodaj ! potencijalno
+ @Output() editEvent = new EventEmitter();
tableData: TableData = new TableData();
@@ -43,31 +44,30 @@ export class FormDatasetComponent {
}
//@ViewChild('fileImportInput', { static: false }) fileImportInput: any; cemu je ovo sluzilo?
- resetPagging(){
- this.begin=0;
+ resetPagging() {
+ this.begin = 0;
}
- goBack(){
- if(this.begin-10<0)
- this.begin=0;
- else
- {
- this.begin-=10;
+ goBack() {
+ if (this.begin - 10 < 0)
+ this.begin = 0;
+ else {
+ this.begin -= 10;
this.loadExisting();
}
}
- goForward(){
- this.begin+=10;
- if(this.dataset.rowCount<this.begin)
- this.begin-=10;
+ goForward() {
+ this.begin += 10;
+ if (this.dataset.rowCount < this.begin)
+ this.begin -= 10;
else
this.loadExisting();
}
- clear(){
+ clear() {
this.tableData.hasInput = false;
}
- getPage(){
- return Math.ceil(this.dataset.rowCount/10)
+ getPage() {
+ return Math.ceil(this.dataset.rowCount / 10)
}
changeListener($event: any): void {
@@ -81,7 +81,7 @@ export class FormDatasetComponent {
this.filename = this.files[0].name;
this.tableData.loaded = false;
- this.existingFlag=false;
+ this.existingFlag = false;
this.update();
}
@@ -115,30 +115,30 @@ export class FormDatasetComponent {
this.dataset.name = this.filename.slice(0, this.filename.length - 4);
}
- loadExisting(){
- this.existingFlag=true;
+ loadExisting() {
+ this.existingFlag = true;
this.firstInput = false;
this.tableData.hasInput = true;
this.tableData.loaded = false;
- this.datasetsService.getDatasetHeader(this.dataset.fileId).subscribe((header: string | undefined)=>{
-
- this.datasetsService.getDatasetFilePaging(this.dataset.fileId,this.begin,this.step).subscribe((file: string | undefined) => {
- if (file) {
- this.tableData.loaded = true;
- this.tableData.numRows = this.dataset.rowCount;
- this.tableData.numCols = this.dataset.columnInfo.length;
- this.tableData.data = this.csv.csvToArray(header+'\n'+file, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "novi red") ? "\t" : this.dataset.delimiter);
-
- }
- else{
- this.begin-=10;
- this.loadExisting();
- }
+ this.datasetsService.getDatasetHeader(this.dataset.fileId).subscribe((header: string | undefined) => {
+
+ this.datasetsService.getDatasetFilePaging(this.dataset.fileId, this.begin, this.step).subscribe((file: string | undefined) => {
+ if (file) {
+ this.tableData.loaded = true;
+ this.tableData.numRows = this.dataset.rowCount;
+ this.tableData.numCols = this.dataset.columnInfo.length;
+ this.tableData.data = this.csv.csvToArray(header + '\n' + file, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "novi red") ? "\t" : this.dataset.delimiter);
+
+ }
+ else {
+ this.begin -= 10;
+ this.loadExisting();
+ }
+ });
});
- });
-
+
}
/*exportAsXLSX():void {
diff --git a/frontend/src/app/_elements/form-model/form-model.component.html b/frontend/src/app/_elements/form-model/form-model.component.html
index c7a9d5ca..bed69998 100644
--- a/frontend/src/app/_elements/form-model/form-model.component.html
+++ b/frontend/src/app/_elements/form-model/form-model.component.html
@@ -5,13 +5,13 @@
<div class="ns-col">
<mat-form-field class="example-full-width" appearance="fill" class="mat-fix">
<mat-label>Naziv</mat-label>
- <input type="text" matInput [(ngModel)]="newModel.name">
+ <input type="text" matInput [(ngModel)]="newModel.name" (valueChange)="editEvent.emit()">
</mat-form-field>
</div>
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Tip problema</mat-label>
- <mat-select [(ngModel)]="forProblemType" [disabled]="this.hideProblemType">
+ <mat-select [(ngModel)]="forProblemType" [disabled]="this.hideProblemType" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" [value]="option">
{{ optionName }}
</mat-option>
@@ -24,7 +24,7 @@
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Optimizacija</mat-label>
- <mat-select [(ngModel)]="newModel.optimizer">
+ <mat-select [(ngModel)]="newModel.optimizer" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)" [value]="option">
{{ optionName }}
</mat-option>
@@ -35,7 +35,7 @@
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Funkcija troška</mat-label>
- <mat-select [(ngModel)]="newModel.lossFunction">
+ <mat-select [(ngModel)]="newModel.lossFunction" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(lossFunctions[forProblemType]); let optionName of Object.values(lossFunctions[forProblemType])" [value]="option">
{{ optionName }}
</mat-option>
@@ -48,7 +48,7 @@
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Funkcija aktivacije izlaznog sloja</mat-label>
- <mat-select name="outputLayerActivationFunction" [(ngModel)]="newModel.outputLayerActivationFunction">
+ <mat-select name="outputLayerActivationFunction" [(ngModel)]="newModel.outputLayerActivationFunction" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" [value]="option">
{{ optionName }}
</mat-option>
@@ -58,7 +58,7 @@
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Stopa učenja</mat-label>
- <mat-select [(ngModel)]="newModel.learningRate">
+ <mat-select [(ngModel)]="newModel.learningRate" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(LearningRate); let optionName of Object.values(LearningRate)" [value]="option">
{{ optionName }}
</mat-option>
@@ -71,14 +71,14 @@
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Broj epoha</mat-label>
- <input type="number" matInput [(ngModel)]="newModel.epochs" min="1" max="1000">
+ <input type="number" matInput [(ngModel)]="newModel.epochs" min="1" max="1000" (valueChange)="editEvent.emit()">
</mat-form-field>
</div>
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Broj uzoraka po iteraciji</mat-label>
- <mat-select matNativeControl [(value)]="newModel.batchSize">
+ <mat-select matNativeControl [(value)]="newModel.batchSize" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(BatchSize); let optionName of Object.values(BatchSize)" [value]="option">{{option}}</mat-option>
</mat-select>
</mat-form-field>
@@ -102,7 +102,7 @@
</div>
<div class="slider-extended">
<div class="slider-pad"></div>
- <mat-slider class="slide" min="10" max="90" step="5" [(ngModel)]="testSetDistribution" (input)="updateTestSet($event)"></mat-slider>
+ <mat-slider class="slide" min="10" max="90" step="5" [(ngModel)]="testSetDistribution" (input)="updateTestSet($event)" (valueChange)="editEvent.emit()"></mat-slider>
<div class="slider-pad"></div>
</div>
<div>
@@ -110,13 +110,13 @@
</div>
<div class="slider-extended">
<div class="slider-pad"></div>
- <mat-slider class="slide" min="10" max="90" step="5" [(ngModel)]="validationSize" (input)="updateValidation($event)"></mat-slider>
+ <mat-slider class="slide" min="10" max="90" step="5" [(ngModel)]="validationSize" (input)="updateValidation($event)" (valueChange)="editEvent.emit()"></mat-slider>
<div class="slider-pad"></div>
</div>
</div>
<div class="d-flex justify-content-center mt-3">
- <mat-checkbox color="accent">Nasumični redosled podataka</mat-checkbox>
+ <mat-checkbox color="accent" (valueChange)="editEvent.emit()">Nasumični redosled podataka</mat-checkbox>
</div>
</div>
@@ -220,7 +220,7 @@
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Regularizacija</mat-label>
- <mat-select [(ngModel)]="newModel.layers[i].regularisation">
+ <mat-select [(ngModel)]="newModel.layers[i].regularisation" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(Regularisation); let optionName of Object.values(Regularisation)" [value]="option">
{{ optionName }}
</mat-option>
@@ -229,7 +229,7 @@
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Stopa regularizacije</mat-label>
- <mat-select [(ngModel)]="newModel.layers[i].regularisationRate">
+ <mat-select [(ngModel)]="newModel.layers[i].regularisationRate" (valueChange)="editEvent.emit()">
<mat-option *ngFor="let option of Object.keys(RegularisationRate); let optionName of Object.values(RegularisationRate)" [value]="option">
{{ optionName }}
</mat-option>
diff --git a/frontend/src/app/_elements/form-model/form-model.component.ts b/frontend/src/app/_elements/form-model/form-model.component.ts
index 9e6082c4..196d575b 100644
--- a/frontend/src/app/_elements/form-model/form-model.component.ts
+++ b/frontend/src/app/_elements/form-model/form-model.component.ts
@@ -24,6 +24,8 @@ export class FormModelComponent implements AfterViewInit {
this.forProblemType = ProblemType.BinaryClassification;
}
+ @Output() editEvent = new EventEmitter();
+
ngAfterViewInit(): void { }
selectFormControl = new FormControl('', Validators.required);
@@ -80,6 +82,7 @@ export class FormModelComponent implements AfterViewInit {
this.newModel.layers.splice(this.newModel.layers.length - 1, 1);
this.newModel.hiddenLayers -= 1;
this.updateGraph();
+ this.editEvent.emit();
}
}
@@ -89,6 +92,7 @@ export class FormModelComponent implements AfterViewInit {
this.newModel.hiddenLayers += 1;
this.updateGraph();
+ this.editEvent.emit();
}
}
@@ -100,6 +104,7 @@ export class FormModelComponent implements AfterViewInit {
if (this.newModel.layers[index].neurons > 1) {
this.newModel.layers[index].neurons -= 1;
this.updateGraph();
+ this.editEvent.emit();
}
}
@@ -107,6 +112,7 @@ export class FormModelComponent implements AfterViewInit {
if (this.newModel.layers[index].neurons < 18) {
this.newModel.layers[index].neurons += 1;
this.updateGraph();
+ this.editEvent.emit();
}
}
@@ -119,22 +125,26 @@ export class FormModelComponent implements AfterViewInit {
for (let i = 0; i < this.newModel.layers.length; i++) {
this.newModel.layers[i].activationFunction = this.selectedActivation;
}
+ this.editEvent.emit();
}
changeAllRegularisation() {
for (let i = 0; i < this.newModel.layers.length; i++) {
this.newModel.layers[i].regularisation = this.selectedRegularisation;
}
+ this.editEvent.emit();
}
changeAllRegularisationRate() {
for (let i = 0; i < this.newModel.layers.length; i++) {
this.newModel.layers[i].regularisationRate = this.selectedRegularisationRate;
}
+ this.editEvent.emit();
}
changeAllNumberOfNeurons() {
for (let i = 0; i < this.newModel.layers.length; i++) {
this.newModel.layers[i].neurons = this.selectedNumberOfNeurons;
- this.updateGraph();
}
+ this.updateGraph();
+ this.editEvent.emit();
}
updateTestSet(event: MatSliderChange) {
this.testSetDistribution = event.value!;
@@ -149,5 +159,6 @@ export class FormModelComponent implements AfterViewInit {
updateValidation(event: MatSliderChange) {
this.validationSize = event.value!;
+ this.editEvent.emit();
}
}
diff --git a/frontend/src/app/_elements/spinner/spinner.component.css b/frontend/src/app/_elements/spinner/spinner.component.css
new file mode 100644
index 00000000..78adc872
--- /dev/null
+++ b/frontend/src/app/_elements/spinner/spinner.component.css
@@ -0,0 +1,78 @@
+.wrap {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.loader {
+ color: #ffffff;
+ font-size: 20px;
+ margin: auto;
+ width: 1em;
+ height: 1em;
+ border-radius: 50%;
+ text-indent: -9999em;
+ -webkit-animation: load4 1.3s infinite linear;
+ animation: load4 1.3s infinite linear;
+ -webkit-transform: scale(0.2);
+ -ms-transform: scale(0.2);
+ transform: scale(0.2);
+}
+
+@-webkit-keyframes load4 {
+ 0%,
+ 100% {
+ box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0;
+ }
+ 12.5% {
+ box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
+ }
+ 25% {
+ box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
+ }
+ 37.5% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
+ }
+ 50% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
+ }
+ 62.5% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
+ }
+ 75% {
+ box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
+ }
+ 87.5% {
+ box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
+ }
+}
+
+@keyframes load4 {
+ 0%,
+ 100% {
+ box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0;
+ }
+ 12.5% {
+ box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
+ }
+ 25% {
+ box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0, 0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
+ }
+ 37.5% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
+ }
+ 50% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
+ }
+ 62.5% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
+ }
+ 75% {
+ box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
+ }
+ 87.5% {
+ box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
+ }
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/spinner/spinner.component.html b/frontend/src/app/_elements/spinner/spinner.component.html
new file mode 100644
index 00000000..c655abf0
--- /dev/null
+++ b/frontend/src/app/_elements/spinner/spinner.component.html
@@ -0,0 +1,3 @@
+<div class="wrap">
+ <div class="loader">Loading...</div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/spinner/spinner.component.spec.ts b/frontend/src/app/_elements/spinner/spinner.component.spec.ts
new file mode 100644
index 00000000..061f78d5
--- /dev/null
+++ b/frontend/src/app/_elements/spinner/spinner.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SpinnerComponent } from './spinner.component';
+
+describe('SpinnerComponent', () => {
+ let component: SpinnerComponent;
+ let fixture: ComponentFixture<SpinnerComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ SpinnerComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SpinnerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/spinner/spinner.component.ts b/frontend/src/app/_elements/spinner/spinner.component.ts
new file mode 100644
index 00000000..f0080edd
--- /dev/null
+++ b/frontend/src/app/_elements/spinner/spinner.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-spinner',
+ templateUrl: './spinner.component.html',
+ styleUrls: ['./spinner.component.css']
+})
+export class SpinnerComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit(): void {
+ }
+
+}
diff --git a/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.css b/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.css
index e69de29b..e99a1e1e 100644
--- a/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.css
+++ b/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.css
@@ -0,0 +1,8 @@
+#btnYes {
+ background-color: var(--offwhite);
+ color: var(--ns-bg-dark-100);
+}
+
+#btnNo {
+ color: gray;
+} \ No newline at end of file
diff --git a/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.html b/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.html
index 77e7be42..259aec0d 100644
--- a/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.html
+++ b/frontend/src/app/_modals/yes-no-dialog/yes-no-dialog.component.html
@@ -1,10 +1,10 @@
-<h2 mat-dialog-title class="text-muted">{{data.title}}</h2>
-<div mat-dialog-content class="mt-4" style="color: rgb(81, 76, 76);">
+<h2 mat-dialog-title class="text-center">{{data.title}}</h2>
+<div mat-dialog-content class="mt-5 mb-4 mx-1">
<form (keydown)="withEnterKey($event)">
{{data.message}}
</form>
</div>
<div mat-dialog-actions class="d-flex justify-content-center mt-4">
- <button mat-button cdkFocusInitial (click)="onYesClick()" style="background-color: lightgray;">Da</button>
- <button mat-button cdkFocusInitial (click)="onNoClick()" style="background-color: lightgray;">Ne</button>
+ <button id="btnYes" mat-stroked-button color="basic" (click)="onYesClick()" style="background-color: lightgray;">Da</button>
+ <button id="btnNo" mat-stroked-button (click)="onNoClick()" style="background-color: lightgray;">Ne</button>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/experiment/experiment.component.ts b/frontend/src/app/_pages/experiment/experiment.component.ts
index 6c8e96b3..7cb5e7cd 100644
--- a/frontend/src/app/_pages/experiment/experiment.component.ts
+++ b/frontend/src/app/_pages/experiment/experiment.component.ts
@@ -21,7 +21,7 @@ import { PredictorsService } from 'src/app/_services/predictors.service';
templateUrl: './experiment.component.html',
styleUrls: ['./experiment.component.css']
})
-export class ExperimentComponent implements AfterViewInit, OnInit {
+export class ExperimentComponent implements AfterViewInit {
@ViewChild(MatStepper) stepper!: MatStepper;
@ViewChild('stepsContainer') stepsContainer!: ElementRef;
@@ -44,46 +44,6 @@ export class ExperimentComponent implements AfterViewInit, OnInit {
this.experiment = new Experiment("exp1");
}
- ngOnInit(): void {
- this.route.queryParams.subscribe(params => {
-
- let experimentId = this.route.snapshot.paramMap.get("id");
- let predictorId = this.route.snapshot.paramMap.get("predictorId");
-
- if (predictorId != null && experimentId != null) {
- this.experimentsService.getExperimentById(experimentId).subscribe((response) => {
- this.experiment = response;
- this.datasetsService.getDatasetById(this.experiment.datasetId).subscribe((response: Dataset) => {
- this.dataset = response;
- this.folderDataset.forExperiment = this.experiment;
- this.folderDataset.selectFile(this.dataset); //sad 3. i 4. korak da se ucitaju
-
- //this.predictorsService.getPredictor(predictorId!).subscribe((response) => {
- let predictor = response;
- //this.modelsService.getModelById(predictor.modelId).subscribe((response) => {
- this.modelsService.getModelById("62853d70696d62ceeb8db7cd").subscribe((response) => {
- //imamo model
- this.folderModel.formModel.newModel = response;
- //this.metricView.update(predictor.metrics);
- });
- //});
- });
- });
- }
- else if (predictorId == null && experimentId != null) {
- this.experimentsService.getExperimentById(experimentId).subscribe((response) => {
- this.experiment = response;
- this.datasetsService.getDatasetById(this.experiment.datasetId).subscribe((response: Dataset) => {
- this.dataset = response;
- this.folderDataset.forExperiment = this.experiment;
- this.folderDataset.selectFile(this.dataset);
- });
- });
- }
-
- });
- }
-
/*updateExperiment(){
}*/
@@ -136,6 +96,52 @@ export class ExperimentComponent implements AfterViewInit, OnInit {
});
}
+
+ this.route.queryParams.subscribe(params => {
+
+ let experimentId = this.route.snapshot.paramMap.get("id");
+ let predictorId = this.route.snapshot.paramMap.get("predictorId");
+ console.log("paramexp: ", experimentId, ", parampredictor: ", predictorId);
+ if (predictorId != null) {
+ this.predictorsService.getPredictor(predictorId!).subscribe((response) => {
+ let predictor = response;
+ //console.log("predictor: ", predictor);
+ this.experimentsService.getExperimentById(predictor.experimentId).subscribe((response) => {
+ this.experiment = response;
+ //console.log("experiment: ", this.experiment);
+ this.datasetsService.getDatasetById(this.experiment.datasetId).subscribe((response: Dataset) => {
+ this.dataset = response;
+ //console.log("dataset: ", this.dataset);
+ this.folderDataset.forExperiment = this.experiment;
+ this.folderDataset.selectFile(this.dataset); //sad 3. i 4. korak da se ucitaju
+
+ this.modelsService.getModelById(predictor.modelId).subscribe((response) => {
+ let model = response;
+ //console.log("model: ", model);
+ this.folderModel.formModel.newModel = model;
+ this.step3 = true;
+ let numOfEpochsArray = Array.from({length: model.epochs}, (_, i) => i + 1);
+ //console.log("metric view1:", this.metricView);
+ setTimeout(() => {
+ this.metricView.linechartComponent.update(numOfEpochsArray, predictor.metricsAcc, predictor.metricsLoss, predictor.metricsMae, predictor.metricsMse, predictor.metricsValAcc, predictor.metricsValLoss, predictor.metricsValMae, predictor.metricsValMse);
+ })
+ });
+ });
+ });
+ });
+ }
+ else if (experimentId != null) {
+ this.experimentsService.getExperimentById(experimentId).subscribe((response) => {
+ this.experiment = response;
+ this.datasetsService.getDatasetById(this.experiment.datasetId).subscribe((response: Dataset) => {
+ this.dataset = response;
+ this.folderDataset.forExperiment = this.experiment;
+ this.folderDataset.selectFile(this.dataset);
+ });
+ });
+ }
+
+ });
}
history: any[] = [];
diff --git a/frontend/src/app/_pages/my-models/my-models.component.html b/frontend/src/app/_pages/my-models/my-models.component.html
deleted file mode 100644
index 9b281239..00000000
--- a/frontend/src/app/_pages/my-models/my-models.component.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<div id="header">
- <h1>Moji modeli</h1>
-</div>
-<div id="wrapper">
- <div id="container" class="container p-5" style="background-color: rgba(255, 255, 255, 0.8); min-height: 100%;">
- <div class="row mt-3 mb-2 d-flex justify-content-center">
-
- <div class="col-sm-6" style="margin-bottom: 10px;">
- </div>
-
- <div class="row">
- <div class="col-sm-4" style="margin-bottom: 10px;" *ngFor="let model of myModels">
- <app-item-model [model]="model"></app-item-model>
-
- <div class="panel-footer row"><!-- panel-footer -->
- <div class="col-xs-6 text-center">
- <div>
- <button type="button" class="btn btn-default btn-lg"style="min-width: 7rem;float: left;" (click)="useThisModel(model)" mat-raised-button color="primary">Koristi
- <span class="glyphicon glyphicon-search"></span>
- </button>
- <button (click)="deleteThisModel(model)" mat-raised-button color="warn" style="min-width: 7rem;float: right" ><mat-icon>delete</mat-icon></button>
-
-
- </div>
- </div>
- </div><!-- end panel-footer -->
-
-
-
- </div>
- </div>
- <div class="text-center" *ngIf="this.myModels.length == 0" >
- <h2>Nema rezultata</h2>
- </div>
- </div>
-
- </div>
-
-
-
-
-
- </div>
diff --git a/frontend/src/app/_pages/my-models/my-models.component.ts b/frontend/src/app/_pages/my-models/my-models.component.ts
deleted file mode 100644
index d379fa69..00000000
--- a/frontend/src/app/_pages/my-models/my-models.component.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { Router } from '@angular/router';
-import shared from 'src/app/Shared';
-import Model from 'src/app/_data/Model';
-import { ModelsService } from 'src/app/_services/models.service';
-
-@Component({
- selector: 'app-my-models',
- templateUrl: './my-models.component.html',
- styleUrls: ['./my-models.component.css']
-})
-export class MyModelsComponent implements OnInit {
- myModels: Model[] = [];
- //myModel: Model;
-
- constructor(private modelsS : ModelsService, private router : Router) {
-
-
-
- }
-
- ngOnInit(): void {
- this.getAllMyModels();
-
- }
-/*
- editModel(): void{
- this.modelsS.editModel().subscribe(m => {
- this.myModel = m;
-
- })
- }
-*/
-
-deleteThisModel(model: Model): void{
- shared.openYesNoDialog('Brisanje seta podataka','Da li ste sigurni da želite da obrišete model?',() => {
- this.modelsS.deleteModel(model).subscribe((response) => {
- this.getAllMyModels();
- }, (error) =>{
- if (error.error == "Model with name = {name} deleted") {
- shared.openDialog("Obaveštenje", "Greška prilikom brisanja modela.");
- }
- });
- });
-}
-
-
-useThisModel(model: Model): void{
-
- this.router.navigate(['/training'])
-
-}
- getAllMyModels(): void{
- this.modelsS.getMyModels().subscribe(m => {
- this.myModels = m;
- });
- }
-
-}
diff --git a/frontend/src/app/_services/experiments.service.ts b/frontend/src/app/_services/experiments.service.ts
index f4473c8c..4b209ff0 100644
--- a/frontend/src/app/_services/experiments.service.ts
+++ b/frontend/src/app/_services/experiments.service.ts
@@ -27,4 +27,8 @@ export class ExperimentsService {
updateExperiment(experiment: Experiment): Observable<Experiment> {
return this.http.put<Experiment>(`${Configuration.settings.apiURL}/experiment/` + experiment._id, experiment, { headers: this.authService.authHeader() });
}
+
+ deleteExperiment(experiment: Experiment) {
+ return this.http.delete(`${Configuration.settings.apiURL}/experiment/` + experiment._id, { headers: this.authService.authHeader(), responseType: "text" });
+ }
}
diff --git a/frontend/src/app/_services/models.service.ts b/frontend/src/app/_services/models.service.ts
index f5d95ec1..2b8fe8f2 100644
--- a/frontend/src/app/_services/models.service.ts
+++ b/frontend/src/app/_services/models.service.ts
@@ -51,7 +51,7 @@ export class ModelsService {
}
editModel(model: Model): Observable<Model> {
- return this.http.put<Model>(`${Configuration.settings.apiURL}/model/`, model, { headers: this.authService.authHeader() });
+ return this.http.put<Model>(`${Configuration.settings.apiURL}/model/` + model.name, model, { headers: this.authService.authHeader() });
}
deleteModel(model: Model) {
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 56442842..d5552ce9 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -12,7 +12,7 @@ import { TestComponent } from './_pages/test/test.component';
const routes: Routes = [
{ path: '', component: HomeComponent, data: { title: 'Početna strana' } },
- { path: 'experiment/:id/:predictorId', component: ExperimentComponent, data: { title: 'Eksperiment' } },
+ { path: 'experiment/p/:predictorId', component: ExperimentComponent, data: { title: 'Eksperiment' } },
{ path: 'experiment/:id', component: ExperimentComponent, data: { title: 'Eksperiment' } },
{ path: 'experiment', component: ExperimentComponent, data: { title: 'Eksperiment' } },
{ path: 'archive', component: ArchiveComponent, data: { title: 'Arhiva' } },
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index d44bf6ad..89d53115 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -52,6 +52,7 @@ import { DoughnutChartComponent } from './_elements/_charts/doughnut-chart/dough
import { HeatmapComponent } from './_elements/_charts/heatmap/heatmap.component';
import { HeatMapAllModule } from '@syncfusion/ej2-angular-heatmap';
import { MetricViewComponent } from './_elements/metric-view/metric-view.component';
+import { SpinnerComponent } from './_elements/spinner/spinner.component';
export function initializeApp(appConfig: Configuration) {
return () => appConfig.load();
@@ -91,7 +92,8 @@ export function initializeApp(appConfig: Configuration) {
HeatmapComponent,
MetricViewComponent,
LineChartComponent,
- SaveExperimentDialogComponent
+ SaveExperimentDialogComponent,
+ SpinnerComponent
],
imports: [
BrowserModule,