aboutsummaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'frontend')
-rw-r--r--frontend/angular.json211
-rw-r--r--frontend/package-lock.json339
-rw-r--r--frontend/package.json8
-rw-r--r--frontend/src/app/Shared.ts12
-rw-r--r--frontend/src/app/_data/Dataset.ts18
-rw-r--r--frontend/src/app/_data/Experiment.ts3
-rw-r--r--frontend/src/app/_data/FolderFile.ts13
-rw-r--r--frontend/src/app/_data/Model.ts73
-rw-r--r--frontend/src/app/_elements/_charts/barchart/barchart.component.css (renamed from frontend/src/app/barchart/barchart.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/barchart/barchart.component.html (renamed from frontend/src/app/barchart/barchart.component.html)0
-rw-r--r--frontend/src/app/_elements/_charts/barchart/barchart.component.spec.ts (renamed from frontend/src/app/barchart/barchart.component.spec.ts)0
-rw-r--r--frontend/src/app/_elements/_charts/barchart/barchart.component.ts (renamed from frontend/src/app/barchart/barchart.component.ts)1
-rw-r--r--frontend/src/app/_elements/_charts/box-plot/box-plot.component.css (renamed from frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/box-plot/box-plot.component.html3
-rw-r--r--frontend/src/app/_elements/_charts/box-plot/box-plot.component.spec.ts (renamed from frontend/src/app/training/training.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts102
-rw-r--r--frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.css (renamed from frontend/src/app/_elements/carousel/carousel.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.html1
-rw-r--r--frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.spec.ts (renamed from frontend/src/app/_elements/item-predictor/item-predictor.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.ts37
-rw-r--r--frontend/src/app/_elements/_charts/heatmap/heatmap.component.css (renamed from frontend/src/app/_elements/item-experiment/item-experiment.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/heatmap/heatmap.component.html3
-rw-r--r--frontend/src/app/_elements/_charts/heatmap/heatmap.component.spec.ts (renamed from frontend/src/app/_pages/predict/predict.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/_charts/heatmap/heatmap.component.ts108
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.css (renamed from frontend/src/app/_elements/item-predictor/item-predictor.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.html5
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.spec.ts (renamed from frontend/src/app/_elements/annvisual/annvisual.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts88
-rw-r--r--frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.css (renamed from frontend/src/app/_pages/browse-datasets/browse-datasets.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.html2
-rw-r--r--frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.ts56
-rw-r--r--frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.css (renamed from frontend/src/app/_pages/filter-datasets/filter-datasets.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.html3
-rw-r--r--frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.spec.ts (renamed from frontend/src/app/_pages/my-models/my-models.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts46
-rw-r--r--frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.css0
-rw-r--r--frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.html2
-rw-r--r--frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.spec.ts (renamed from frontend/src/app/_elements/item-experiment/item-experiment.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.ts57
-rw-r--r--frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css (renamed from frontend/src/app/scatterchart/scatterchart.component.css)0
-rw-r--r--frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html (renamed from frontend/src/app/scatterchart/scatterchart.component.html)0
-rw-r--r--frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.spec.ts (renamed from frontend/src/app/scatterchart/scatterchart.component.spec.ts)0
-rw-r--r--frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.ts (renamed from frontend/src/app/scatterchart/scatterchart.component.ts)0
-rw-r--r--frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html49
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.css4
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.html5
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.ts45
-rw-r--r--frontend/src/app/_elements/carousel/carousel.component.html17
-rw-r--r--frontend/src/app/_elements/carousel/carousel.component.ts18
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.css223
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.html243
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.spec.ts (renamed from frontend/src/app/_elements/item-dataset/item-dataset.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.ts250
-rw-r--r--frontend/src/app/_elements/dataset-load/dataset-load.component.css18
-rw-r--r--frontend/src/app/_elements/dataset-load/dataset-load.component.html40
-rw-r--r--frontend/src/app/_elements/datatable/datatable.component.html30
-rw-r--r--frontend/src/app/_elements/folder/folder.component.css189
-rw-r--r--frontend/src/app/_elements/folder/folder.component.html99
-rw-r--r--frontend/src/app/_elements/folder/folder.component.spec.ts (renamed from frontend/src/app/_elements/carousel/carousel.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/folder/folder.component.ts276
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.css69
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.html74
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.spec.ts (renamed from frontend/src/app/_elements/dataset-load/dataset-load.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.ts (renamed from frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.ts)34
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.css87
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.html202
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.spec.ts (renamed from frontend/src/app/_elements/item-model/item-model.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.ts138
-rw-r--r--frontend/src/app/_elements/gradient-background/gradient-background.component.css0
-rw-r--r--frontend/src/app/_elements/gradient-background/gradient-background.component.html1
-rw-r--r--frontend/src/app/_elements/gradient-background/gradient-background.component.spec.ts (renamed from frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/gradient-background/gradient-background.component.ts47
-rw-r--r--frontend/src/app/_elements/graph/graph.component.css17
-rw-r--r--frontend/src/app/_elements/graph/graph.component.html11
-rw-r--r--frontend/src/app/_elements/graph/graph.component.ts84
-rw-r--r--frontend/src/app/_elements/item-dataset/item-dataset.component.css23
-rw-r--r--frontend/src/app/_elements/item-dataset/item-dataset.component.html41
-rw-r--r--frontend/src/app/_elements/item-dataset/item-dataset.component.ts40
-rw-r--r--frontend/src/app/_elements/item-experiment/item-experiment.component.html10
-rw-r--r--frontend/src/app/_elements/item-experiment/item-experiment.component.ts15
-rw-r--r--frontend/src/app/_elements/item-model/item-model.component.css23
-rw-r--r--frontend/src/app/_elements/item-model/item-model.component.html58
-rw-r--r--frontend/src/app/_elements/item-model/item-model.component.ts33
-rw-r--r--frontend/src/app/_elements/item-predictor/item-predictor.component.html35
-rw-r--r--frontend/src/app/_elements/item-predictor/item-predictor.component.ts23
-rw-r--r--frontend/src/app/_elements/metric-view/metric-view.component.css0
-rw-r--r--frontend/src/app/_elements/metric-view/metric-view.component.html3
-rw-r--r--frontend/src/app/_elements/metric-view/metric-view.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/metric-view/metric-view.component.ts49
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.css17
-rw-r--r--frontend/src/app/_elements/navbar/navbar.component.css8
-rw-r--r--frontend/src/app/_elements/navbar/navbar.component.html34
-rw-r--r--frontend/src/app/_elements/navbar/navbar.component.ts5
-rw-r--r--frontend/src/app/_elements/notifications/notifications.component.ts1
-rw-r--r--frontend/src/app/_elements/playlist/playlist.component.css61
-rw-r--r--frontend/src/app/_elements/playlist/playlist.component.html19
-rw-r--r--frontend/src/app/_elements/playlist/playlist.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/playlist/playlist.component.ts49
-rw-r--r--frontend/src/app/_elements/reactive-background/reactive-background.component.html2
-rw-r--r--frontend/src/app/_elements/reactive-background/reactive-background.component.ts166
-rw-r--r--frontend/src/app/_modals/alert-dialog/alert-dialog.component.css3
-rw-r--r--frontend/src/app/_modals/alert-dialog/alert-dialog.component.html16
-rw-r--r--frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css0
-rw-r--r--frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html16
-rw-r--r--frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.spec.ts (renamed from frontend/src/app/_pages/browse-datasets/browse-datasets.component.spec.ts)12
-rw-r--r--frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts28
-rw-r--r--frontend/src/app/_modals/login-modal/login-modal.component.css37
-rw-r--r--frontend/src/app/_modals/login-modal/login-modal.component.html79
-rw-r--r--frontend/src/app/_modals/login-modal/login-modal.component.ts19
-rw-r--r--frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css0
-rw-r--r--frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html13
-rw-r--r--frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.spec.ts25
-rw-r--r--frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts28
-rw-r--r--frontend/src/app/_modals/register-modal/register-modal.component.css44
-rw-r--r--frontend/src/app/_modals/register-modal/register-modal.component.html159
-rw-r--r--frontend/src/app/_modals/register-modal/register-modal.component.ts47
-rw-r--r--frontend/src/app/_pages/archive/archive.component.css0
-rw-r--r--frontend/src/app/_pages/archive/archive.component.html49
-rw-r--r--frontend/src/app/_pages/archive/archive.component.spec.ts25
-rw-r--r--frontend/src/app/_pages/archive/archive.component.ts25
-rw-r--r--frontend/src/app/_pages/browse-datasets/browse-datasets.component.html1
-rw-r--r--frontend/src/app/_pages/browse-datasets/browse-datasets.component.ts15
-rw-r--r--frontend/src/app/_pages/browse-predictors/browse-predictors.component.css7
-rw-r--r--frontend/src/app/_pages/browse-predictors/browse-predictors.component.html40
-rw-r--r--frontend/src/app/_pages/browse-predictors/browse-predictors.component.spec.ts25
-rw-r--r--frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts26
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.css55
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.html40
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.spec.ts (renamed from frontend/src/app/experiment/experiment.component.spec.ts)0
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.ts95
-rw-r--r--frontend/src/app/_pages/filter-datasets/filter-datasets.component.html38
-rw-r--r--frontend/src/app/_pages/filter-datasets/filter-datasets.component.spec.ts25
-rw-r--r--frontend/src/app/_pages/home/home.component.css20
-rw-r--r--frontend/src/app/_pages/home/home.component.html76
-rw-r--r--frontend/src/app/_pages/home/home.component.ts5
-rw-r--r--frontend/src/app/_pages/my-datasets/my-datasets.component.css8
-rw-r--r--frontend/src/app/_pages/my-datasets/my-datasets.component.html39
-rw-r--r--frontend/src/app/_pages/my-datasets/my-datasets.component.spec.ts25
-rw-r--r--frontend/src/app/_pages/my-datasets/my-datasets.component.ts63
-rw-r--r--frontend/src/app/_pages/my-models/my-models.component.css12
-rw-r--r--frontend/src/app/_pages/my-predictors/my-predictors.component.css13
-rw-r--r--frontend/src/app/_pages/my-predictors/my-predictors.component.html23
-rw-r--r--frontend/src/app/_pages/my-predictors/my-predictors.component.spec.ts25
-rw-r--r--frontend/src/app/_pages/my-predictors/my-predictors.component.ts43
-rw-r--r--frontend/src/app/_pages/playground/playground.component.css0
-rw-r--r--frontend/src/app/_pages/playground/playground.component.html18
-rw-r--r--frontend/src/app/_pages/playground/playground.component.spec.ts (renamed from frontend/src/app/_elements/model-load/model-load.component.spec.ts)12
-rw-r--r--frontend/src/app/_pages/playground/playground.component.ts35
-rw-r--r--frontend/src/app/_pages/predict/predict.component.css3
-rw-r--r--frontend/src/app/_pages/predict/predict.component.html73
-rw-r--r--frontend/src/app/_pages/predict/predict.component.ts45
-rw-r--r--frontend/src/app/_pages/profile/profile.component.css51
-rw-r--r--frontend/src/app/_pages/profile/profile.component.html66
-rw-r--r--frontend/src/app/_pages/test/test.component.css0
-rw-r--r--frontend/src/app/_pages/test/test.component.html5
-rw-r--r--frontend/src/app/_pages/test/test.component.spec.ts25
-rw-r--r--frontend/src/app/_pages/test/test.component.ts15
-rw-r--r--frontend/src/app/_services/auth.service.ts7
-rw-r--r--frontend/src/app/_services/configuration.service.spec.ts (renamed from frontend/src/app/configuration.service.spec.ts)2
-rw-r--r--frontend/src/app/_services/configuration.service.ts (renamed from frontend/src/app/configuration.service.ts)2
-rw-r--r--frontend/src/app/_services/datasets.service.ts5
-rw-r--r--frontend/src/app/_services/experiments.service.ts2
-rw-r--r--frontend/src/app/_services/models.service.ts2
-rw-r--r--frontend/src/app/_services/predictors.service.ts10
-rw-r--r--frontend/src/app/_services/signal-r.service.ts2
-rw-r--r--frontend/src/app/_services/user-info.service.ts2
-rw-r--r--frontend/src/app/app-routing.module.ts32
-rw-r--r--frontend/src/app/app.component.html17
-rw-r--r--frontend/src/app/app.component.ts32
-rw-r--r--frontend/src/app/app.module.ts95
-rw-r--r--frontend/src/app/experiment/experiment.component.css43
-rw-r--r--frontend/src/app/material.module.ts119
-rw-r--r--frontend/src/app/training/training.component.css39
-rw-r--r--frontend/src/app/training/training.component.ts55
-rw-r--r--frontend/src/assets/images/add_model_background.jpgbin56906 -> 0 bytes
-rw-r--r--frontend/src/assets/images/logo.pngbin13315 -> 11962 bytes
-rw-r--r--frontend/src/assets/images/logo_igrannonica_temp - Copy.pngbin0 -> 16336 bytes
-rw-r--r--frontend/src/assets/images/logo_igrannonica_temp.pngbin0 -> 29448 bytes
-rw-r--r--frontend/src/custom-theme.scss267
-rw-r--r--frontend/src/styles.css10
-rw-r--r--frontend/src/styles/fx.css24
-rw-r--r--frontend/src/styles/helper.css144
-rw-r--r--frontend/src/styles/layout.css78
-rw-r--r--frontend/src/styles/scrollbar.css28
-rw-r--r--frontend/src/styles/theme.css68
186 files changed, 5189 insertions, 1971 deletions
diff --git a/frontend/angular.json b/frontend/angular.json
index 6653e4b1..13c27f40 100644
--- a/frontend/angular.json
+++ b/frontend/angular.json
@@ -1,112 +1,113 @@
{
- "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
- "version": 1,
- "newProjectRoot": "projects",
- "projects": {
- "frontend": {
- "projectType": "application",
- "schematics": {
- "@schematics/angular:application": {
- "strict": true
- }
- },
- "root": "",
- "sourceRoot": "src",
- "prefix": "app",
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "outputPath": "dist/frontend",
- "index": "src/index.html",
- "main": "src/main.ts",
- "polyfills": "src/polyfills.ts",
- "tsConfig": "tsconfig.app.json",
- "assets": [
- "src/favicon.ico",
- "src/assets"
- ],
- "styles": [
- "src/custom-theme.scss",
- "node_modules/bootstrap/dist/css/bootstrap.min.css",
- "src/styles.css",
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
- ],
- "scripts": [
- "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
- ]
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "2mb",
- "maximumError": "4mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "10kb",
- "maximumError": "15kb"
- }
- ],
- "fileReplacements": [
- {
- "replace": "src/environments/environment.ts",
- "with": "src/environments/environment.prod.ts"
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "frontend": {
+ "projectType": "application",
+ "schematics": {
+ "@schematics/angular:application": {
+ "strict": true
}
- ],
- "outputHashing": "all"
- },
- "development": {
- "buildOptimizer": false,
- "optimization": false,
- "vendorChunk": true,
- "extractLicenses": false,
- "sourceMap": true,
- "namedChunks": true
- }
- },
- "defaultConfiguration": "production"
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "configurations": {
- "production": {
- "browserTarget": "frontend:build:production"
},
- "development": {
- "browserTarget": "frontend:build:development"
+ "root": "",
+ "sourceRoot": "src",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "outputPath": "dist/frontend",
+ "index": "src/index.html",
+ "main": "src/main.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.app.json",
+ "assets": [
+ "src/favicon.ico",
+ "src/assets"
+ ],
+ "styles": [
+ "node_modules/bootstrap/dist/css/bootstrap.min.css",
+ "src/styles.css",
+ "src/custom-theme.scss"
+ ],
+ "scripts": [
+ "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
+ ]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [{
+ "type": "initial",
+ "maximumWarning": "2mb",
+ "maximumError": "4mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "10kb",
+ "maximumError": "15kb"
+ }
+ ],
+ "fileReplacements": [{
+ "replace": "src/environments/environment.ts",
+ "with": "src/environments/environment.prod.ts"
+ }],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "browserTarget": "frontend:build:production"
+ },
+ "development": {
+ "browserTarget": "frontend:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "frontend:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "src/test.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.spec.json",
+ "karmaConfig": "karma.conf.js",
+ "assets": [
+ "src/favicon.ico",
+ "src/assets"
+ ],
+ "styles": [
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
+ "src/styles.css"
+ ],
+ "scripts": []
+ }
+ }
}
- },
- "defaultConfiguration": "development"
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "frontend:build"
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "src/test.ts",
- "polyfills": "src/polyfills.ts",
- "tsConfig": "tsconfig.spec.json",
- "karmaConfig": "karma.conf.js",
- "assets": [
- "src/favicon.ico",
- "src/assets"
- ],
- "styles": [
- "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
- "src/styles.css"
- ],
- "scripts": []
- }
}
- }
+ },
+ "defaultProject": "frontend",
+ "cli": {
+ "warnings": {
+ "versionMismatch": false
+ }
}
- },
- "defaultProject": "frontend"
} \ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 488653db..7f6dbdde 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -10,13 +10,13 @@
"hasInstallScript": true,
"dependencies": {
"@angular/animations": "~13.2.0",
- "@angular/cdk": "^13.2.6",
+ "@angular/cdk": "^13.3.4",
"@angular/common": "~13.2.0",
"@angular/compiler": "~13.2.0",
"@angular/core": "~13.2.0",
"@angular/forms": "~13.2.0",
"@angular/localize": "~13.2.0",
- "@angular/material": "^13.2.6",
+ "@angular/material": "^13.3.4",
"@angular/platform-browser": "~13.2.0",
"@angular/platform-browser-dynamic": "~13.2.0",
"@angular/router": "~13.2.0",
@@ -24,11 +24,15 @@
"@microsoft/signalr": "^6.0.4",
"@ng-bootstrap/ng-bootstrap": "^12.0.0",
"@popperjs/core": "^2.10.2",
+ "@sgratzl/chartjs-chart-boxplot": "^3.7.1",
+ "@syncfusion/ej2-angular-heatmap": "^20.1.47",
"bootstrap": "^5.1.3",
+ "chart.heatmap.js": "^0.0.1-alpha",
"chart.js": "^3.7.1",
"csv-parser": "^3.0.0",
"d3-graphviz": "^2.6.1",
"jquery": "^3.6.0",
+ "material-icons": "^1.10.8",
"mdb-angular-ui-kit": "^2.0.0",
"ng-multiselect-dropdown": "^0.3.8",
"ng-uikit-pro-standard": "^1.0.0",
@@ -351,9 +355,9 @@
"dev": true
},
"node_modules/@angular/animations": {
- "version": "13.2.6",
- "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.2.6.tgz",
- "integrity": "sha512-DrjpKo68uR3lSLQQXosoTCbjKQS6IKRCpR14E2t8fo0AX8i2hkB8je4SrhdCyB7FgFN7l2kgUYo4Qa8+BOB+aA==",
+ "version": "13.2.7",
+ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.2.7.tgz",
+ "integrity": "sha512-FthGqRPQ1AOcOx/NIW65xeFYkQZJ7PpXcX59Kt+qkoUzngAQEY+UUpOteG52tmL0iZSVwOCjtxRFi9w4heVgEg==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -361,13 +365,13 @@
"node": "^12.20.0 || ^14.15.0 || >=16.10.0"
},
"peerDependencies": {
- "@angular/core": "13.2.6"
+ "@angular/core": "13.2.7"
}
},
"node_modules/@angular/cdk": {
- "version": "13.2.6",
- "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.2.6.tgz",
- "integrity": "sha512-epuXmaHqfukwPsYvIksbuHLXDtb6GALV2Vgv6W2asj4TorD584CeQTs0EcdPGmCzhGUYI8U8QV63WOxu9YFcNA==",
+ "version": "13.3.4",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.4.tgz",
+ "integrity": "sha512-im4LKxJaIuqFVzmtf650PoiYsn/SZlvBV2zEgzusK8HwQ24C1Lya7NQSApwl8k43h4eKO1OvUKBjqL5uDgEQag==",
"dependencies": {
"tslib": "^2.3.0"
},
@@ -670,15 +674,15 @@
}
},
"node_modules/@angular/material": {
- "version": "13.2.6",
- "resolved": "https://registry.npmjs.org/@angular/material/-/material-13.2.6.tgz",
- "integrity": "sha512-/h5wa/tXE0DMIIEQX+rozFkUWHYUWg1Xf1R2tXUFLslLQ0KRCGyNo225Sv/1wrxXHxfrML787lA9ex4p90Feqw==",
+ "version": "13.3.4",
+ "resolved": "https://registry.npmjs.org/@angular/material/-/material-13.3.4.tgz",
+ "integrity": "sha512-jK9rWmBaPrE+3re6uIdyvG5DCzc47VUvnP1DqblNnpaa8GCKllb1cFRGqa5GPYB1/96d3wO+RPwzhC06qqV+yw==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/animations": "^13.0.0 || ^14.0.0-0",
- "@angular/cdk": "13.2.6",
+ "@angular/cdk": "13.3.4",
"@angular/common": "^13.0.0 || ^14.0.0-0",
"@angular/core": "^13.0.0 || ^14.0.0-0",
"@angular/forms": "^13.0.0 || ^14.0.0-0",
@@ -2700,6 +2704,22 @@
"yarn": ">= 1.13.0"
}
},
+ "node_modules/@sgratzl/boxplots": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@sgratzl/boxplots/-/boxplots-1.3.0.tgz",
+ "integrity": "sha512-2BRWv+WOH58pwzSgP50buoXgxQic+4auz3BF0wiIUXS8D3QGkdBNgsNdQO1754Tm/0uEwly0R3WaCiGnoYWcmA=="
+ },
+ "node_modules/@sgratzl/chartjs-chart-boxplot": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/@sgratzl/chartjs-chart-boxplot/-/chartjs-chart-boxplot-3.7.1.tgz",
+ "integrity": "sha512-DYyOedq9CVFcDQZbRekyZAu/Bg0SUgaa19hsl4ikU85Di2DPdaiC/tFIkwHS6YB4L1GMWNvY+TDUODMYRFjhxA==",
+ "dependencies": {
+ "@sgratzl/boxplots": "^1.3.0"
+ },
+ "peerDependencies": {
+ "chart.js": "^3.7.0"
+ }
+ },
"node_modules/@socket.io/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
@@ -2709,6 +2729,115 @@
"node": ">= 0.6.0"
}
},
+ "node_modules/@syncfusion/ej2-angular-base": {
+ "version": "20.1.48",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-angular-base/-/ej2-angular-base-20.1.48.tgz",
+ "integrity": "sha512-MVnQl2TuqD0pKvXJRWekHO8vtsdC89OzETUVRnYllnLqnGdNDzOFxi1Gmm+ON3HpVjcfzNSbUoFFQcJwUF+WGQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@syncfusion/ej2-base": "~20.1.48",
+ "@syncfusion/ej2-icons": "~20.1.47",
+ "core-js": "^3.4.8",
+ "reflect-metadata": "^0.1.9",
+ "rxjs": "^6.5.4",
+ "rxjs-compat": "^6.5.4",
+ "zone.js": "^0.10.2"
+ }
+ },
+ "node_modules/@syncfusion/ej2-angular-base/node_modules/rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dependencies": {
+ "tslib": "^1.9.0"
+ },
+ "engines": {
+ "npm": ">=2.0.0"
+ }
+ },
+ "node_modules/@syncfusion/ej2-angular-base/node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ },
+ "node_modules/@syncfusion/ej2-angular-base/node_modules/zone.js": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
+ "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg=="
+ },
+ "node_modules/@syncfusion/ej2-angular-heatmap": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-angular-heatmap/-/ej2-angular-heatmap-20.1.47.tgz",
+ "integrity": "sha512-mx9Z5/zNmNcjogVfS7DKNbg7zW2FXZ78O0BYPA4CqdwDLZdA30xx25JGwM7fZ6iTDs8kpEyWAAEMt+zJPyRKFw==",
+ "dependencies": {
+ "@syncfusion/ej2-angular-base": "~20.1.47",
+ "@syncfusion/ej2-base": "~20.1.47",
+ "@syncfusion/ej2-heatmap": "20.1.47"
+ }
+ },
+ "node_modules/@syncfusion/ej2-base": {
+ "version": "20.1.50",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-base/-/ej2-base-20.1.50.tgz",
+ "integrity": "sha512-RdBCPjvD/ArwArVoYjTXB7jQ7zAdgT8MxoKY4aSwY9wrNIUxNS4HhO8slY2ergjZHDP3eDnLn/UiCg5qaBtFJQ==",
+ "dependencies": {
+ "@syncfusion/ej2-icons": "~20.1.47"
+ }
+ },
+ "node_modules/@syncfusion/ej2-compression": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-compression/-/ej2-compression-20.1.47.tgz",
+ "integrity": "sha512-4+74eOf6+vxg1mobYEf5qCvTbo6DjjSZv1O2zfWUc0tgVV0A9AspXIcoeeivemTKnRDj0fm3E7Tv15h1qodpUQ==",
+ "dependencies": {
+ "@syncfusion/ej2-file-utils": "~20.1.47"
+ }
+ },
+ "node_modules/@syncfusion/ej2-data": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-data/-/ej2-data-20.1.47.tgz",
+ "integrity": "sha512-AAq95oux06/Dtoo9Az1MlN0r1xbV8BF6vIbCbpiIK016jp2V38X0x2AhvHFV/yM+winrT1d2nxUhcGcnabPveQ==",
+ "dependencies": {
+ "@syncfusion/ej2-base": "~20.1.47"
+ }
+ },
+ "node_modules/@syncfusion/ej2-file-utils": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-file-utils/-/ej2-file-utils-20.1.47.tgz",
+ "integrity": "sha512-69c/1BBbQpJ/XkdOrtGijxRIDvz05+mO4PB6VANo+FwNdhGFt4MvWmYjCDwwCE2GmqiukKvxXaLRCOjFVFRmig=="
+ },
+ "node_modules/@syncfusion/ej2-heatmap": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-heatmap/-/ej2-heatmap-20.1.47.tgz",
+ "integrity": "sha512-hOCGlHNQaFyojR84jCCQ+ssDOtWpzy0nvC3/1xNhC2VbDPvxo/zNqiNJuW+ELTlViv+2UcPMKnCLL9rgv7jakg==",
+ "dependencies": {
+ "@syncfusion/ej2-base": "~20.1.47",
+ "@syncfusion/ej2-compression": "~20.1.47",
+ "@syncfusion/ej2-data": "~20.1.47",
+ "@syncfusion/ej2-file-utils": "~20.1.47",
+ "@syncfusion/ej2-pdf-export": "~20.1.47",
+ "@syncfusion/ej2-svg-base": "~20.1.47"
+ }
+ },
+ "node_modules/@syncfusion/ej2-icons": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-icons/-/ej2-icons-20.1.47.tgz",
+ "integrity": "sha512-0P5enxVZSl+AISIlRvQV/d/k0EgP8RDN/gBmb2AQuldMoz+Nx64G7zLEXd1l9Ib2j5Si9JgXF37aYhwc2brdNw=="
+ },
+ "node_modules/@syncfusion/ej2-pdf-export": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-pdf-export/-/ej2-pdf-export-20.1.47.tgz",
+ "integrity": "sha512-ww5BtrCrn4RTOcfYnqTF9elizfLLLTZhDgsHJ09hPMhFDzazfuO79D1zfER4b2JiJYffcBiY6Xsp56qCB/ccpw==",
+ "dependencies": {
+ "@syncfusion/ej2-compression": "~20.1.47"
+ }
+ },
+ "node_modules/@syncfusion/ej2-svg-base": {
+ "version": "20.1.48",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-svg-base/-/ej2-svg-base-20.1.48.tgz",
+ "integrity": "sha512-uiGEd5Gws9NYa+lqkR2L8Z1MYeIV5QRAt9sT21KghEpoh2lS1nuzou/4vKMyQPJGayzqRCEW5BBIGkrSbgVXGg==",
+ "dependencies": {
+ "@syncfusion/ej2-base": "~20.1.48"
+ }
+ },
"node_modules/@tootallnate/once": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -3420,9 +3549,9 @@
}
},
"node_modules/async": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
- "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+ "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true,
"dependencies": {
"lodash": "^4.17.14"
@@ -3902,6 +4031,11 @@
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
+ "node_modules/chart.heatmap.js": {
+ "version": "0.0.1-alpha",
+ "resolved": "https://registry.npmjs.org/chart.heatmap.js/-/chart.heatmap.js-0.0.1-alpha.tgz",
+ "integrity": "sha1-wqcltMGZMMhu6oiyRorPWFOzpSY="
+ },
"node_modules/chart.js": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz",
@@ -4323,7 +4457,6 @@
"version": "3.20.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz",
"integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==",
- "dev": true,
"hasInstallScript": true,
"funding": {
"type": "opencollective",
@@ -7800,6 +7933,11 @@
"node": ">= 10"
}
},
+ "node_modules/material-icons": {
+ "version": "1.10.8",
+ "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.10.8.tgz",
+ "integrity": "sha512-CbtQXCmC9MXIIkz/0CmEfxELosxKxLegrjoa0mxM0zPA+GgAuhnWX6ITo/5oON/JFaCi/bh4MydEUNu0erbaxw=="
+ },
"node_modules/mdb-angular-ui-kit": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdb-angular-ui-kit/-/mdb-angular-ui-kit-2.0.0.tgz",
@@ -10169,6 +10307,11 @@
"tslib": "^2.1.0"
}
},
+ "node_modules/rxjs-compat": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs-compat/-/rxjs-compat-6.6.7.tgz",
+ "integrity": "sha512-szN4fK+TqBPOFBcBcsR0g2cmTTUF/vaFEOZNuSdfU8/pGFnNmmn2u8SystYXG1QMrjOPBc6XTKHMVfENDf6hHw=="
+ },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -12087,17 +12230,17 @@
}
},
"@angular/animations": {
- "version": "13.2.6",
- "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.2.6.tgz",
- "integrity": "sha512-DrjpKo68uR3lSLQQXosoTCbjKQS6IKRCpR14E2t8fo0AX8i2hkB8je4SrhdCyB7FgFN7l2kgUYo4Qa8+BOB+aA==",
+ "version": "13.2.7",
+ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.2.7.tgz",
+ "integrity": "sha512-FthGqRPQ1AOcOx/NIW65xeFYkQZJ7PpXcX59Kt+qkoUzngAQEY+UUpOteG52tmL0iZSVwOCjtxRFi9w4heVgEg==",
"requires": {
"tslib": "^2.3.0"
}
},
"@angular/cdk": {
- "version": "13.2.6",
- "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.2.6.tgz",
- "integrity": "sha512-epuXmaHqfukwPsYvIksbuHLXDtb6GALV2Vgv6W2asj4TorD584CeQTs0EcdPGmCzhGUYI8U8QV63WOxu9YFcNA==",
+ "version": "13.3.4",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.4.tgz",
+ "integrity": "sha512-im4LKxJaIuqFVzmtf650PoiYsn/SZlvBV2zEgzusK8HwQ24C1Lya7NQSApwl8k43h4eKO1OvUKBjqL5uDgEQag==",
"requires": {
"parse5": "^5.0.0",
"tslib": "^2.3.0"
@@ -12304,9 +12447,9 @@
}
},
"@angular/material": {
- "version": "13.2.6",
- "resolved": "https://registry.npmjs.org/@angular/material/-/material-13.2.6.tgz",
- "integrity": "sha512-/h5wa/tXE0DMIIEQX+rozFkUWHYUWg1Xf1R2tXUFLslLQ0KRCGyNo225Sv/1wrxXHxfrML787lA9ex4p90Feqw==",
+ "version": "13.3.4",
+ "resolved": "https://registry.npmjs.org/@angular/material/-/material-13.3.4.tgz",
+ "integrity": "sha512-jK9rWmBaPrE+3re6uIdyvG5DCzc47VUvnP1DqblNnpaa8GCKllb1cFRGqa5GPYB1/96d3wO+RPwzhC06qqV+yw==",
"requires": {
"tslib": "^2.3.0"
}
@@ -13716,12 +13859,132 @@
"jsonc-parser": "3.0.0"
}
},
+ "@sgratzl/boxplots": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@sgratzl/boxplots/-/boxplots-1.3.0.tgz",
+ "integrity": "sha512-2BRWv+WOH58pwzSgP50buoXgxQic+4auz3BF0wiIUXS8D3QGkdBNgsNdQO1754Tm/0uEwly0R3WaCiGnoYWcmA=="
+ },
+ "@sgratzl/chartjs-chart-boxplot": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/@sgratzl/chartjs-chart-boxplot/-/chartjs-chart-boxplot-3.7.1.tgz",
+ "integrity": "sha512-DYyOedq9CVFcDQZbRekyZAu/Bg0SUgaa19hsl4ikU85Di2DPdaiC/tFIkwHS6YB4L1GMWNvY+TDUODMYRFjhxA==",
+ "requires": {
+ "@sgratzl/boxplots": "^1.3.0"
+ }
+ },
"@socket.io/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==",
"dev": true
},
+ "@syncfusion/ej2-angular-base": {
+ "version": "20.1.48",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-angular-base/-/ej2-angular-base-20.1.48.tgz",
+ "integrity": "sha512-MVnQl2TuqD0pKvXJRWekHO8vtsdC89OzETUVRnYllnLqnGdNDzOFxi1Gmm+ON3HpVjcfzNSbUoFFQcJwUF+WGQ==",
+ "requires": {
+ "@syncfusion/ej2-base": "~20.1.48",
+ "@syncfusion/ej2-icons": "~20.1.47",
+ "core-js": "^3.4.8",
+ "reflect-metadata": "^0.1.9",
+ "rxjs": "^6.5.4",
+ "rxjs-compat": "^6.5.4",
+ "zone.js": "^0.10.2"
+ },
+ "dependencies": {
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ },
+ "zone.js": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
+ "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg=="
+ }
+ }
+ },
+ "@syncfusion/ej2-angular-heatmap": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-angular-heatmap/-/ej2-angular-heatmap-20.1.47.tgz",
+ "integrity": "sha512-mx9Z5/zNmNcjogVfS7DKNbg7zW2FXZ78O0BYPA4CqdwDLZdA30xx25JGwM7fZ6iTDs8kpEyWAAEMt+zJPyRKFw==",
+ "requires": {
+ "@syncfusion/ej2-angular-base": "~20.1.47",
+ "@syncfusion/ej2-base": "~20.1.47",
+ "@syncfusion/ej2-heatmap": "20.1.47"
+ }
+ },
+ "@syncfusion/ej2-base": {
+ "version": "20.1.50",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-base/-/ej2-base-20.1.50.tgz",
+ "integrity": "sha512-RdBCPjvD/ArwArVoYjTXB7jQ7zAdgT8MxoKY4aSwY9wrNIUxNS4HhO8slY2ergjZHDP3eDnLn/UiCg5qaBtFJQ==",
+ "requires": {
+ "@syncfusion/ej2-icons": "~20.1.47"
+ }
+ },
+ "@syncfusion/ej2-compression": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-compression/-/ej2-compression-20.1.47.tgz",
+ "integrity": "sha512-4+74eOf6+vxg1mobYEf5qCvTbo6DjjSZv1O2zfWUc0tgVV0A9AspXIcoeeivemTKnRDj0fm3E7Tv15h1qodpUQ==",
+ "requires": {
+ "@syncfusion/ej2-file-utils": "~20.1.47"
+ }
+ },
+ "@syncfusion/ej2-data": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-data/-/ej2-data-20.1.47.tgz",
+ "integrity": "sha512-AAq95oux06/Dtoo9Az1MlN0r1xbV8BF6vIbCbpiIK016jp2V38X0x2AhvHFV/yM+winrT1d2nxUhcGcnabPveQ==",
+ "requires": {
+ "@syncfusion/ej2-base": "~20.1.47"
+ }
+ },
+ "@syncfusion/ej2-file-utils": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-file-utils/-/ej2-file-utils-20.1.47.tgz",
+ "integrity": "sha512-69c/1BBbQpJ/XkdOrtGijxRIDvz05+mO4PB6VANo+FwNdhGFt4MvWmYjCDwwCE2GmqiukKvxXaLRCOjFVFRmig=="
+ },
+ "@syncfusion/ej2-heatmap": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-heatmap/-/ej2-heatmap-20.1.47.tgz",
+ "integrity": "sha512-hOCGlHNQaFyojR84jCCQ+ssDOtWpzy0nvC3/1xNhC2VbDPvxo/zNqiNJuW+ELTlViv+2UcPMKnCLL9rgv7jakg==",
+ "requires": {
+ "@syncfusion/ej2-base": "~20.1.47",
+ "@syncfusion/ej2-compression": "~20.1.47",
+ "@syncfusion/ej2-data": "~20.1.47",
+ "@syncfusion/ej2-file-utils": "~20.1.47",
+ "@syncfusion/ej2-pdf-export": "~20.1.47",
+ "@syncfusion/ej2-svg-base": "~20.1.47"
+ }
+ },
+ "@syncfusion/ej2-icons": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-icons/-/ej2-icons-20.1.47.tgz",
+ "integrity": "sha512-0P5enxVZSl+AISIlRvQV/d/k0EgP8RDN/gBmb2AQuldMoz+Nx64G7zLEXd1l9Ib2j5Si9JgXF37aYhwc2brdNw=="
+ },
+ "@syncfusion/ej2-pdf-export": {
+ "version": "20.1.47",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-pdf-export/-/ej2-pdf-export-20.1.47.tgz",
+ "integrity": "sha512-ww5BtrCrn4RTOcfYnqTF9elizfLLLTZhDgsHJ09hPMhFDzazfuO79D1zfER4b2JiJYffcBiY6Xsp56qCB/ccpw==",
+ "requires": {
+ "@syncfusion/ej2-compression": "~20.1.47"
+ }
+ },
+ "@syncfusion/ej2-svg-base": {
+ "version": "20.1.48",
+ "resolved": "https://registry.npmjs.org/@syncfusion/ej2-svg-base/-/ej2-svg-base-20.1.48.tgz",
+ "integrity": "sha512-uiGEd5Gws9NYa+lqkR2L8Z1MYeIV5QRAt9sT21KghEpoh2lS1nuzou/4vKMyQPJGayzqRCEW5BBIGkrSbgVXGg==",
+ "requires": {
+ "@syncfusion/ej2-base": "~20.1.48"
+ }
+ },
"@tootallnate/once": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -14355,9 +14618,9 @@
"dev": true
},
"async": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
- "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+ "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true,
"requires": {
"lodash": "^4.17.14"
@@ -14715,6 +14978,11 @@
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
+ "chart.heatmap.js": {
+ "version": "0.0.1-alpha",
+ "resolved": "https://registry.npmjs.org/chart.heatmap.js/-/chart.heatmap.js-0.0.1-alpha.tgz",
+ "integrity": "sha1-wqcltMGZMMhu6oiyRorPWFOzpSY="
+ },
"chart.js": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz",
@@ -15036,8 +15304,7 @@
"core-js": {
"version": "3.20.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz",
- "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==",
- "dev": true
+ "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag=="
},
"core-js-compat": {
"version": "3.21.1",
@@ -17576,6 +17843,11 @@
"ssri": "^8.0.0"
}
},
+ "material-icons": {
+ "version": "1.10.8",
+ "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.10.8.tgz",
+ "integrity": "sha512-CbtQXCmC9MXIIkz/0CmEfxELosxKxLegrjoa0mxM0zPA+GgAuhnWX6ITo/5oON/JFaCi/bh4MydEUNu0erbaxw=="
+ },
"mdb-angular-ui-kit": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdb-angular-ui-kit/-/mdb-angular-ui-kit-2.0.0.tgz",
@@ -19297,6 +19569,11 @@
"tslib": "^2.1.0"
}
},
+ "rxjs-compat": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs-compat/-/rxjs-compat-6.6.7.tgz",
+ "integrity": "sha512-szN4fK+TqBPOFBcBcsR0g2cmTTUF/vaFEOZNuSdfU8/pGFnNmmn2u8SystYXG1QMrjOPBc6XTKHMVfENDf6hHw=="
+ },
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index c02a1fb0..89381956 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -13,13 +13,13 @@
"private": true,
"dependencies": {
"@angular/animations": "~13.2.0",
- "@angular/cdk": "^13.2.6",
+ "@angular/cdk": "^13.3.4",
"@angular/common": "~13.2.0",
"@angular/compiler": "~13.2.0",
"@angular/core": "~13.2.0",
"@angular/forms": "~13.2.0",
"@angular/localize": "~13.2.0",
- "@angular/material": "^13.2.6",
+ "@angular/material": "^13.3.4",
"@angular/platform-browser": "~13.2.0",
"@angular/platform-browser-dynamic": "~13.2.0",
"@angular/router": "~13.2.0",
@@ -27,11 +27,15 @@
"@microsoft/signalr": "^6.0.4",
"@ng-bootstrap/ng-bootstrap": "^12.0.0",
"@popperjs/core": "^2.10.2",
+ "@sgratzl/chartjs-chart-boxplot": "^3.7.1",
+ "@syncfusion/ej2-angular-heatmap": "^20.1.47",
"bootstrap": "^5.1.3",
+ "chart.heatmap.js": "^0.0.1-alpha",
"chart.js": "^3.7.1",
"csv-parser": "^3.0.0",
"d3-graphviz": "^2.6.1",
"jquery": "^3.6.0",
+ "material-icons": "^1.10.8",
"mdb-angular-ui-kit": "^2.0.0",
"ng-multiselect-dropdown": "^0.3.8",
"ng-uikit-pro-standard": "^1.0.0",
diff --git a/frontend/src/app/Shared.ts b/frontend/src/app/Shared.ts
index 59a2716d..d088fff9 100644
--- a/frontend/src/app/Shared.ts
+++ b/frontend/src/app/Shared.ts
@@ -1,4 +1,4 @@
-import { ElementRef } from "@angular/core";
+import { ElementRef, EventEmitter } from "@angular/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { AlertDialogComponent } from './_modals/alert-dialog/alert-dialog.component';
@@ -27,18 +27,24 @@ class Shared {
});
}
}
- openYesNoDialog(title: string, message: string,yesFunction:Function): void {
+ openYesNoDialog(title: string, message: string, yesFunction: Function): void {
if (this.dialog) {
const dialogRef = this.dialog.open(YesNoDialogComponent, {
width: '350px',
- data: { title: title, message: message,yesFunction}
+ data: { title: title, message: message, yesFunction }
});
dialogRef.afterClosed().subscribe(res => {
//nesto
});
}
}
+
+ bgScroll: EventEmitter<number> = new EventEmitter();
+
+ emitBGScrollEvent(value: number) {
+ this.bgScroll.emit(value);
+ }
}
export default new Shared(false); \ No newline at end of file
diff --git a/frontend/src/app/_data/Dataset.ts b/frontend/src/app/_data/Dataset.ts
index 766040a3..e8207718 100644
--- a/frontend/src/app/_data/Dataset.ts
+++ b/frontend/src/app/_data/Dataset.ts
@@ -1,17 +1,19 @@
-export default class Dataset {
+import { FolderFile } from "./FolderFile";
+
+export default class Dataset extends FolderFile {
_id: string = '';
constructor(
- public name: string = 'Novi izvor podataka',
+ name: string = 'Novi izvor podataka',
public description: string = '',
public header: string[] = [],
public fileId?: number,
public extension: string = '.csv',
public isPublic: boolean = false,
public accessibleByLink: boolean = false,
- public dateCreated: Date = new Date(),
- public lastUpdated: Date = new Date(),
+ dateCreated: Date = new Date(),
+ lastUpdated: Date = new Date(),
public uploaderId: string = '',
- public delimiter: string = '',
+ public delimiter: string = ',',
public hasHeader: boolean = true,
public columnInfo: ColumnInfo[] = [],
@@ -19,7 +21,9 @@ export default class Dataset {
public nullRows: number = 0,
public nullCols: number = 0,
public preview: string[][] = [[]]
- ) { }
+ ) {
+ super(name, dateCreated, lastUpdated);
+ }
}
export class ColumnInfo {
@@ -33,4 +37,4 @@ export class ColumnInfo {
public min?: number,
public max?: number
) { }
-} \ No newline at end of file
+}
diff --git a/frontend/src/app/_data/Experiment.ts b/frontend/src/app/_data/Experiment.ts
index 95ef6e1e..ec966008 100644
--- a/frontend/src/app/_data/Experiment.ts
+++ b/frontend/src/app/_data/Experiment.ts
@@ -19,8 +19,7 @@ export default class Experiment {
public randomTestSet: boolean = true,
public randomTestSetDistribution: number = 0.1, //0.1-0.9 (10% - 90%) JESTE OVDE ZAKUCANO 10, AL POSLATO JE KAO 0.1 BACK-U
- public encodings: ColumnEncoding[] = [],
- public type: ProblemType = ProblemType.Regression
+ public encodings: ColumnEncoding[] = []//[{columnName: "", columnEncoding: Encoding.Label}]
) { }
}
diff --git a/frontend/src/app/_data/FolderFile.ts b/frontend/src/app/_data/FolderFile.ts
new file mode 100644
index 00000000..a79eeac5
--- /dev/null
+++ b/frontend/src/app/_data/FolderFile.ts
@@ -0,0 +1,13 @@
+export class FolderFile {
+ constructor(
+ public name: string,
+ public dateCreated: Date,
+ public lastUpdated: Date
+ ) { }
+}
+
+
+export enum FolderType {
+ Dataset,
+ Model
+} \ No newline at end of file
diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts
index b273f56a..6281748c 100644
--- a/frontend/src/app/_data/Model.ts
+++ b/frontend/src/app/_data/Model.ts
@@ -1,12 +1,13 @@
import { NgIf } from "@angular/common";
+import { FolderFile } from "./FolderFile";
-export default class Model {
+export default class Model extends FolderFile {
_id: string = '';
constructor(
- public name: string = 'Novi model',
+ name: string = 'Novi model',
public description: string = '',
- public dateCreated: Date = new Date(),
- public lastUpdated: Date = new Date(),
+ dateCreated: Date = new Date(),
+ lastUpdated: Date = new Date(),
//public experimentId: string = '',
// Neural net training settings
@@ -14,17 +15,58 @@ export default class Model {
public optimizer: Optimizer = Optimizer.Adam,
public lossFunction: LossFunction = LossFunction.MeanSquaredError,
public inputNeurons: number = 1,
- public hiddenLayerNeurons: number = 1,
public hiddenLayers: number = 1,
- public batchSize: number = 5,
- public hiddenLayerActivationFunctions: string[] = ['sigmoid'],
+ public batchSize: BatchSize = BatchSize.O3,
public outputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid,
public uploaderId: string = '',
public metrics: string[] = [], // TODO add to add-model form
- public epochs: number = 5 // TODO add to add-model form
+ public epochs: number = 5, // TODO add to add-model form
+ public inputColNum: number = 5,
+ public learningRate: LearningRate = LearningRate.LR1,
+ public layers: Layer[] = [new Layer()]
+
+ ) {
+ super(name, dateCreated, lastUpdated);
+ }
+}
+export class Layer {
+ constructor(
+ public layerNumber: number = 0,
+ public activationFunction: ActivationFunction = ActivationFunction.Sigmoid,
+ public neurons: number = 3,
+ public regularisation: Regularisation = Regularisation.L1,
+ public regularisationRate: RegularisationRate = RegularisationRate.RR1,
) { }
}
-
+export enum LearningRate {
+ LR1 = '0.00001',
+ LR2 = '0.0001',
+ LR3 = '0.001',
+ LR4 = '0.003',
+ LR5 = '0.01',
+ LR6 = '0.03',
+ LR7 = '0.1',
+ LR8 = '0.3',
+ LR9 = '1',
+ LR10 = '3',
+ LR11 = '10',
+}
+export enum Regularisation {
+ L1 = 'l1',
+ L2 = 'l2'
+}
+export enum RegularisationRate {
+ RR1 = '0',
+ RR2 = '0.001',
+ RR3 = '0.003',
+ RR4 = '0.01',
+ RR5 = '0.03',
+ RR6 = '0.1',
+ RR7 = '0.3',
+ RR8 = '1',
+ RR9 = '3',
+ RR10 = '10',
+}
export enum ProblemType {
Regression = 'regresioni',
BinaryClassification = 'binarni-klasifikacioni',
@@ -157,3 +199,16 @@ export enum MetricsMultiClassification {
Recall = 'recall_score',
F1 = 'f1_score',
}
+
+export enum BatchSize {
+ O1 = '2',
+ O2 = '4',
+ O3 = '8',
+ O4 = '16',
+ O5 = '32',
+ O6 = '64',
+ O7 = '128',
+ O8 = '256',
+ O9 = '512',
+ O10 = '1024'
+} \ No newline at end of file
diff --git a/frontend/src/app/barchart/barchart.component.css b/frontend/src/app/_elements/_charts/barchart/barchart.component.css
index c3634c9f..c3634c9f 100644
--- a/frontend/src/app/barchart/barchart.component.css
+++ b/frontend/src/app/_elements/_charts/barchart/barchart.component.css
diff --git a/frontend/src/app/barchart/barchart.component.html b/frontend/src/app/_elements/_charts/barchart/barchart.component.html
index 48b7bd3e..48b7bd3e 100644
--- a/frontend/src/app/barchart/barchart.component.html
+++ b/frontend/src/app/_elements/_charts/barchart/barchart.component.html
diff --git a/frontend/src/app/barchart/barchart.component.spec.ts b/frontend/src/app/_elements/_charts/barchart/barchart.component.spec.ts
index 8b346d1c..8b346d1c 100644
--- a/frontend/src/app/barchart/barchart.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/barchart/barchart.component.spec.ts
diff --git a/frontend/src/app/barchart/barchart.component.ts b/frontend/src/app/_elements/_charts/barchart/barchart.component.ts
index def64b7d..904335d7 100644
--- a/frontend/src/app/barchart/barchart.component.ts
+++ b/frontend/src/app/_elements/_charts/barchart/barchart.component.ts
@@ -8,6 +8,7 @@ import {Chart} from 'node_modules/chart.js';
})
export class BarchartComponent implements OnInit {
+
constructor() { }
ngOnInit(){
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.css b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.css
index e69de29b..e69de29b 100644
--- a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.css
+++ b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.css
diff --git a/frontend/src/app/_elements/_charts/box-plot/box-plot.component.html b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.html
new file mode 100644
index 00000000..688eafae
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.html
@@ -0,0 +1,3 @@
+<div class="chart-wrapper">
+ <canvas #boxplot [width]="width" [height]="height"></canvas>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/training/training.component.spec.ts b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.spec.ts
index 1222cb40..759e7c5e 100644
--- a/frontend/src/app/training/training.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { TrainingComponent } from './training.component';
+import { BoxPlotComponent } from './box-plot.component';
-describe('TrainingComponent', () => {
- let component: TrainingComponent;
- let fixture: ComponentFixture<TrainingComponent>;
+describe('BoxPlotComponent', () => {
+ let component: BoxPlotComponent;
+ let fixture: ComponentFixture<BoxPlotComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ TrainingComponent ]
+ declarations: [ BoxPlotComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(TrainingComponent);
+ fixture = TestBed.createComponent(BoxPlotComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts
new file mode 100644
index 00000000..3faa4794
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts
@@ -0,0 +1,102 @@
+import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
+import { Chart, LinearScale, CategoryScale } from 'chart.js';
+import { BoxPlotController, BoxAndWiskers } from '@sgratzl/chartjs-chart-boxplot';
+
+function randomValues(count: number, min: number, max: number) {
+ const delta = max - min;
+ return Array.from({ length: count }).map(() => Math.random() * delta + min);
+}
+
+Chart.register(BoxPlotController, BoxAndWiskers, LinearScale, CategoryScale);
+
+@Component({
+ selector: 'app-box-plot',
+ templateUrl: './box-plot.component.html',
+ styleUrls: ['./box-plot.component.css']
+})
+export class BoxPlotComponent implements AfterViewInit {
+
+ @Input()width?: number;
+ @Input()height?: number;
+
+ @ViewChild('boxplot') chartRef!: ElementRef;
+ constructor() { }
+
+ boxplotData = {
+ // define label tree
+ labels: ['January'/*, 'February', 'March', 'April', 'May', 'June', 'July'*/],
+ datasets: [{
+ label: 'Dataset 1',
+ backgroundColor: 'rgba(0, 65, 101, 1.0)',
+ borderColor: '#0063AB',
+ borderWidth: 1,
+ outlierColor: '#999999',
+ scaleFontColor: '#0063AB',
+ padding: 10,
+ itemRadius: 0,
+ data: [
+ randomValues(100, 0, 100),
+ /*randomValues(100, 0, 20),
+ randomValues(100, 20, 70),
+ randomValues(100, 60, 100),
+ randomValues(40, 50, 100),
+ randomValues(100, 60, 120),
+ randomValues(100, 80, 100)*/
+ ]}/*, {
+ label: 'Dataset 2',
+ backgroundColor: 'rgba(0,0,255,0.5)',
+ borderColor: 'blue',
+ borderWidth: 1,
+ outlierColor: '#999999',
+ padding: 10,
+ itemRadius: 0,
+ data: [
+ randomValues(100, 60, 100),
+ randomValues(100, 0, 100),
+ randomValues(100, 0, 20),
+ randomValues(100, 20, 70),
+ randomValues(40, 60, 120),
+ randomValues(100, 20, 100),
+ randomValues(100, 80, 100)
+ ]
+ }*/]
+ };
+ ngAfterViewInit(): void {
+ const myChart = new Chart(this.chartRef.nativeElement, {
+ type: "boxplot",
+ data: this.boxplotData,
+ options: {
+ /*title: {
+ display: true,
+ text: 'Predicted world population (millions) in 2050'
+ }*/
+ plugins:{
+ legend: {
+ display: false
+ },
+ },
+ scales : {
+ x: {
+ ticks: {
+ color: 'rgba(0, 65, 101, 1.0)'
+ },
+ grid: {
+ color: "rgba(0, 99, 171, 0.5)"
+ }
+ },
+ y : {
+ min: -50,
+ max: 200,
+ ticks: {
+ color: 'rgba(0, 65, 101, 1.0)'
+ },
+ grid: {
+ color: "rgba(0, 99, 171, 0.5)"
+ }
+ }
+ }
+ }
+ });
+}
+
+}
diff --git a/frontend/src/app/_elements/carousel/carousel.component.css b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.css
index e69de29b..e69de29b 100644
--- a/frontend/src/app/_elements/carousel/carousel.component.css
+++ b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.css
diff --git a/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.html b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.html
new file mode 100644
index 00000000..9c464534
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.html
@@ -0,0 +1 @@
+<canvas #doughnut [width]="width" [height]="height"></canvas>
diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.spec.ts b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.spec.ts
index b5c2d91c..67309670 100644
--- a/frontend/src/app/_elements/item-predictor/item-predictor.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ItemPredictorComponent } from './item-predictor.component';
+import { DoughnutChartComponent } from './doughnut-chart.component';
-describe('ItemPredictorComponent', () => {
- let component: ItemPredictorComponent;
- let fixture: ComponentFixture<ItemPredictorComponent>;
+describe('DoughnutChartComponent', () => {
+ let component: DoughnutChartComponent;
+ let fixture: ComponentFixture<DoughnutChartComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ ItemPredictorComponent ]
+ declarations: [ DoughnutChartComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(ItemPredictorComponent);
+ fixture = TestBed.createComponent(DoughnutChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.ts b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.ts
new file mode 100644
index 00000000..fc13289c
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/doughnut-chart/doughnut-chart.component.ts
@@ -0,0 +1,37 @@
+import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
+import {Chart} from 'node_modules/chart.js';
+
+@Component({
+ selector: 'app-doughnut-chart',
+ templateUrl: './doughnut-chart.component.html',
+ styleUrls: ['./doughnut-chart.component.css']
+})
+export class DoughnutChartComponent implements AfterViewInit {
+
+ @Input()width: number = 800;
+ @Input()height: number = 450;
+
+ @ViewChild('doughnut') chartRef!: ElementRef;
+ constructor() { }
+
+ ngAfterViewInit(): void {
+ const myChart = new Chart(this.chartRef.nativeElement, {
+ type: 'doughnut',
+ data: {
+ labels: ["Africa", "Asia", "Europe", "Latin America", "North America"],
+ datasets: [{
+ label: "Population (millions)",
+ backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
+ data: [2478,5267,734,784,433]
+ }]
+ },
+ /*options: {
+ title: {
+ display: true,
+ text: 'Predicted world population (millions) in 2050'
+ }
+ }*/
+ });
+ }
+
+}
diff --git a/frontend/src/app/_elements/item-experiment/item-experiment.component.css b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.css
index e69de29b..e69de29b 100644
--- a/frontend/src/app/_elements/item-experiment/item-experiment.component.css
+++ b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.css
diff --git a/frontend/src/app/_elements/_charts/heatmap/heatmap.component.html b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.html
new file mode 100644
index 00000000..52d95516
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.html
@@ -0,0 +1,3 @@
+<div style="width:800px; height: 400px; background-color: red;">
+ <ejs-heatmap [dataSource]='dataSource' [xAxis]='xAxis' [yAxis]='yAxis'></ejs-heatmap>
+</div>
diff --git a/frontend/src/app/_pages/predict/predict.component.spec.ts b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.spec.ts
index 65871ecc..fa0a90cc 100644
--- a/frontend/src/app/_pages/predict/predict.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { PredictComponent } from './predict.component';
+import { HeatmapComponent } from './heatmap.component';
-describe('PredictComponent', () => {
- let component: PredictComponent;
- let fixture: ComponentFixture<PredictComponent>;
+describe('HeatmapComponent', () => {
+ let component: HeatmapComponent;
+ let fixture: ComponentFixture<HeatmapComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ PredictComponent ]
+ declarations: [ HeatmapComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(PredictComponent);
+ fixture = TestBed.createComponent(HeatmapComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/_charts/heatmap/heatmap.component.ts b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.ts
new file mode 100644
index 00000000..f3d1af98
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/heatmap/heatmap.component.ts
@@ -0,0 +1,108 @@
+import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
+import {Chart} from 'chart.js';
+import { HeatMapAllModule } from '@syncfusion/ej2-angular-heatmap';
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+
+
+
+@Component({
+ selector: 'app-heatmap',
+ templateUrl: './heatmap.component.html',
+ styleUrls: ['./heatmap.component.css']
+})
+export class HeatmapComponent implements OnInit {
+
+
+ @Input()width?: number;
+ @Input()height?: number;
+
+ dataSource = [
+
+ [73, 39, 26, 39, 94, 0],
+
+ [93, 58, 53, 38, 26, 68],
+
+ [99, 28, 22, 4, 66, 90],
+
+ [14, 26, 97, 69, 69, 3],
+
+ [7, 46, 47, 47, 88, 6],
+
+ [41, 55, 73, 23, 3, 79],
+
+ [56, 69, 21, 86, 3, 33],
+
+ [45, 7, 53, 81, 95, 79],
+
+ [60, 77, 74, 68, 88, 51],
+
+ [25, 25, 10, 12, 78, 14],
+
+ [25, 56, 55, 58, 12, 82],
+
+ [74, 33, 88, 23, 86, 59]
+
+ ];
+
+ xAxis = {
+
+ labels: ['Nancy', 'Andrew', 'Janet', 'Margaret', 'Steven', 'Michael', 'Robert',
+
+ 'Laura', 'Anne', 'Paul', 'Karin', 'Mario'],
+
+ };
+
+ yAxis = {
+
+ labels: ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'],
+
+ }
+
+ //@ViewChild('heatmap') chartRef!: ElementRef;
+ constructor() { }
+
+ ngOnInit(): void {
+
+
+
+ /*
+ const myChart = new Chart(this.chartRef.nativeElement, {
+ type: 'pie',
+ data: {
+ datasets: [{
+ data: [
+
+ [73, 39, 26, 39, 94, 0],
+
+ [93, 58, 53, 38, 26, 68],
+
+ [99, 28, 22, 4, 66, 90],
+
+ [14, 26, 97, 69, 69, 3],
+
+ [7, 46, 47, 47, 88, 6],
+
+ [41, 55, 73, 23, 3, 79],
+
+ [56, 69, 21, 86, 3, 33],
+
+ [45, 7, 53, 81, 95, 79],
+
+ [60, 77, 74, 68, 88, 51],
+
+ [25, 25, 10, 12, 78, 14],
+
+ [25, 56, 55, 58, 12, 82],
+
+ [74, 33, 88, 23, 86, 59]
+
+ ],
+ }]
+ }
+});
+ */
+
+ }
+
+}
diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.css b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.css
index e69de29b..e69de29b 100644
--- a/frontend/src/app/_elements/item-predictor/item-predictor.component.css
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.css
diff --git a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.html b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.html
new file mode 100644
index 00000000..c8f406f4
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.html
@@ -0,0 +1,5 @@
+<div class="chart-wrapper">
+ <canvas id="myChart">
+
+ </canvas>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.spec.ts b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.spec.ts
index cb07ef1d..0c5e7ef5 100644
--- a/frontend/src/app/_elements/annvisual/annvisual.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { AnnvisualComponent } from './annvisual.component';
+import { LineChartComponent } from './line-chart.component';
-describe('AnnvisualComponent', () => {
- let component: AnnvisualComponent;
- let fixture: ComponentFixture<AnnvisualComponent>;
+describe('LineChartComponent', () => {
+ let component: LineChartComponent;
+ let fixture: ComponentFixture<LineChartComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ AnnvisualComponent ]
+ declarations: [ LineChartComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(AnnvisualComponent);
+ fixture = TestBed.createComponent(LineChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
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
new file mode 100644
index 00000000..49558025
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts
@@ -0,0 +1,88 @@
+import { Component, AfterViewInit } from '@angular/core';
+import { Chart } from 'chart.js';
+
+@Component({
+ selector: 'app-line-chart',
+ templateUrl: './line-chart.component.html',
+ styleUrls: ['./line-chart.component.css']
+})
+
+export class LineChartComponent implements AfterViewInit {
+
+ dataAcc: number[] = [];
+ dataMAE: number[] = [];
+ dataMSE: number[] = [];
+ dataLOSS: number[] = [];
+
+ dataEpoch: number[] = [];
+
+ constructor() {
+ /*let i = 0;
+ setInterval(() => {
+ this.dataAcc.push(0.5);
+ this.dataEpoch.push(i);
+ i++;
+ this.update();
+ }, 200);*/
+ }
+
+ myChart!: Chart;
+
+ update(myEpochs: number[], myAcc: number[], myLoss: number[], myMae: number[], myMse: 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.dataLOSS.length = 0;
+ this.dataLOSS.push(...myLoss);
+
+ this.dataMSE.length = 0;
+ this.dataMSE.push(...myMse);
+
+ this.myChart.update();
+ }
+
+ ngAfterViewInit(): void {
+ this.myChart = new Chart("myChart",
+ {
+ type: 'line',
+ data: {
+ labels: this.dataEpoch,
+ datasets: [{
+ label: 'Accuracy',
+ data: this.dataAcc,
+ borderWidth: 1
+ },
+ {
+ label: 'Loss',
+ data: this.dataLOSS,
+ borderWidth: 1
+ },
+ {
+ label: 'MAE',
+ data: this.dataMAE,
+ borderWidth: 1
+ },
+ {
+ label: 'MSE',
+ data: this.dataMSE,
+ borderWidth: 1
+ }
+ ]
+ },
+ options: {
+ scales: {
+ y: {
+ beginAtZero: true
+ }
+ }
+ }
+ }
+ );
+ }
+}
diff --git a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.css b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.css
index e69de29b..e69de29b 100644
--- a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.css
+++ b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.css
diff --git a/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.html b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.html
new file mode 100644
index 00000000..806ea9e8
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.html
@@ -0,0 +1,2 @@
+<canvas #mixedchart width="800" height="450"></canvas>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
diff --git a/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.spec.ts b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.spec.ts
new file mode 100644
index 00000000..361cd047
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MixedChartComponent } from './mixed-chart.component';
+
+describe('MixedChartComponent', () => {
+ let component: MixedChartComponent;
+ let fixture: ComponentFixture<MixedChartComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ MixedChartComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MixedChartComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.ts b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.ts
new file mode 100644
index 00000000..2524ee36
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/mixed-chart/mixed-chart.component.ts
@@ -0,0 +1,56 @@
+import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import {Chart} from 'node_modules/chart.js';
+
+@Component({
+ selector: 'app-mixed-chart',
+ templateUrl: './mixed-chart.component.html',
+ styleUrls: ['./mixed-chart.component.css']
+})
+export class MixedChartComponent implements AfterViewInit {
+
+ @ViewChild('mixedchart') chartRef!: ElementRef;
+ constructor() { }
+
+ ngAfterViewInit(): void {
+ const myChart = new Chart(this.chartRef.nativeElement, {
+ type: 'bar',
+ data: {
+ labels: ["1900", "1950", "1999", "2050"],
+ datasets: [{
+ label: "Europe",
+ type: "line",
+ borderColor: "#8e5ea2",
+ data: [408,547,675,734],
+ fill: false
+ }, {
+ label: "Africa",
+ type: "line",
+ borderColor: "#3e95cd",
+ data: [133,221,783,2478],
+ fill: false
+ }, {
+ label: "Europe",
+ type: "bar",
+ backgroundColor: "rgba(0,0,0,0.2)",
+ data: [408,547,675,734],
+ }, {
+ label: "Africa",
+ type: "bar",
+ backgroundColor: "rgba(0,0,0,0.2)",
+ //backgroundColorHover: "#3e95cd",
+ data: [133,221,783,2478]
+ }
+ ]
+ },
+ /*options: {
+ title: {
+ display: true,
+ text: 'Population growth (millions): Europe & Africa'
+ },
+ legend: { display: false }
+ }*/
+
+ });
+ }
+
+}
diff --git a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.css b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.css
index e69de29b..e69de29b 100644
--- a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.css
+++ b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.css
diff --git a/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.html b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.html
new file mode 100644
index 00000000..7faf3af0
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.html
@@ -0,0 +1,3 @@
+<div class="chart-wrapper">
+ <canvas #piechart [width]="width" [height]="height"></canvas>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/my-models/my-models.component.spec.ts b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.spec.ts
index e431d04c..64f36b7d 100644
--- a/frontend/src/app/_pages/my-models/my-models.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MyModelsComponent } from './my-models.component';
+import { PieChartComponent } from './pie-chart.component';
-describe('MyModelsComponent', () => {
- let component: MyModelsComponent;
- let fixture: ComponentFixture<MyModelsComponent>;
+describe('PieChartComponent', () => {
+ let component: PieChartComponent;
+ let fixture: ComponentFixture<PieChartComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ MyModelsComponent ]
+ declarations: [ PieChartComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(MyModelsComponent);
+ fixture = TestBed.createComponent(PieChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts
new file mode 100644
index 00000000..f141f522
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts
@@ -0,0 +1,46 @@
+import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
+import {Chart} from 'chart.js';
+
+@Component({
+ selector: 'app-pie-chart',
+ templateUrl: './pie-chart.component.html',
+ styleUrls: ['./pie-chart.component.css']
+})
+export class PieChartComponent implements AfterViewInit {
+
+ @Input()width?: number;
+ @Input()height?: number;
+
+ @ViewChild('piechart') chartRef!: ElementRef;
+ constructor() { }
+
+ ngAfterViewInit(): void {
+ const myChart = new Chart(this.chartRef.nativeElement, {
+ type: 'pie',
+ data: {
+ labels: ["Africa", "Asia", "Europe", "Latin America", "North America"],
+ datasets: [{
+ label: "Population (millions)",
+ backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
+ data: [2478,5267,734,784,433],
+ }]
+ },
+ options: {
+ /*title: {
+ display: true,
+ text: 'Predicted world population (millions) in 2050'
+ }*/
+ plugins:{
+ legend: {
+ display: false
+ },
+ },
+ layout: {
+ padding: 15}
+ }
+});
+
+ }
+
+
+}
diff --git a/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.css b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.css
diff --git a/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.html b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.html
new file mode 100644
index 00000000..f9f9a24a
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.html
@@ -0,0 +1,2 @@
+<canvas #linechart width="800" height="450">Point line chart:</canvas>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
diff --git a/frontend/src/app/_elements/item-experiment/item-experiment.component.spec.ts b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.spec.ts
index 1da7d05d..fe08fe7c 100644
--- a/frontend/src/app/_elements/item-experiment/item-experiment.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ItemExperimentComponent } from './item-experiment.component';
+import { PointLinechartComponent } from './point-linechart.component';
-describe('ItemExperimentComponent', () => {
- let component: ItemExperimentComponent;
- let fixture: ComponentFixture<ItemExperimentComponent>;
+describe('PointLinechartComponent', () => {
+ let component: PointLinechartComponent;
+ let fixture: ComponentFixture<PointLinechartComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ ItemExperimentComponent ]
+ declarations: [ PointLinechartComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(ItemExperimentComponent);
+ fixture = TestBed.createComponent(PointLinechartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.ts b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.ts
new file mode 100644
index 00000000..3497a20c
--- /dev/null
+++ b/frontend/src/app/_elements/_charts/point-linechart/point-linechart.component.ts
@@ -0,0 +1,57 @@
+import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import {Chart} from 'node_modules/chart.js';
+
+
+@Component({
+ selector: 'app-point-linechart',
+ templateUrl: './point-linechart.component.html',
+ styleUrls: ['./point-linechart.component.css']
+})
+export class PointLinechartComponent implements AfterViewInit {
+
+ @ViewChild('linechart') chartRef!: ElementRef;
+ constructor() { }
+ ngAfterViewInit(): void {
+ const myChart = new Chart(this.chartRef.nativeElement, {
+ type: 'line',
+ data: {
+ labels: [1500,1600,1700,1750,1800,1850,1900,1950,1999,2050],
+ datasets: [{
+ data: [86,114,106,106,107,111,133,221,783,2478],
+ label: "Africa",
+ borderColor: "#3e95cd",
+ fill: false
+ }, {
+ data: [282,350,411,502,635,809,947,1402,3700,5267],
+ label: "Asia",
+ borderColor: "#8e5ea2",
+ fill: false
+ }, {
+ data: [168,170,178,190,203,276,408,547,675,734],
+ label: "Europe",
+ borderColor: "#3cba9f",
+ fill: false
+ }, {
+ data: [40,20,10,16,24,38,74,167,508,784],
+ label: "Latin America",
+ borderColor: "#e8c3b9",
+ fill: false
+ }, {
+ data: [6,3,2,2,7,26,82,172,312,433],
+ label: "North America",
+ borderColor: "#c45850",
+ fill: false
+ }
+ ]
+ },
+ /*options: {
+ title: {
+ display: true,
+ text: 'World population per region (in millions)'
+ }
+ }*/
+
+ });
+
+ }
+} \ No newline at end of file
diff --git a/frontend/src/app/scatterchart/scatterchart.component.css b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css
index 5735217e..5735217e 100644
--- a/frontend/src/app/scatterchart/scatterchart.component.css
+++ b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css
diff --git a/frontend/src/app/scatterchart/scatterchart.component.html b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html
index 2b30fe1f..2b30fe1f 100644
--- a/frontend/src/app/scatterchart/scatterchart.component.html
+++ b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html
diff --git a/frontend/src/app/scatterchart/scatterchart.component.spec.ts b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.spec.ts
index 1db81051..1db81051 100644
--- a/frontend/src/app/scatterchart/scatterchart.component.spec.ts
+++ b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.spec.ts
diff --git a/frontend/src/app/scatterchart/scatterchart.component.ts b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.ts
index 9dfef4c3..9dfef4c3 100644
--- a/frontend/src/app/scatterchart/scatterchart.component.ts
+++ b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.ts
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html
deleted file mode 100644
index bff8b022..00000000
--- a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<div class="row mb-4">
- <div class="col-2">
- </div>
- <div class="col-3">
- <label for="name" class="col-form-label">Naziv dataseta:</label>
- <input type="text" class="form-control mb-1" name="name" placeholder="Naziv..." [(ngModel)]="dataset.name">
-
- <label for="desc" class="col-sm-2 col-form-label">Opis:</label>
- <div>
- <textarea class="form-control" name="desc" rows="3" [(ngModel)]="dataset.description"></textarea>
- </div>
-
- <label for="checkboxIsPublic" class="form-check-label mt-3 mb-1">Želite li da dataset bude javan?
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="dataset.isPublic" (change)="checkAccessible()" type="checkbox"
- value="" id="checkboxIsPublic">
- </label>
-
- <label for="checkboxAccessibleByLink" class="form-check-label">Želite li da bude deljiv linkom? &nbsp;
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="dataset.accessibleByLink" type="checkbox"
- value="" id="checkboxAccessibleByLink">
- </label>
- </div>
- <div class="col-1">
- </div>
- <div class="col-4 mt-4">
-
- <input list="delimiterOptions" placeholder="Izaberite ili ukucajte delimiter za .csv fajl" class="form-control mt-2"
- [(ngModel)]="dataset.delimiter" (input)="update()">
- <datalist id="delimiterOptions">
- <option *ngFor="let option of delimiterOptions">{{option}}</option>
- </datalist>
-
- <label for="type" class="form-check-label my-5">Da li .csv ima header?
- <input class="mx-3 form-check-input" type="checkbox" (input)="update()" [(ngModel)]="dataset.hasHeader" type="checkbox"
- value="" id="checkboxHeader" checked>
- </label>
- <br>
- <input id="fileInput" class="form-control" type="file" class="upload" (change)="changeListener($event)"
- accept=".csv">
- </div>
-</div>
-
-<div class="px-5 mt-5">
- <app-datatable [tableData]="tableData"></app-datatable>
-</div>
-
-<div class="d-flex flex-row align-items-center justify-content-center w-100 my-2">
- <button (click)="uploadDataset()" class="btn btn-lg col-4" style="background-color:#003459; color:white;">Dodaj izvor podataka</button>
-</div>
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.css b/frontend/src/app/_elements/annvisual/annvisual.component.css
deleted file mode 100644
index 857a3390..00000000
--- a/frontend/src/app/_elements/annvisual/annvisual.component.css
+++ /dev/null
@@ -1,4 +0,0 @@
-#graph{
- width: 100%;
- text-align: center;
-} \ No newline at end of file
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.html b/frontend/src/app/_elements/annvisual/annvisual.component.html
deleted file mode 100644
index 09251398..00000000
--- a/frontend/src/app/_elements/annvisual/annvisual.component.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div style="text-align: center; " >
- <button (click)="d3()" mat-raised-button color="primary">Prikaz veštačke neuronske mreže</button>
- <div id="graph" align-items-center style="width: 12rem;"></div>
- </div>
-
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.ts b/frontend/src/app/_elements/annvisual/annvisual.component.ts
deleted file mode 100644
index df0a3898..00000000
--- a/frontend/src/app/_elements/annvisual/annvisual.component.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { Component, OnInit, Input } from '@angular/core';
-import Model from 'src/app/_data/Model';
-import { graphviz } from 'd3-graphviz';
-
-@Component({
- selector: 'app-annvisual',
- templateUrl: './annvisual.component.html',
- styleUrls: ['./annvisual.component.css']
-})
-export class AnnvisualComponent implements OnInit {
- ngOnInit(): void {
- }
-
- @Input() model: Model = new Model();
-
- d3() {
- let inputlayerstring: string = '';
- let hiddenlayerstring: string = '';
- let digraphstring: string = 'digraph {';
-
- for (let i = 0; i < /*this.model.inputColumns.length*/ 10; i++) {
- inputlayerstring = inputlayerstring + 'i' + i + ',';
- }
- inputlayerstring = inputlayerstring.slice(0, -1);
-
- digraphstring = digraphstring + inputlayerstring + '->';
-
- for (let j = 0; j < this.model.hiddenLayers; j++) {
- for (let i = 0; i < this.model.hiddenLayerNeurons; i++) {
- hiddenlayerstring = hiddenlayerstring + 'h' + j + '_' + i + ',';
- }
- hiddenlayerstring = hiddenlayerstring.slice(0, -1);
- digraphstring = digraphstring + hiddenlayerstring + '->';
- hiddenlayerstring = '';
- }
- digraphstring = digraphstring + 'o}';
-
- graphviz('#graph').renderDot(digraphstring);
- }
-
- //'digraph {i0,i1,i2->h1,h2,h3->h21,h22,h23->o}'
-}
-
-
-
diff --git a/frontend/src/app/_elements/carousel/carousel.component.html b/frontend/src/app/_elements/carousel/carousel.component.html
deleted file mode 100644
index eb1041ce..00000000
--- a/frontend/src/app/_elements/carousel/carousel.component.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<div class="container">
- <div class="row d-flex align-items-stretch flex-row mx-5 align-items-stretch">
- <div class="col my-1" *ngFor="let item of items" [ngSwitch]="type">
- <ng-template ngSwitchCase="Object">
- Unknown item type
- </ng-template>
- <ng-template ngSwitchCase="Dataset">
- <app-item-dataset [dataset]="item">
- </app-item-dataset>
- </ng-template>
- <ng-template ngSwitchCase="Predictor">
- <app-item-predictor [predictor]="item">
- </app-item-predictor>
- </ng-template>
- </div>
- </div>
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/carousel/carousel.component.ts b/frontend/src/app/_elements/carousel/carousel.component.ts
deleted file mode 100644
index e0112121..00000000
--- a/frontend/src/app/_elements/carousel/carousel.component.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-
-@Component({
- selector: 'app-carousel',
- templateUrl: './carousel.component.html',
- styleUrls: ['./carousel.component.css']
-})
-export class CarouselComponent {
-
- @Input() items: any[] = [];
- @Input() type: string = "Object";
-
- constructor() { }
-
- ngOnInit(): void {
- }
-
-}
diff --git a/frontend/src/app/_elements/column-table/column-table.component.css b/frontend/src/app/_elements/column-table/column-table.component.css
new file mode 100644
index 00000000..108efb32
--- /dev/null
+++ b/frontend/src/app/_elements/column-table/column-table.component.css
@@ -0,0 +1,223 @@
+table.fixed {
+ table-layout: fixed;
+ display: block;
+ overflow-x: auto;
+ white-space: nowrap;
+ border: 1px solid var(--ns-primary-50);
+ font-size: 12px;
+ border-radius: 4px;
+}
+
+#divTable {
+ height: 100%;
+ overflow-y: auto;
+}
+
+table.fixed td {
+ overflow: hidden;
+ max-width: 200px;
+ min-width: 200px;
+ vertical-align: middle;
+ background-color: var(--ns-bg-dark-100);
+ margin: 4px;
+}
+
+table.fixed th {
+ overflow: hidden;
+ max-width: 120px;
+ min-width: 120px;
+ vertical-align: middle;
+ background-color: var(--ns-bg-dark-100);
+ font-size: 14px;
+}
+
+table.fixed th:first-child {
+ text-align: center;
+ background-color: var(--ns-primary-25);
+}
+
+.columnNames {
+ background-color: var(--ns-primary-50) !important;
+}
+
+.brighter {
+ background-color: var(--ns-primary) !important;
+ border-color: var(--offwhite);
+}
+
+.border-bottom {
+ border-bottom-color: var(--offwhite) !important;
+}
+
+mat-slider {
+ width: 300px;
+}
+
+.slider {
+ background-color: var(--ns-bg-dark-100);
+}
+
+#missingValuesHeader {
+ font-size: 12px;
+ line-height: 110% !important;
+}
+
+.verticalAlign {
+ vertical-align: center;
+}
+
+.cell-align {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ vertical-align: middle;
+ height: 100%;
+}
+
+.text-left {
+ text-align: left !important;
+}
+
+table ::ng-deep .mat-form-field-wrapper {
+ margin-top: -2rem;
+}
+
+.graphics-row {
+ height: 100px;
+ padding: 1px;
+ margin: 0;
+}
+
+.no-pad {
+ padding: 1px;
+ margin: 0;
+}
+
+.text-overflow {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.row-height {
+ height: 30px;
+ border: none;
+ outline: none;
+}
+
+.graphic-class {
+ background-color: white !important;
+}
+
+
+/* TABS STYLE */
+
+#folder-table {
+ border: 1px solid var(--ns-primary);
+ border-radius: 4px;
+ height: 70%;
+}
+
+#tabs {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-end;
+ height: 3.2rem;
+}
+
+#tabs>.folder-tab:not(:first-child) {
+ margin-left: -5px;
+}
+
+.folder-tab-end {
+ margin-left: auto;
+ color: var(--offwhite) !important;
+ overflow: hidden;
+}
+
+.folder-tab,
+.folder-tab-end {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ position: relative;
+ overflow-x: hidden;
+ height: 2.5rem;
+ background-color: var(--ns-bg-dark-100);
+ border-color: var(--ns-primary);
+ color: var(--ns-primary);
+ border-style: solid;
+ border-width: 1px 1px 0 1px;
+}
+
+.folder-tab:not(:first-child) {
+ margin-block-start: auto;
+}
+
+.folder-tab {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.selected-tab {
+ height: 3rem;
+ background-color: var(--ns-primary);
+ color: var(--offwhite);
+}
+
+.hover-tab {
+ height: 3.2rem;
+}
+
+.selected-tab,
+.hover-tab {
+ width: fit-content !important;
+}
+
+.tab-link {
+ color: var(--offwhite) !important;
+ text-decoration: none !important;
+ cursor: pointer;
+}
+
+.tab-link:active {
+ text-decoration: underline !important;
+}
+
+.selected-tab {
+ background-color: var(--ns-primary);
+}
+
+.hidden {
+ visibility: hidden;
+ height: 1px;
+}
+
+.bottom-button {
+ font-size: large;
+ position: relative;
+ background-color: var(--ns-primary);
+ width: 10rem;
+ height: 2.3rem;
+ border-color: var(--ns-primary);
+ border-style: solid;
+ border-width: 0px 1px 1px 1px;
+}
+
+#footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+}
+
+.pad-fix {
+ padding-top: 0.6rem;
+ padding-bottom: 0;
+}
+
+.long {
+ height: 3rem;
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/column-table/column-table.component.html b/frontend/src/app/_elements/column-table/column-table.component.html
new file mode 100644
index 00000000..53cb3551
--- /dev/null
+++ b/frontend/src/app/_elements/column-table/column-table.component.html
@@ -0,0 +1,243 @@
+<div id="tabs">
+ <div class="folder-tab p-1 rounded-top" *ngFor="let tab of tabs; let i = index" [style]="'z-index:' + calcZIndex(i) + ' ;'" [ngClass]="{'selected-tab' : selectedTab.index == i, 'hover-tab' : hoveringOverTab?.index == i}">
+ <a class="m-1 stretched-link tab-link" (click)="selectTab(i)" (mouseenter)="hoverOverTab(i)" (mouseleave)="hoverOverTab(-1)">
+ {{tab.name}}
+ </a>
+ </div>
+ <button mat-button class="p-1 folder-tab-end rounded-top">
+ Kolone
+ <mat-icon>keyboard_double_arrow_down</mat-icon>
+ <!--meni ovde-->
+ </button>
+</div>
+<div id="folder-table" *ngIf="dataset && experiment">
+ <!--<div [ngSwitch]="tabToDisplay">-->
+ <div id="divTable">
+
+ <div [ngClass]="{'hidden': tabToDisplay != Table.Data}">
+ <table class="table text-offwhite fixed bg-blur">
+ <thead>
+ <tr>
+ <th>#</th>
+ <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index">
+ <div class="cell-align">
+ #{{i + 1}}&nbsp;&nbsp;{{colInfo.columnName}}
+ <mat-checkbox color="primary" checked (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox>
+ </div>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let row of tableData; let i = index">
+ <th>#{{i}}</th>
+ <td *ngFor="let col of row; let j = index">
+ <div class="text-overflow">
+ {{col}}
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div [ngClass]="{'hidden': tabToDisplay != Table.CorrelationMatrix}">
+ <table class="table text-offwhite fixed bg-blur">
+ <thead>
+ <tr>
+ <th>Naziv</th>
+ <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index">
+ #{{i + 1}}&nbsp;&nbsp;{{colInfo.columnName}}
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let colInfo of dataset.columnInfo; let i = index">
+ <th>
+ <div class="text-left">
+ {{colInfo.columnName}}
+ </div>
+ </th>
+ <td *ngFor="let colInfo of dataset.columnInfo; let j = index">
+ <div class="text-overflow">
+ 0.1
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div [ngClass]="{'hidden': tabToDisplay != Table.Columns}">
+ <table class="table text-offwhite fixed bg-blur">
+ <thead>
+ <tr>
+ <th>Naziv</th>
+ <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index">
+ <div class="cell-align">
+ #{{i + 1}}&nbsp;&nbsp;{{colInfo.columnName}}
+ <mat-checkbox color="primary" checked (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox>
+ </div>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>Tip</th>
+ <td *ngFor="let colInfo of dataset.columnInfo; let i = index" class="pad-fix">
+ <mat-form-field>
+ <mat-select matNativeControl [(value)]="colInfo.isNumber">
+ <mat-option [value]="false">Kategorijski</mat-option>
+ <mat-option [value]="true">Numerički</mat-option>
+ </mat-select>
+ </mat-form-field>
+ </td>
+ </tr>
+ <tr class="graphics-row">
+ <th class="no-pad border-bottom">Grafik</th>
+ <td class="graphic-class no-pad" *ngFor="let colInfo of dataset.columnInfo; let i = index">
+ <app-box-plot *ngIf="colInfo.isNumber" [width]="150" [height]="150"></app-box-plot>
+ <app-pie-chart *ngIf="!colInfo.isNumber" [width]="150" [height]="150"></app-pie-chart>
+ </td>
+ </tr>
+ <tr>
+ <th class="brighter">Statistika</th>
+ <td *ngFor="let colInfo of dataset.columnInfo; let i = index">
+ <span *ngIf="colInfo.isNumber">
+ Mean: {{colInfo.mean}}<br>
+ Median: {{colInfo.median}}<br>
+ Min: {{colInfo.min}}<br>
+ Max: {{colInfo.max}}<br>
+ <!-- TODO na ML-u: Q1 i Q3 u statistici
+ Q1: {{colInfo.q1}}<br>
+ Q3: {{colInfo.q3}}<br>
+ -->
+ </span>
+ <div class="text-overflow" *ngIf="!colInfo.isNumber">
+ <span *ngFor="let uniqueValue of colInfo.uniqueValues | slice:0:6; let i = index">
+ {{uniqueValue}}<br><!-- TODO na ML-u: broj ponavljanja unique values-a u zagradi nek pise -->
+ </span>
+ </div>
+ </td>
+ </tr>
+ <tr style="padding: 0">
+ <th class="brighter cell-align long" (click)="openEncodingDialog()">
+ <span class="verticalAlign">Enkodiranje</span>&nbsp;
+ <span class="material-icons-round verticalAlign">settings</span>
+ </th>
+ <td *ngFor="let colInfo of dataset.columnInfo; let i = index" class="pad-fix">
+ <mat-form-field>
+ <mat-select matNativeControl [(value)]="experiment.encodings[i].encoding">
+ <mat-option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </td>
+ </tr>
+ <tr>
+ <th class="brighter cell-align" (click)="openMissingValuesDialog()">
+ <div id="missingValuesHeader">Regulisanje<br>nedostajućih<br>vrednosti<br></div>
+ <span class="material-icons-round">settings</span>
+ </th>
+ <td *ngFor="let colInfo of dataset.columnInfo; let i = index">
+
+ <button class="w-100" mat-raised-button [matMenuTriggerFor]="menu" id="main_{{colInfo.columnName}}" #nullValMenu>
+ <div class="cell-align">
+ {{nullValOption[i]}}
+ <mat-icon>arrow_drop_down</mat-icon>
+ </div>
+ </button>
+ <mat-menu #menu="matMenu">
+ <button mat-menu-item (click)="MissValsDeleteClicked($event, NullValueOptions.DeleteColumns, i)" value={{colInfo.columnName}}>Obriši kolonu</button>
+ <button mat-menu-item (click)="MissValsDeleteClicked($event, NullValueOptions.DeleteRows, i)" value={{colInfo.columnName}}>Obriši redove</button>
+ <button mat-menu-item [matMenuTriggerFor]="fillWith">Popuni sa ____</button>
+ </mat-menu>
+
+ <mat-menu #fillWith="matMenu">
+ <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.mean}}>Mean ({{colInfo.mean}})</button>
+ <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.median}}>Median ({{colInfo.median}})</button>
+ <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.max}}>Max ({{colInfo.max}})</button>
+ <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.min}}>Min ({{colInfo.min}})</button>
+
+ <button *ngIf="!colInfo.isNumber" mat-menu-item [matMenuTriggerFor]="uniques">Najčešće vrednosti</button>
+
+ <button mat-menu-item [matMenuTriggerFor]="replaceWith">Unesi vrednost...</button>
+ </mat-menu>
+
+ <mat-menu #uniques="matMenu">
+ <button mat-menu-item *ngFor="let uniqueValue of colInfo.uniqueValues" (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{uniqueValue}}>{{uniqueValue}}</button>
+ </mat-menu>
+
+ <mat-menu #replaceWith="matMenu">
+ <input type="text" id={{colInfo.columnName}} mat-menu-item placeholder="Unesi vrednost..." [value]>
+ <button [disabled]="getValue(colInfo.columnName) == ''" mat-menu-item value={{getValue(colInfo.columnName)}} (click)="MissValsReplaceClicked($event, colInfo.columnName, i)">Potvrdi unos</button>
+ </mat-menu>
+
+ </td>
+ </tr>
+ <!--<tr class="row-height" *ngFor="let row of tableData; let i = index">
+ <th *ngIf="i == 0" [attr.rowspan]="tableData!.length">Vrednosti</th>
+
+
+ <td class="text-center" *ngFor="let col of row; let j = index">
+ <div class="text-overflow">
+ {{col}}
+ </div>
+ </td>
+ </tr>-->
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="container-fluid text-offwhite belowColumn mt-3">
+ <div class="ns-row">
+ <div class="ns-col slider rounded" style="border:1px solid var(--ns-primary)">
+
+ <div class="text-center pt-3 pb-0 mb-0"><b>{{testSetDistribution}}%</b> : <b>{{100-testSetDistribution}}%</b></div>
+ <div class="text-center pt-0 mt-0">Trening
+ <mat-slider min="10" max="90" step="10" [(ngModel)]="testSetDistribution" (input)="updateTestSet($event)"></mat-slider>
+ Test</div>
+
+ </div>
+ <div class="ns-col slider rounded" style="border:1px solid var(--ns-primary);margin-left: 10px;">
+ <div class="text-center text-offwhite justify-content-center align-items-center">
+ <mat-checkbox class="pt-4" color="accent">Nasumični redosled podataka</mat-checkbox>
+ </div>
+ </div>
+
+ <div class="break-2"></div>
+
+ <div class="ns-col rounded">
+ <mat-form-field appearance="fill" class="align-items-center justify-content-center pt-3 w-100">
+ <mat-label>Tip problema</mat-label>
+ <mat-select value="ToDo1">
+ <mat-option value="ToDo1">Regresioni</mat-option>
+ <mat-option value="ToDo2">Binarni-Klasifikacioni</mat-option>
+ <mat-option value="ToDo3">Multi-Klasifikacioni</mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+ <div class="ns-col rounded">
+ <mat-form-field appearance="fill" class="align-items-center justify-content-center pt-3 w-100">
+ <mat-label>Izlazna kolona</mat-label>
+ <mat-select>
+ <mat-option *ngFor="let item of dataset?.columnInfo" [value]="item.columnName">{{item.columnName}}</mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+ <div class="break-1"></div>
+ <div class="ns-col d-flex align-items-center justify-content-center">
+ <button mat-button (click)="ok()" class="bottom-button text-offwhite rounded-bottom">
+ <div class="f-row" style="justify-content: space-around;">
+ <div>Potvrdi</div>
+ <div class="icon-double pt-1">
+ <mat-icon>check</mat-icon>
+ <mat-icon>check</mat-icon>
+ </div>
+ </div>
+ </button>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.spec.ts b/frontend/src/app/_elements/column-table/column-table.component.spec.ts
index 603889b2..360a8109 100644
--- a/frontend/src/app/_elements/item-dataset/item-dataset.component.spec.ts
+++ b/frontend/src/app/_elements/column-table/column-table.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ItemDatasetComponent } from './item-dataset.component';
+import { ColumnTableComponent } from './column-table.component';
-describe('ItemDatasetComponent', () => {
- let component: ItemDatasetComponent;
- let fixture: ComponentFixture<ItemDatasetComponent>;
+describe('ColumnTableComponent', () => {
+ let component: ColumnTableComponent;
+ let fixture: ComponentFixture<ColumnTableComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ ItemDatasetComponent ]
+ declarations: [ ColumnTableComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(ItemDatasetComponent);
+ fixture = TestBed.createComponent(ColumnTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/column-table/column-table.component.ts b/frontend/src/app/_elements/column-table/column-table.component.ts
new file mode 100644
index 00000000..9cabf190
--- /dev/null
+++ b/frontend/src/app/_elements/column-table/column-table.component.ts
@@ -0,0 +1,250 @@
+import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChildren } from '@angular/core';
+import Dataset from 'src/app/_data/Dataset';
+import Experiment, { ColumnEncoding, Encoding, NullValReplacer, NullValueOptions } from 'src/app/_data/Experiment';
+import { DatasetsService } from 'src/app/_services/datasets.service';
+import { EncodingDialogComponent } from 'src/app/_modals/encoding-dialog/encoding-dialog.component';
+import { MatDialog } from '@angular/material/dialog';
+import { MissingvaluesDialogComponent } from 'src/app/_modals/missingvalues-dialog/missingvalues-dialog.component';
+import { MatSliderChange } from '@angular/material/slider';
+import { MatCheckboxChange } from '@angular/material/checkbox';
+import { CsvParseService } from 'src/app/_services/csv-parse.service';
+
+@Component({
+ selector: 'app-column-table',
+ templateUrl: './column-table.component.html',
+ styleUrls: ['./column-table.component.css']
+})
+export class ColumnTableComponent implements AfterViewInit {
+
+ @Input() dataset?: Dataset;
+ @Input() experiment?: Experiment;
+ @ViewChildren("nullValMenu") nullValMenus!: ElementRef[];
+ @Output() okPressed: EventEmitter<string> = new EventEmitter();
+ Object = Object;
+ Encoding = Encoding;
+ NullValueOptions = NullValueOptions;
+ tableData?: any[][];
+ nullValOption: string[] = [];
+
+ testSetDistribution: number = 70;
+ constructor(private datasetService: DatasetsService, public csvParseService: CsvParseService, public dialog: MatDialog) {
+ //ovo mi nece trebati jer primam dataset iz druge komponente
+ }
+
+ ngAfterViewInit(): void {
+ this.datasetService.getMyDatasets().subscribe((datasets) => {
+ this.dataset = datasets[0];
+ this.experiment = new Experiment();
+
+ console.log(datasets);
+ for (let i = 0; i < this.dataset?.columnInfo.length; i++) {
+ this.experiment?.inputColumns.push(this.dataset.columnInfo[i].columnName);
+ }
+ this.resetColumnEncodings(Encoding.Label);
+ this.setDeleteColumnsForMissingValTreatment();
+
+ this.nullValOption = [].constructor(this.dataset.columnInfo.length).fill('Obriši redove');
+
+ this.datasetService.getDatasetFilePartial(this.dataset.fileId, 0, 10).subscribe((response: string | undefined) => {
+ if (response && this.dataset != undefined) {
+ this.tableData = this.csvParseService.csvToArray(response, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter.toString() == "") ? "," : this.dataset.delimiter);
+ }
+ });
+ });
+ }
+
+ setDeleteColumnsForMissingValTreatment() {
+ if (this.experiment != undefined) {
+ this.experiment.nullValues = NullValueOptions.DeleteRows;
+ this.experiment.nullValuesReplacers = [];
+ for (let i = 0; i < this.experiment.inputColumns.length; i++) {
+ this.experiment.nullValuesReplacers.push({
+ column: this.experiment.inputColumns[i],
+ option: NullValueOptions.DeleteRows,
+ value: ""
+ });
+ }
+ }
+ }
+
+ changeInputColumns(targetMatCheckbox: MatCheckboxChange, columnName: string) {
+ if (this.experiment != undefined) {
+ if (targetMatCheckbox.checked) {
+ if (this.experiment.inputColumns.filter(x => x == columnName)[0] == undefined) {
+ this.experiment.inputColumns.push(columnName);
+ }
+ }
+ else {
+ this.experiment.inputColumns = this.experiment.inputColumns.filter(x => x != columnName);
+ //console.log("Input columns: ", this.experiment.inputColumns);
+ //TODO: da se zatamni kolona koja je unchecked
+ //this.experiment.encodings = this.experiment.encodings.filter(x => x.columnName != columnName); samo na kraju iz enkodinga skloni necekirane
+ this.experiment.nullValuesReplacers = this.experiment.nullValuesReplacers.filter(x => x.column != columnName);
+ }
+ }
+ }
+
+ resetColumnEncodings(encodingType: Encoding) {
+ if (this.experiment != undefined && this.dataset != undefined) {
+ this.experiment.encodings = [];
+ for (let i = 0; i < this.dataset?.columnInfo.length; i++) {
+ this.experiment.encodings.push(new ColumnEncoding(this.dataset?.columnInfo[i].columnName, encodingType));
+ //console.log(this.experiment.encodings);
+ }
+ }
+ }
+ openEncodingDialog() {
+ const dialogRef = this.dialog.open(EncodingDialogComponent, {
+ width: '300px'
+ });
+ dialogRef.afterClosed().subscribe(selectedEncoding => {
+ if (selectedEncoding != undefined)
+ this.resetColumnEncodings(selectedEncoding);
+ });
+ }
+
+ resetMissingValuesTreatment(selectedMissingValuesOption: NullValueOptions) {
+ if (this.experiment != undefined && this.dataset != undefined) {
+
+ if (selectedMissingValuesOption == NullValueOptions.DeleteColumns) {
+ this.experiment.nullValues = NullValueOptions.DeleteColumns;
+ this.experiment.nullValuesReplacers = [];
+ for (let i = 0; i < this.experiment.inputColumns.length; i++) {
+ this.experiment.nullValuesReplacers.push({
+ column: this.experiment.inputColumns[i],
+ option: NullValueOptions.DeleteColumns,
+ value: ""
+ });
+ this.nullValOption[i] = "Obriši kolonu";
+ }
+ }
+ else if (selectedMissingValuesOption == NullValueOptions.DeleteRows) {
+ this.experiment.nullValues = NullValueOptions.DeleteRows;
+ this.experiment.nullValuesReplacers = [];
+ for (let i = 0; i < this.experiment.inputColumns.length; i++) {
+ this.experiment.nullValuesReplacers.push({
+ column: this.experiment.inputColumns[i],
+ option: NullValueOptions.DeleteRows,
+ value: ""
+ });
+ this.nullValOption[i] = "Obriši redove";
+ }
+ }
+ }
+ }
+ openMissingValuesDialog() {
+ const dialogRef = this.dialog.open(MissingvaluesDialogComponent, {
+ width: '400px'
+ });
+ dialogRef.afterClosed().subscribe(selectedMissingValuesOption => {
+ if (selectedMissingValuesOption != undefined)
+ this.resetMissingValuesTreatment(selectedMissingValuesOption);
+ });
+ }
+ updateTestSet(event: MatSliderChange) {
+ this.testSetDistribution = event.value!;
+ }
+
+
+ MissValsDeleteClicked(event: Event, replacementType: NullValueOptions, index: number) {
+ if (this.experiment != undefined) {
+ let columnName = (<HTMLInputElement>event.currentTarget).value;
+ let arrayElement = this.experiment.nullValuesReplacers.filter(x => x.column == columnName)[0];
+
+ if (arrayElement == undefined) {
+ this.experiment.nullValuesReplacers.push({
+ column: columnName,
+ option: (replacementType == NullValueOptions.DeleteColumns) ? NullValueOptions.DeleteColumns : NullValueOptions.DeleteRows,
+ value: ""
+ });
+ }
+ else {
+ arrayElement.option = (replacementType == NullValueOptions.DeleteColumns) ? NullValueOptions.DeleteColumns : NullValueOptions.DeleteRows;
+ arrayElement.value = "";
+ }
+
+ this.nullValOption[index] = (replacementType == NullValueOptions.DeleteColumns) ? "Obriši kolonu" : "Obriši redove";
+ }
+ }
+
+ MissValsReplaceClicked(event: Event, columnName: string, index: number) {
+ if (this.experiment != undefined) {
+ let fillValue = (<HTMLInputElement>event.currentTarget).value;
+ let arrayElement = this.experiment.nullValuesReplacers.filter(x => x.column == columnName)[0];
+
+ if (arrayElement == undefined) {
+ this.experiment.nullValuesReplacers.push({
+ column: columnName,
+ option: NullValueOptions.Replace,
+ value: fillValue
+ });
+ }
+ else {
+ arrayElement.option = NullValueOptions.Replace;
+ arrayElement.value = fillValue;
+ }
+
+ this.nullValOption[index] = "Popuni sa: " + fillValue;
+ }
+ }
+ getValue(columnName: string): string {
+ if (<HTMLInputElement>document.getElementById(columnName) != undefined)
+ return (<HTMLInputElement>document.getElementById(columnName)).value;
+ return '0';
+ }
+ ok() {
+ this.okPressed.emit();
+ }
+
+
+ tabs = [
+ new Tab(0, 'Podešavanja kolona', Table.Columns),
+ new Tab(1, 'Podaci', Table.Data),
+ new Tab(2, 'Korelaciona matrica', Table.CorrelationMatrix)
+ ]
+
+ selectedTab: Tab = this.tabs[0];
+ hoveringOverTab: (Tab | null) = null;
+
+ tabToDisplay: Table = Table.Columns;
+
+ selectTab(index: number) {
+ this.selectedTab = this.tabs[index];
+ this.tabToDisplay = this.tabs[index].value;
+ }
+
+ hoverOverTab(index: number) {
+ if (index < 0) {
+ this.hoveringOverTab = null;
+ this.tabToDisplay = this.selectedTab.value;
+ } else {
+ this.hoveringOverTab = this.tabs[index];
+ this.tabToDisplay = this.tabs[index].value;
+ }
+ }
+
+ calcZIndex(i: number) {
+ let zIndex = (this.tabs.length - i - 1)
+ if (this.selectedTab.index == i)
+ zIndex = this.tabs.length + 1;
+ if (this.hoveringOverTab?.index == i)
+ zIndex = this.tabs.length + 2;
+ return zIndex;
+ }
+
+ Table = Table;
+}
+
+export enum Table {
+ Columns,
+ Data,
+ CorrelationMatrix
+}
+
+export class Tab {
+ constructor(
+ public index: number,
+ public name: string,
+ public value: Table
+ ) { }
+}
diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.css b/frontend/src/app/_elements/dataset-load/dataset-load.component.css
deleted file mode 100644
index ff6e2750..00000000
--- a/frontend/src/app/_elements/dataset-load/dataset-load.component.css
+++ /dev/null
@@ -1,18 +0,0 @@
-.btnType1 {
- background-color: #003459;
- color: white;
- padding-top: 2vh;
- padding-bottom: 2vh;
-}
-.btnType2 {
- background-color: white;
- color: #003459;
- border-color: #003459;
- padding-top: 2vh;
- padding-bottom: 2vh;
-
-}
-.selectedDatasetClass {
- /*border-color: 2px solid #003459;*/
- background-color: lightblue;
-} \ No newline at end of file
diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.html b/frontend/src/app/_elements/dataset-load/dataset-load.component.html
deleted file mode 100644
index 56a3b3c9..00000000
--- a/frontend/src/app/_elements/dataset-load/dataset-load.component.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<div>
-
- <!--Sklonjeno ucitavanje novog dataseta i sve opcije u vezi sa tim, premesteno u add-new-dataset-->
-
- <div class="d-flex flex-row justify-content-center align-items-center mt-3 mb-5">
- <button type="button" id="btnMyDataset" class="btn" (click)="viewMyDatasetsForm()"
- [ngClass]="{'btnType1': showMyDatasets, 'btnType2': !showMyDatasets}">
- Izaberite dataset iz kolekcije
- </button>
- <h3 class="mt-3 mx-3">ili</h3>
- <button type="button" id="btnNewDataset" class="btn" (click)="viewNewDatasetForm()"
- [ngClass]="{'btnType1': !showMyDatasets, 'btnType2': showMyDatasets}">
- Dodajte novi dataset
- </button>
- </div>
-
- <div class="px-5 my-2">
- <input *ngIf="showMyDatasets" type="text" class="form-control" placeholder="Pretraga"
- [(ngModel)]="term">
- </div>
- <div class="px-5" *ngIf="showMyDatasets">
- <div class="overflow-auto" style="max-height: 500px;">
- <ul class="list-group">
- <li class="list-group-item p-3" *ngFor="let dataset of myDatasets|filter:term"
- [ngClass]="{'selectedDatasetClass': this.selectedDataset == dataset}">
- <app-item-dataset name="usersDataset" [dataset]="dataset"
- (click)="selectThisDataset(dataset);"></app-item-dataset>
- </li>
- </ul>
- </div>
- <div class="px-5 mt-5">
- <app-datatable [tableData]="tableData"></app-datatable>
- </div>
- </div>
-
- <app-add-new-dataset [style]="(showMyDatasets)?'display:none;visibility:hidden;':''" id="dataset"
- (newDatasetAdded)="refreshMyDatasets()">
- </app-add-new-dataset>
-
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/datatable/datatable.component.html b/frontend/src/app/_elements/datatable/datatable.component.html
index 8db62aff..17a187ef 100644
--- a/frontend/src/app/_elements/datatable/datatable.component.html
+++ b/frontend/src/app/_elements/datatable/datatable.component.html
@@ -1,18 +1,16 @@
-<div *ngIf="tableData.hasInput">
- <div>
- <div *ngIf="!tableData.loaded" backgroundColor="secondary" style="width: 100%; height: 100%;"
- class="d-flex justify-content-center align-items-center">
+<div *ngIf="tableData.hasInput" class="position-relative">
+ <div class="text-white">
+ <div *ngIf="!tableData.loaded" style="width: 100%; height: 100%;" class="d-flex justify-content-center align-items-center">
<app-loading></app-loading>
</div>
<div *ngIf="tableData.loaded && tableData.data">
- <div id="info" *ngIf="tableData.data.length > 0 && tableData.data[0].length > 0"
- class="d-flex flex-row justify-content-center align-items-center">
+ <div id="info" *ngIf="tableData.data.length > 0 && tableData.data[0].length > 0" class="d-flex flex-row justify-content-center align-items-center">
<div class="fs-5 mb-3">
Tabela {{tableData.numCols}}x{{tableData.numRows}}
</div>
</div>
- <div class="table-responsive" style="overflow: auto; border-radius: 5px;">
- <table *ngIf="tableData.data.length > 0 && tableData.hasHeader && tableData.data[0].length > 0" class="table table-bordered table-light">
+ <div style="border-radius: 5px; overflow-x: auto; overflow-y: hidden;">
+ <table *ngIf="tableData.data.length && tableData.data[0].length > 0" class="table table-responsive table-sm text-offwhite row-height">
<thead>
<tr>
<th *ngFor="let item of tableData.data[0]; let i = index">{{item}}</th>
@@ -22,22 +20,12 @@
<tr *ngFor="let row of tableData.data | slice:1">
<td *ngFor="let col of row">{{col}}</td>
</tr>
- <tr>
- <td colspan="100" class="text-lg-center fs-6">+ {{tableData.numRows - 11}} redova...</td>
- </tr>
- </tbody>
- </table>
- <table *ngIf="tableData.data.length > 0 && !tableData.hasHeader && tableData.data[0].length > 0" class="table table-bordered table-light">
- <tbody>
- <tr *ngFor="let row of tableData.data">
- <td *ngFor="let col of row">{{col}}</td>
- </tr>
- <tr>
- <td colspan="100" class="text-lg-center fs-6">+ {{tableData.numRows - 10}} redova...</td>
- </tr>
</tbody>
</table>
</div>
+ <div class="footer-center" >
+ <div>+ {{tableData.numRows - 11}} redova...</div>
+ </div>
</div>
</div>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/folder/folder.component.css b/frontend/src/app/_elements/folder/folder.component.css
new file mode 100644
index 00000000..137a9643
--- /dev/null
+++ b/frontend/src/app/_elements/folder/folder.component.css
@@ -0,0 +1,189 @@
+#folder {
+ /*position: absolute;
+ left: 50%;
+ transform: translateX(-50%);*/
+}
+
+#tabs {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-end;
+ height: 3.1rem;
+}
+
+#tabs>.folder-tab:not(:first-child) {
+ margin-left: -5px;
+}
+
+.folder-tab {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ position: relative;
+ height: 2.5rem;
+ background-color: var(--ns-bg-dark-100);
+ border-color: var(--ns-primary);
+ color: var(--ns-primary);
+ border-style: solid;
+ border-width: 1px 1px 0 1px;
+}
+
+.folder-tab:not(:first-child) {
+ margin-block-start: auto;
+}
+
+.selected-tab {
+ height: 3rem;
+ background-color: var(--ns-primary);
+ color: var(--offwhite);
+}
+
+.hover-tab {
+ height: 3.2rem;
+}
+
+.selected-tab,
+.hover-tab {
+ width: fit-content !important;
+}
+
+.tab-link {
+ color: var(--offwhite) !important;
+ text-decoration: none !important;
+ cursor: pointer;
+ padding: 0.5rem;
+}
+
+.tab-link:active {
+ text-decoration: underline !important;
+}
+
+.selected-tab {
+ background-color: var(--ns-primary);
+}
+
+#searchbar {
+ height: 2.5rem;
+ background-color: var(--ns-bg-dark-100);
+ border-bottom: 1px solid var(--ns-primary);
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ width: 100%;
+}
+
+.collapse-horizontal {
+ white-space: nowrap;
+ height: 2.5rem;
+ overflow-x: hidden;
+}
+
+#search-options {
+ margin-left: auto;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 100%;
+}
+
+#selected-content {
+ background-color: var(--ns-bg-dark-50);
+ width: 100%;
+ /*backdrop-filter: blur(2px);*/
+ border-color: var(--ns-primary);
+ border-style: solid;
+ border-width: 1px 1px 1px 1px;
+ border-top-right-radius: 4px;
+}
+
+#footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+}
+
+.bottom-button {
+ font-size: large;
+ position: relative;
+ background-color: var(--ns-primary);
+ width: 10rem;
+ height: 2.3rem;
+ border-color: var(--ns-primary);
+ border-style: solid;
+ border-width: 0px 1px 1px 1px;
+}
+
+.rounded-bottom {
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+}
+
+.separator {
+ border-left-color: var(--ns-primary);
+ border-left-width: 1px;
+ border-left-style: solid;
+}
+
+.list-view {
+ height: 100%;
+ overflow-y: auto;
+}
+
+.list-item {
+ height: 3rem;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ border-bottom: 1px solid var(--ns-primary);
+}
+
+.list-item:hover {
+ background-color: var(--ns-bg-dark-100);
+ box-shadow: 0px 3px 3px var(--ns-primary);
+}
+
+.list-item:hover>.hover-hide {
+ display: none;
+}
+
+.folder-inside {
+ width: 100%;
+ height: 40rem;
+ overflow-y: auto;
+}
+
+.file-content {
+ width: 100%;
+ height: 92%;
+ position: relative;
+}
+
+.file-bottom-buttons {
+ position: absolute;
+ bottom: 15px;
+ right: 15px;
+ display: flex;
+ flex-direction: row-reverse;
+}
+
+.file-button {
+ position: relative;
+ color: var(--offwhite);
+ border-radius: 4px;
+ border: 1px solid var(--ns-primary);
+ margin: 5px;
+ padding: 5px;
+ cursor: pointer;
+ z-index: 1001;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
+
+.file-button:hover {
+ background-color: var(--ns-primary);
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/folder/folder.component.html b/frontend/src/app/_elements/folder/folder.component.html
new file mode 100644
index 00000000..36f70c97
--- /dev/null
+++ b/frontend/src/app/_elements/folder/folder.component.html
@@ -0,0 +1,99 @@
+<div id="folder">
+ <div id="tabs">
+ <div id="new-file-tab" class="folder-tab p-1 rounded-top" [style]="'z-index:' + (selectedTab == TabType.NewFile ? 11 : 10) + ' ;'" [ngClass]="{'selected-tab' : selectedTab == TabType.NewFile, 'hover-tab' : hoverTab == TabType.NewFile}">
+ <mat-icon class="text-offwhite">add</mat-icon>
+ <a class="stretched-link tab-link" (click)="selectTab(TabType.NewFile)" (mouseenter)="hoverOverTab(TabType.NewFile)" (mouseleave)="hoverOverTab(TabType.None)">
+ {{tabTitles[TabType.NewFile]}}
+ </a>
+ </div>
+ <!--<div class="folder-tab p-1 rounded-top" *ngFor="let file of filteredFiles; let i = index" [style]="'z-index:' + calcZIndex(i) + ' ;'" [ngClass]="{'selected-tab' : selectedFileIndex == i, 'hover-tab' : hoveringOverFileIndex == i}">
+ <a class="m-1 stretched-link tab-link" (click)="selectFile(i)" (mouseenter)="hoverOverFile(i)" (mouseleave)="hoverOverFile(-1)">{{file.name}}</a>
+ </div>-->
+ <div class="folder-tab p-1 rounded-top" *ngFor="let tab of tabsToShow; let i = index" [style]="'z-index:' + (selectedTab == tab ? 11 : (tabsToShow.length - i)) + ' ;'" [ngClass]="{'selected-tab' : selectedTab == tab, 'hover-tab' : hoverTab == tab}">
+ <a class="m-1 stretched-link tab-link" (click)="selectTab(tab)" (mouseenter)="hoverOverTab(tab)" (mouseleave)="hoverOverTab(TabType.None)">{{tabTitles[tab]}}</a>
+ </div>
+ </div>
+ <div id="selected-content" class="rounded-bottom text-offwhite">
+ <div id="searchbar" *ngIf="listView">
+ <!-- <div id="path" class="ps-2">{{folderName}}
+ </div>
+ <mat-icon>keyboard_arrow_right</mat-icon> -->
+ <div id="search" class="text-offwhite mx-1">
+ <mat-form-field>
+ <button matPrefix class="btn-clear input-icon"><mat-icon>search</mat-icon></button>
+ <input type="search" matInput name="search" [(ngModel)]="searchTerm" (input)="searchTermsChanged()">
+ <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">
+ <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>
+ <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">
+ [sort options here TODO]
+ </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()">
+ <mat-icon>view_list</mat-icon>
+ </button> -->
+ </div>
+ </div>
+ <!--{{fileToDisplay ? fileToDisplay.name : 'No file selected.'}} {{selectedFileIndex}} {{hoveringOverFileIndex}}-->
+ <div [ngSwitch]="listView" class="folder-inside bg-blur">
+ <div class="file-content" [ngSwitch]="type" *ngSwitchCase="false">
+ <div class="file-bottom-buttons">
+ <button class="btn-clear file-button" (click)="deleteFile()">
+ <mat-icon>delete</mat-icon>
+ </button>
+ <button class="btn-clear file-button">
+ <mat-icon>link</mat-icon>
+ </button>
+ <button class="btn-clear file-button">
+ <mat-icon>zoom_out_map</mat-icon>
+ </button>
+ </div>
+ <app-form-model [forExperiment]="forExperiment" [model]="fileToDisplay" *ngSwitchCase="FolderType.Model"></app-form-model>
+ <app-form-dataset *ngSwitchCase="FolderType.Dataset" ></app-form-dataset>
+ </div>
+ <div *ngSwitchCase="true" class="list-view">
+ <div *ngFor="let file of filteredFiles; let i = index" class="list-item">
+ <div class="mx-2">
+ <a class="force-link" (click)="selectFile(i)">{{file.name}}</a>
+ </div>
+ <div class="mx-2 hover-hide">
+ {{file.lastUpdated | date}}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="footer" [ngSwitch]="newFileSelected">
+ <button mat-button (click)="saveNewFile()" class="bottom-button text-offwhite rounded-bottom" *ngSwitchCase="true">
+ <div class="f-row">
+ <div>Sačuvaj</div>
+ <div class="pt-1">
+ <mat-icon>check</mat-icon>
+ </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>
+ </div>
+ </div>
+ </button>
+ </div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/carousel/carousel.component.spec.ts b/frontend/src/app/_elements/folder/folder.component.spec.ts
index 9196e044..33a573a7 100644
--- a/frontend/src/app/_elements/carousel/carousel.component.spec.ts
+++ b/frontend/src/app/_elements/folder/folder.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { CarouselComponent } from './carousel.component';
+import { FolderComponent } from './folder.component';
-describe('CarouselComponent', () => {
- let component: CarouselComponent;
- let fixture: ComponentFixture<CarouselComponent>;
+describe('FolderComponent', () => {
+ let component: FolderComponent;
+ let fixture: ComponentFixture<FolderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ CarouselComponent ]
+ declarations: [ FolderComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(CarouselComponent);
+ fixture = TestBed.createComponent(FolderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/folder/folder.component.ts b/frontend/src/app/_elements/folder/folder.component.ts
new file mode 100644
index 00000000..06b4d893
--- /dev/null
+++ b/frontend/src/app/_elements/folder/folder.component.ts
@@ -0,0 +1,276 @@
+import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
+import Dataset from 'src/app/_data/Dataset';
+import { FolderFile, FolderType } from 'src/app/_data/FolderFile';
+import Model from 'src/app/_data/Model';
+import { DatasetsService } from 'src/app/_services/datasets.service';
+import shared from 'src/app/Shared';
+import { ModelsService } from 'src/app/_services/models.service';
+import { FormDatasetComponent } from '../form-dataset/form-dataset.component';
+import Experiment from 'src/app/_data/Experiment';
+import { ExperimentsService } from 'src/app/_services/experiments.service';
+import { PredictorsService } from 'src/app/_services/predictors.service';
+
+@Component({
+ selector: 'app-folder',
+ templateUrl: './folder.component.html',
+ styleUrls: ['./folder.component.css']
+})
+export class FolderComponent implements OnInit {
+
+ @ViewChild(FormDatasetComponent) formDataset?: FormDatasetComponent;
+
+ @Input() folderName: string = 'Moji podaci';
+
+ @Input() files!: FolderFile[]
+
+ newFile!: Dataset | Model;
+
+ @Input() type: FolderType = FolderType.Dataset;
+
+ @Input() forExperiment?: Experiment;
+
+ newFileSelected: boolean = true;
+
+ selectedFileIndex: number = -1;
+ selectedFile?: FolderFile;
+ hoveringOverFileIndex: number = -1;
+
+ fileToDisplay?: FolderFile;
+
+ @Output() selectedFileChanged: EventEmitter<FolderFile> = new EventEmitter();
+ @Output() okPressed: EventEmitter<string> = new EventEmitter();
+
+ searchTerm: string = '';
+
+ constructor(private datasetsService: DatasetsService, private experimentsService: ExperimentsService, private modelsService: ModelsService, private predictorsService: PredictorsService) {
+ //PLACEHOLDER
+ this.forExperiment = new Experiment();
+ this.forExperiment.inputColumns = ['kolona1', 'kol2', '???', 'test'];
+
+ this.folders[TabType.File] = [];
+ this.folders[TabType.NewFile] = [];
+
+ this.refreshFiles();
+
+
+ }
+
+ ngOnInit(): void {
+ if (this.files.length > 0)
+ this.selectFile(0);
+ else {
+ this.selectNewFile();
+ }
+ }
+
+ displayFile(){
+ if(this.type == FolderType.Dataset)
+ this.formDataset!.dataset = <Dataset>this.fileToDisplay;
+ }
+
+ hoverOverFile(i: number) {
+ this.hoveringOverFileIndex = i;
+ if (i != -1) {
+ this.fileToDisplay = this.files[i];
+ } else {
+ if (this.newFileSelected) {
+ this.fileToDisplay = this.newFile;
+ } else {
+ this.fileToDisplay = this.files[this.selectedFileIndex];
+ }
+ }
+ this.displayFile();
+ }
+
+ selectNewFile() {
+ if (!this.newFile) {
+ this.createNewFile();
+ }
+ this.fileToDisplay = this.newFile;
+ this.selectedFile = this.newFile;
+ this.newFileSelected = true;
+ this.listView = false;
+ this.selectedFileChanged.emit(this.newFile);
+ this.displayFile();
+ }
+
+ selectFile(index: number) {
+ this.selectedFile = this.filteredFiles[index];
+ this.fileToDisplay = this.filteredFiles[index];
+ this.newFileSelected = false;
+ this.listView = false;
+ this.selectedFileChanged.emit(this.selectedFile);
+ this.displayFile();
+ }
+
+ createNewFile() {
+ if (this.type == FolderType.Dataset) {
+ this.newFile = new Dataset();
+ } else if (this.type == FolderType.Model) {
+ this.newFile = new Model();
+ }
+ }
+
+ ok() {
+ this.okPressed.emit();
+ }
+
+ refreshFiles(){
+ this.datasetsService.getMyDatasets().subscribe((datasets) => {
+ this.folders[TabType.MyDatasets] = datasets;
+ });
+
+ this.datasetsService.getPublicDatasets().subscribe((datasets) => {
+ this.folders[TabType.PublicDatasets] = datasets;
+ });
+
+ this.modelsService.getMyModels().subscribe((models) => {
+ this.folders[TabType.MyModels] = models;
+ });
+
+ /*this.modelsService.getMyModels().subscribe((models) => {
+ this.folders[TabType.PublicModels] = models;
+ });*/
+ this.folders[TabType.PublicModels] = [];
+
+ this.experimentsService.getMyExperiments().subscribe((experiments) => {
+ this.folders[TabType.MyExperiments] = experiments;
+ });
+
+ this.files = [];
+
+ this.filteredFiles.length = 0;
+ this.filteredFiles.push(...this.files);
+
+ this.searchTermsChanged();
+
+ }
+
+ saveNewFile() {
+ if(this.type == FolderType.Dataset)
+ this.formDataset!.uploadDataset();
+ }
+
+ /*calcZIndex(i: number) {
+ let zIndex = (this.files.length - i - 1)
+ if (this.selectedFileIndex == i)
+ zIndex = this.files.length + 2;
+ if (this.hoveringOverFileIndex == i)
+ zIndex = this.files.length + 3;
+ return zIndex;
+ }
+
+ newFileZIndex() {
+ return (this.files.length + 1);
+ }*/
+
+ clearSearchTerm() {
+ this.searchTerm = '';
+ this.searchTermsChanged();
+ }
+
+ filteredFiles: FolderFile[] = [];
+
+ searchTermsChanged() {
+ this.filteredFiles.length = 0;
+ this.filteredFiles.push(...this.files.filter((file) => file.name.toLowerCase().includes(this.searchTerm.toLowerCase())));
+ if (this.selectedFile) {
+ if (!this.filteredFiles.includes(this.selectedFile)) {
+ this.selectFile(-1);
+ } else {
+ this.selectedFileIndex = this.filteredFiles.indexOf(this.selectedFile);
+ }
+ }
+ }
+
+ listView: boolean = false;
+
+ toggleListView() {
+ this.listView = !this.listView;
+ }
+
+ deleteFile() {
+ console.log('delete');
+ }
+
+ folders: { [tab: number]: FolderFile[] } = {};
+
+ tabTitles: { [tab: number]: string } = {
+ [TabType.File]: 'Fajl',
+ [TabType.NewFile]: 'Novi fajl',
+ [TabType.MyDatasets]: 'Moji izvori podataka',
+ [TabType.PublicDatasets]: 'Javni izvori podataka',
+ [TabType.MyModels]: 'Moje konfiguracije neuronske mreže',
+ [TabType.PublicModels]: 'Javne konfiguracije neuronske mreže',
+ [TabType.MyExperiments]: 'Eksperimenti',
+ };
+
+ FolderType = FolderType;
+
+ TabType = TabType;
+
+ @Input() tabsToShow: TabType[] = [
+ TabType.MyDatasets,
+ TabType.PublicDatasets,
+ TabType.MyModels,
+ TabType.PublicModels,
+ TabType.MyExperiments,
+ TabType.File
+ ]
+
+ @Input() selectedTab: TabType = TabType.NewFile;
+ hoverTab: TabType = TabType.None;
+
+ selectTab(tab: TabType) {
+ this.checkListView(tab);
+ this.selectedTab = tab;
+ this.files = this.folders[tab];
+
+ this.searchTermsChanged();
+ }
+
+ checkListView(tab: TabType) {
+ switch (tab) {
+ case TabType.File:
+ case TabType.NewFile:
+ case TabType.None:
+ this.listView = false;
+ break;
+ case TabType.MyExperiments:
+ case TabType.MyDatasets:
+ case TabType.MyModels:
+ case TabType.PublicDatasets:
+ case TabType.PublicModels:
+ this.listView = true;
+ break;
+ }
+ }
+
+ hoverOverTab(tab: TabType) {
+ this.checkListView(tab);
+ this.hoverTab = tab;
+ if (tab == TabType.None) {
+ this.checkListView(this.selectedTab);
+ this.files = this.folders[this.selectedTab];
+ } else {
+ this.files = this.folders[tab];
+ }
+ this.searchTermsChanged();
+ }
+}
+
+export enum Privacy {
+ Private,
+ Public
+}
+
+export enum TabType {
+ NewFile,
+ File,
+ MyDatasets,
+ PublicDatasets,
+ MyModels,
+ PublicModels,
+ MyExperiments,
+ None
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.css b/frontend/src/app/_elements/form-dataset/form-dataset.component.css
new file mode 100644
index 00000000..da31cfcb
--- /dev/null
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.css
@@ -0,0 +1,69 @@
+.folderBox {
+ width: 100%;
+ height: 100%;
+ position: relative;
+}
+
+.file-container {
+ border: 4px solid transparent;
+ position: relative;
+ margin-left: 3%;
+ margin-top: 3rem;
+ width: 94%;
+ min-height: 300px;
+ height: 75%;
+}
+
+.fileButton {
+ position: absolute;
+ margin-top: -3rem;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.fileButton label {
+ margin-left: 10px;
+}
+
+.dottedClass {
+ border: 4px dotted white;
+ border-radius: 25px;
+}
+
+.hidden {
+ visibility: hidden;
+}
+
+.file {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+}
+
+.file input {
+ border-radius: 4px;
+ margin-top: -15px;
+ width: 100%;
+ height: 100%;
+}
+
+.icon-display {
+ position: absolute;
+ top: 45%;
+ left: 50%;
+ transform: translate(-50%, -50%) scale(4);
+}
+
+.bottomBar {
+ width: 50%;
+ margin: 1rem;
+ align-items: flex-start;
+}
+
+#bottomButton {
+ background-color: var(--ns-bg-dark-100);
+ width: 10%;
+ height: 65%;
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.html b/frontend/src/app/_elements/form-dataset/form-dataset.component.html
new file mode 100644
index 00000000..2176b130
--- /dev/null
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.html
@@ -0,0 +1,74 @@
+<div class="folderBox">
+
+ <div class="file-container" [ngClass]="{'dottedClass': !tableData.hasInput}">
+
+ <i class="material-icons-outlined icon-display" [ngClass]="{'hidden': tableData.hasInput}">file_upload</i>
+
+ <div class="fileButton">
+ <button type="button" mat-raised-button (click)="fileInput.click()">Choose File</button>
+ <label>{{filename}}</label>
+ </div>
+
+ <input class="file" id="file-upload" (change)="changeListener($event)" #fileInput type="file" accept=".csv">
+
+
+ <div class="mt-5 datatable">
+ <app-datatable [tableData]="tableData"></app-datatable>
+ </div>
+
+
+ </div>
+
+
+
+
+
+ <div class="bottomBar">
+ <div class="row">
+ <div class="col-sm">
+ <div role="group">
+ <div class="row">
+ <mat-form-field class="example-full-width" appearance="fill">
+ <mat-label>Naziv</mat-label>
+ <input type="text" matInput value="{{dataset?.name}}">
+ <!--[formControl]="nameFormControl"-->
+
+ <mat-error *ngIf="nameFormControl.hasError('required')">
+ Naziv je <strong>obavezan</strong>
+ </mat-error>
+ </mat-form-field>
+ </div>
+ </div>
+ </div>
+ <div class="col-sm mb-3">
+
+ <!--<input id="fileInput" class="form-control btn-lg" type="file" class="upload" (change)="changeListener($event)" accept=".csv">
+ -->
+ </div>
+ <div class="col-sm">
+
+
+
+ <mat-form-field appearance="fill">
+ <mat-label>Delimiter</mat-label>
+ <mat-select id="delimiterOptions" [(ngModel)]="dataset.delimiter" (change)="update()" value=",">
+ <mat-option *ngFor="let option of delimiterOptions" [value]="option">
+ {{ option }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+ </div>
+ </div>
+
+ <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
+
+ </div>
+
+
+ <!--
+ <div class="d-flex flex-row align-items-center justify-content-center w-100 my-2">
+ <button (click)="uploadDataset()" class="btn btn-lg col-4" style="background-color:#003459; color:white;">Dodaj izvor podataka</button>
+ </div>
+-->
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.spec.ts b/frontend/src/app/_elements/form-dataset/form-dataset.component.spec.ts
index 5601b57b..51491c58 100644
--- a/frontend/src/app/_elements/dataset-load/dataset-load.component.spec.ts
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { DatasetLoadComponent } from './dataset-load.component';
+import { FormDatasetComponent } from './form-dataset.component';
-describe('DatasetLoadComponent', () => {
- let component: DatasetLoadComponent;
- let fixture: ComponentFixture<DatasetLoadComponent>;
+describe('FormDatasetComponent', () => {
+ let component: FormDatasetComponent;
+ let fixture: ComponentFixture<FormDatasetComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ DatasetLoadComponent ]
+ declarations: [ FormDatasetComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(DatasetLoadComponent);
+ fixture = TestBed.createComponent(FormDatasetComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.ts b/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
index 3e1b5c73..63376524 100644
--- a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.ts
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
@@ -1,34 +1,42 @@
-import { Component, EventEmitter, Output, ViewChild } from '@angular/core';
+import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import Dataset from 'src/app/_data/Dataset';
import { DatasetsService } from 'src/app/_services/datasets.service';
import { ModelsService } from 'src/app/_services/models.service';
import shared from 'src/app/Shared';
import { DatatableComponent, TableData } from '../datatable/datatable.component';
import { CsvParseService } from 'src/app/_services/csv-parse.service';
+import {FormControl, Validators} from '@angular/forms';
@Component({
- selector: 'app-add-new-dataset',
- templateUrl: './add-new-dataset.component.html',
- styleUrls: ['./add-new-dataset.component.css']
+ selector: 'app-form-dataset',
+ templateUrl: './form-dataset.component.html',
+ styleUrls: ['./form-dataset.component.css']
})
-export class AddNewDatasetComponent {
+export class FormDatasetComponent {
- @Output() newDatasetAdded = new EventEmitter<string>();
@ViewChild(DatatableComponent) datatable!: DatatableComponent;
- delimiterOptions: Array<string> = [",", ";", "\t", "razmak", "|"]; //podrazumevano ","
+ nameFormControl = new FormControl('', [Validators.required, Validators.email]);
+
+ delimiterOptions: Array<string> = [",", ";", "|", "razmak", "novi red"]; //podrazumevano ","
csvRecords: any[] = [];
files: File[] = [];
rowsNumber: number = 0;
colsNumber: number = 0;
- dataset: Dataset; //dodaj ! potencijalno
+ @Input() dataset: Dataset; //dodaj ! potencijalno
tableData: TableData = new TableData();
+ @ViewChild('fileInput') fileInput! : ElementRef
+
+ filename: String;
+
constructor(private modelsService: ModelsService, private datasetsService: DatasetsService, private csv: CsvParseService) {
this.dataset = new Dataset();
+ this.dataset.delimiter = ',';
+ this.filename = "";
}
//@ViewChild('fileImportInput', { static: false }) fileImportInput: any; cemu je ovo sluzilo?
@@ -36,14 +44,13 @@ export class AddNewDatasetComponent {
changeListener($event: any): void {
this.files = $event.srcElement.files;
if (this.files.length == 0 || this.files[0] == null) {
- //console.log("NEMA FAJLA");
- //this.loaded.emit("not loaded");
this.tableData.hasInput = false;
return;
}
else
this.tableData.hasInput = true;
+ this.filename = this.files[0].name;
this.tableData.loaded = false;
this.update();
}
@@ -56,7 +63,7 @@ export class AddNewDatasetComponent {
const fileReader = new FileReader();
fileReader.onload = (e) => {
if (typeof fileReader.result === 'string') {
- const result = this.csv.csvToArray(fileReader.result, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "") ? "," : this.dataset.delimiter)
+ const result = this.csv.csvToArray(fileReader.result, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "novi red") ? "\t" : this.dataset.delimiter)
if (this.dataset.hasHeader)
this.csvRecords = result.splice(0, 11);
@@ -74,6 +81,8 @@ export class AddNewDatasetComponent {
}
}
fileReader.readAsText(this.files[0]);
+
+ this.dataset.name = this.filename.slice(0, this.filename.length - 4);
}
checkAccessible() {
@@ -93,7 +102,6 @@ export class AddNewDatasetComponent {
this.dataset.uploaderId = shared.userId;
this.datasetsService.addDataset(this.dataset).subscribe((dataset) => {
- this.newDatasetAdded.emit("added");
shared.openDialog("Obaveštenje", "Uspešno ste dodali novi izvor podataka u kolekciju. Molimo sačekajte par trenutaka da se procesira.");
}, (error) => {
shared.openDialog("Neuspeo pokušaj!", "Izvor podataka sa unetim nazivom već postoji u Vašoj kolekciji. Izmenite naziv ili iskoristite postojeći dataset.");
@@ -103,4 +111,6 @@ export class AddNewDatasetComponent {
}); //kraj uploadData subscribe
}
+
+
}
diff --git a/frontend/src/app/_elements/form-model/form-model.component.css b/frontend/src/app/_elements/form-model/form-model.component.css
new file mode 100644
index 00000000..8c279523
--- /dev/null
+++ b/frontend/src/app/_elements/form-model/form-model.component.css
@@ -0,0 +1,87 @@
+#container {
+ color: var(--offwhite);
+}
+
+mat-label {
+ color: var(--offwhite) !important;
+}
+
+select {
+ color: var(--offwhite) !important;
+}
+
+mat-form-field {
+ color: var(--offwhite) !important;
+ padding: 0;
+ margin: 5px;
+ font-size: 12px;
+ width: 100%;
+}
+
+hr {
+ color: var(--offwhite) !important;
+ margin-bottom: 30px;
+}
+
+.neuron {
+ text-align: justify;
+ border: 1px solid white;
+ border-radius: 5px;
+ padding: 0;
+ color: var(--offwhite) !important;
+ background-color: var(--ns-bg-dark-100) !important;
+ min-width: none;
+ max-width: 12.5rem;
+}
+
+.row {
+ margin: 0;
+ padding: 0;
+}
+
+.mat-fix ::ng-deep .mat-form-field-wrapper {
+ margin-bottom: -1.85em;
+}
+
+#layers-control {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
+
+#layers {
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: row;
+ overflow-x: auto;
+ overflow-wrap: break-word;
+ overflow-y: hidden;
+ width: 100%;
+}
+
+.layer {
+ border: 1px solid var(--ns-primary);
+ border-radius: 4px;
+ margin: 5px;
+ padding: 0px;
+ width: 12rem;
+ height: 11.1rem;
+}
+
+.tm {
+ margin-left: 10px;
+}
+
+.layer>* {
+ margin-top: 0;
+}
+
+.layer>mat-form-field {
+ margin-left: 0;
+}
+
+.m-2 {
+ max-height: 20 rem;
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/form-model/form-model.component.html b/frontend/src/app/_elements/form-model/form-model.component.html
new file mode 100644
index 00000000..76601465
--- /dev/null
+++ b/frontend/src/app/_elements/form-model/form-model.component.html
@@ -0,0 +1,202 @@
+<div id="container">
+ <div class="ns-row">
+
+ <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">
+ </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)]="newModel.type">
+ <mat-option *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+
+ <div class="break-1"></div>
+
+ <div class="ns-col">
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Optimizacija</mat-label>
+ <mat-select [(ngModel)]="newModel.optimizer">
+ <mat-option *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+
+ </mat-form-field>
+ </div>
+ <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-option *ngFor="let option of Object.keys(LossFunction); let optionName of Object.values(LossFunction)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+
+ <div class="break-2"></div>
+
+ <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-option *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+ <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-option *ngFor="let option of Object.keys(LearningRate); let optionName of Object.values(LearningRate)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+
+ <div class="break-1"></div>
+
+ <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">
+ </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 required [(value)]="newModel.batchSize">
+ <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>
+ </div>
+
+ </div>
+</div>
+
+
+<!--kraj unosa parametara-->
+<hr>
+<div class="m-2">
+ <app-graph [model]="newModel" [inputColumns]="forExperiment?.inputColumns"></app-graph>
+</div>
+<div class="ns-row">
+
+ <div class="ns-col" id="layers-control">
+ <div>Broj Skrivenih Slojeva</div>
+ <button class="btn-clear btn-icon bubble" (click)="addLayer()">
+ <mat-icon>add</mat-icon>
+ </button>
+ <div>{{newModel.hiddenLayers}}</div>
+ <button class="btn-clear btn-icon bubble" (click)="removeLayer()">
+ <mat-icon>remove</mat-icon>
+ </button>
+
+ </div>
+ <div class="break-1"></div>
+ <div class="ns-col">
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Aktivaciona funkcija svih slojeva</mat-label>
+
+ <mat-select [(ngModel)]="selectedActivation" (selectionChange)="changeAllActivation()">
+ <mat-option *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+
+ <div class="ns-col">
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Broj neurona svih slojeva</mat-label>
+ <input matInput type="number" min="1" max="18" [(ngModel)]="selectedNumberOfNeurons" (change)="changeAllNumberOfNeurons()">
+ </mat-form-field>
+ </div>
+ <div class="break-2"></div>
+ <div class="ns-col">
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Regularizacija svih slojeva</mat-label>
+ <mat-select [(ngModel)]="selectedRegularisation" (selectionChange)="changeAllRegularisation()">
+ <mat-option *ngFor="let option of Object.keys(Regularisation); let optionName of Object.values(Regularisation)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+
+ <div class="ns-col">
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Stopa regularizacije svih slojeva</mat-label>
+ <mat-select [(ngModel)]="selectedRegularisationRate" (selectionChange)="changeAllRegularisationRate()">
+ <mat-option *ngFor="let option of Object.keys(RegularisationRate); let optionName of Object.values(RegularisationRate)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+
+
+</div>
+
+<!--kraj selectall**********************************************************************************-->
+<div id="layers">
+
+ <div class="layer" *ngFor="let item of newModel.layers; let i=index">
+
+
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Aktivacija</mat-label>
+ <button matPrefix class="btn-clear center-center text-offwhite">
+ <div>
+ #{{i+1}}
+ </div>
+ </button>
+ <mat-select [(ngModel)]="newModel.layers[i].activationFunction">
+ <mat-option *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+
+ <div class="d-flex flex-row align-items-center justify-content-center tm">
+ <div class="col-6" style="font-size: 13px;">Broj čvorova</div>
+ <button class="btn-clear btn-icon bubble" (click)="addNeuron(i)">
+ <mat-icon>add</mat-icon>
+ </button>
+ <div class="col-2 text-center">{{newModel.layers[i].neurons}}</div>
+ <button class="btn-clear btn-icon bubble" (click)="removeNeuron(i)">
+ <mat-icon>remove</mat-icon>
+ </button>
+ </div>
+
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Regularizacija</mat-label>
+ <mat-select [(ngModel)]="newModel.layers[i].regularisation">
+ <mat-option *ngFor="let option of Object.keys(Regularisation); let optionName of Object.values(Regularisation)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+
+ <mat-form-field appearance="fill" class="mat-fix">
+ <mat-label>Stopa regularizacije</mat-label>
+ <mat-select [(ngModel)]="newModel.layers[i].regularisationRate">
+ <mat-option *ngFor="let option of Object.keys(RegularisationRate); let optionName of Object.values(RegularisationRate)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-model/item-model.component.spec.ts b/frontend/src/app/_elements/form-model/form-model.component.spec.ts
index f696a160..af1091cc 100644
--- a/frontend/src/app/_elements/item-model/item-model.component.spec.ts
+++ b/frontend/src/app/_elements/form-model/form-model.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ItemModelComponent } from './item-model.component';
+import { FormModelComponent } from './form-model.component';
-describe('ItemModelComponent', () => {
- let component: ItemModelComponent;
- let fixture: ComponentFixture<ItemModelComponent>;
+describe('FormModelComponent', () => {
+ let component: FormModelComponent;
+ let fixture: ComponentFixture<FormModelComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ ItemModelComponent ]
+ declarations: [ FormModelComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(ItemModelComponent);
+ fixture = TestBed.createComponent(FormModelComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/form-model/form-model.component.ts b/frontend/src/app/_elements/form-model/form-model.component.ts
new file mode 100644
index 00000000..2c78cd56
--- /dev/null
+++ b/frontend/src/app/_elements/form-model/form-model.component.ts
@@ -0,0 +1,138 @@
+import { Component, OnInit, Input, ViewChild, Output, EventEmitter, AfterViewInit } from '@angular/core';
+import { FormControl, Validators } from '@angular/forms';
+import Shared from 'src/app/Shared';
+import Experiment from 'src/app/_data/Experiment';
+import Model, { Layer, ActivationFunction, LossFunction, LearningRate, LossFunctionBinaryClassification, LossFunctionMultiClassification, LossFunctionRegression, Metrics, MetricsBinaryClassification, MetricsMultiClassification, MetricsRegression, NullValueOptions, Optimizer, ProblemType, Regularisation, RegularisationRate, BatchSize } from 'src/app/_data/Model';
+import { GraphComponent } from '../graph/graph.component';
+
+
+@Component({
+ selector: 'app-form-model',
+ templateUrl: './form-model.component.html',
+ styleUrls: ['./form-model.component.css']
+})
+export class FormModelComponent implements AfterViewInit {
+ @ViewChild(GraphComponent) graph!: GraphComponent;
+ @Input() forExperiment?: Experiment;
+ @Output() selectedModelChangeEvent = new EventEmitter<Model>();
+
+ constructor() { }
+
+ ngAfterViewInit(): void {
+ }
+
+ selectFormControl = new FormControl('', Validators.required);
+ nameFormControl = new FormControl('', [Validators.required, Validators.email]);
+ selectTypeFormControl = new FormControl('', Validators.required);
+ selectOptFormControl = new FormControl('', Validators.required);
+ selectLFFormControl = new FormControl('', Validators.required);
+ selectLRFormControl = new FormControl('', Validators.required);
+ selectEpochFormControl = new FormControl('', Validators.required);
+ selectAFFormControl = new FormControl('', Validators.required);
+ selectBSFormControl = new FormControl('', Validators.required);
+ selectActivationFormControl = new FormControl('', Validators.required);
+ selectRegularisationFormControl = new FormControl('', Validators.required);
+ selectRRateFormControl = new FormControl('', Validators.required);
+
+ newModel: Model = new Model();
+ myModels?: Model[];
+
+ selectedModel?: Model;
+
+ ProblemType = ProblemType;
+ ActivationFunction = ActivationFunction;
+ RegularisationRate = RegularisationRate;
+ Regularisation = Regularisation;
+ metrics: any = Metrics;
+ LossFunction = LossFunction;
+ Optimizer = Optimizer;
+ BatchSize = BatchSize;
+ Object = Object;
+ document = document;
+ shared = Shared;
+ LearningRate = LearningRate;
+ Layer = Layer;
+
+ term: string = "";
+ selectedMetrics = [];
+ lossFunction: any = LossFunction;
+
+ showMyModels: boolean = true;
+
+ updateGraph() {
+ //console.log(this.newModel.layers);
+ this.graph.update();
+ }
+
+ removeLayer() {
+ if (this.newModel.hiddenLayers > 1) {
+ this.newModel.layers.splice(this.newModel.layers.length - 1, 1);
+ this.newModel.hiddenLayers -= 1;
+ this.updateGraph();
+ }
+ }
+ addLayer() {
+ if (this.newModel.hiddenLayers < 128) {
+ this.newModel.layers.push(new Layer(this.newModel.layers.length, this.selectedActivation, this.selectedNumberOfNeurons, this.selectedRegularisation, this.selectedRegularisationRate));
+
+ this.newModel.hiddenLayers += 1;
+ this.updateGraph();
+ }
+
+ }
+ /*
+ setNeurons()
+ {
+ for(let i=0;i<this.newModel.hiddenLayers;i++){
+ this.newModel.hiddenLayerNeurons[i]=1;
+ }
+ }*/
+ numSequence(n: number): Array<number> {
+ return Array(n);
+ }
+
+ removeNeuron(index: number) {
+ if (this.newModel.layers[index].neurons > 1) {
+ this.newModel.layers[index].neurons -= 1;
+ this.updateGraph();
+ }
+ }
+ addNeuron(index: number) {
+ if (this.newModel.layers[index].neurons < 18) {
+ this.newModel.layers[index].neurons += 1;
+ this.updateGraph();
+ }
+ }
+ selectedActivation: ActivationFunction = ActivationFunction.Sigmoid;
+ selectedRegularisationRate: RegularisationRate = RegularisationRate.RR1;
+ selectedRegularisation: Regularisation = Regularisation.L1;
+ selectedNumberOfNeurons: number = 3;
+
+ changeAllActivation() {
+ for (let i = 0; i < this.newModel.layers.length; i++) {
+ this.newModel.layers[i].activationFunction = this.selectedActivation;
+
+ }
+
+ }
+ changeAllRegularisation() {
+ for (let i = 0; i < this.newModel.layers.length; i++) {
+ this.newModel.layers[i].regularisation = this.selectedRegularisation;
+ }
+ }
+ changeAllRegularisationRate() {
+
+ for (let i = 0; i < this.newModel.layers.length; i++) {
+ this.newModel.layers[i].regularisationRate = this.selectedRegularisationRate;
+ }
+ }
+ changeAllNumberOfNeurons() {
+ for (let i = 0; i < this.newModel.layers.length; i++) {
+ this.newModel.layers[i].neurons = this.selectedNumberOfNeurons;
+ this.updateGraph();
+ }
+ }
+
+
+
+}
diff --git a/frontend/src/app/_elements/gradient-background/gradient-background.component.css b/frontend/src/app/_elements/gradient-background/gradient-background.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_elements/gradient-background/gradient-background.component.css
diff --git a/frontend/src/app/_elements/gradient-background/gradient-background.component.html b/frontend/src/app/_elements/gradient-background/gradient-background.component.html
new file mode 100644
index 00000000..3f30c35e
--- /dev/null
+++ b/frontend/src/app/_elements/gradient-background/gradient-background.component.html
@@ -0,0 +1 @@
+<div #holder style="position: fixed; z-index: -1;" [ngStyle]="{'background': color}"></div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.spec.ts b/frontend/src/app/_elements/gradient-background/gradient-background.component.spec.ts
index a9ea25b4..969c73b7 100644
--- a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.spec.ts
+++ b/frontend/src/app/_elements/gradient-background/gradient-background.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { AddNewDatasetComponent } from './add-new-dataset.component';
+import { GradientBackgroundComponent } from './gradient-background.component';
-describe('AddNewDatasetComponent', () => {
- let component: AddNewDatasetComponent;
- let fixture: ComponentFixture<AddNewDatasetComponent>;
+describe('GradientBackgroundComponent', () => {
+ let component: GradientBackgroundComponent;
+ let fixture: ComponentFixture<GradientBackgroundComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ AddNewDatasetComponent ]
+ declarations: [ GradientBackgroundComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(AddNewDatasetComponent);
+ fixture = TestBed.createComponent(GradientBackgroundComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/gradient-background/gradient-background.component.ts b/frontend/src/app/_elements/gradient-background/gradient-background.component.ts
new file mode 100644
index 00000000..1414bc60
--- /dev/null
+++ b/frontend/src/app/_elements/gradient-background/gradient-background.component.ts
@@ -0,0 +1,47 @@
+import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
+
+@Component({
+ selector: 'app-gradient-background',
+ templateUrl: './gradient-background.component.html',
+ styleUrls: ['./gradient-background.component.css']
+})
+export class GradientBackgroundComponent implements AfterViewInit {
+
+ @ViewChild('holder') holderRef!: ElementRef;
+ private holder!: HTMLDivElement;
+
+
+ @Input() colorHorizontal1 = 'rgba(0, 8, 45, 0.5)';
+ @Input() colorHorizontal2 = 'rgba(0, 52, 89, 0.5)';
+
+ @Input() colorVertical1 = 'rgba(0, 52, 89, 0.5)';
+ @Input() colorVertical2 = 'rgba(0, 152, 189, 0.5)';
+
+ constructor() { }
+
+ color: string = this.gradientHorizontal();
+
+ private width = 0;
+ private height = 0;
+
+ gradientHorizontal(): string {
+ return `linear-gradient(90deg, ${this.colorHorizontal1} 0%, ${this.colorHorizontal2} 50%, ${this.colorHorizontal1} 100%), linear-gradient(0deg, ${this.colorVertical1} 0%, ${this.colorVertical2} 100%)`;
+ }
+
+ resize() {
+ this.width = window.innerWidth;
+ this.height = window.innerHeight;
+
+ this.holder.style.width = this.width + 'px';
+ this.holder.style.height = this.height + 'px';
+ }
+
+ ngAfterViewInit(): void {
+ this.holder = <HTMLDivElement>this.holderRef.nativeElement;
+
+ window.addEventListener('resize', () => this.resize());
+ this.resize();
+
+ }
+
+}
diff --git a/frontend/src/app/_elements/graph/graph.component.css b/frontend/src/app/_elements/graph/graph.component.css
index e69de29b..361e7249 100644
--- a/frontend/src/app/_elements/graph/graph.component.css
+++ b/frontend/src/app/_elements/graph/graph.component.css
@@ -0,0 +1,17 @@
+.node-text {
+ position: absolute;
+ color: transparent;
+ width: 100px;
+ height: 40px;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ /*border: 1px solid red;*/
+ transform: translate(-50%, -50%);
+}
+
+.node-text:hover {
+ color: var(--offwhite);
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/graph/graph.component.html b/frontend/src/app/_elements/graph/graph.component.html
index 1c21fb6c..19e5c14a 100644
--- a/frontend/src/app/_elements/graph/graph.component.html
+++ b/frontend/src/app/_elements/graph/graph.component.html
@@ -1,3 +1,8 @@
-<div #graphWrapper class="w-100" style="height: 16rem;">
- <canvas #graphCanvas class="border"></canvas>
-</div> \ No newline at end of file
+<div #graphWrapper class="w-100 position-relative" style="height: 14rem;">
+ <ng-container *ngFor="let layer of layers; let i = index">
+ <div class="node-text" *ngFor="let node of layer; let j = index" [style.left.%]="node.x * 99.4" [style.top.%]="node.y * 100">
+ {{ i == 0 ? (inputColumns ? inputColumns[j] : 'nepoznato') : (i > 0 && i
+ < layers.length - 1 ? model!.layers[i-1].activationFunction : (i==layers.length - 1 ? 'out' : '')) }} </div>
+ </ng-container>
+ <canvas #graphCanvas></canvas>
+ </div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/graph/graph.component.ts b/frontend/src/app/_elements/graph/graph.component.ts
index 8051acc3..31814c2c 100644
--- a/frontend/src/app/_elements/graph/graph.component.ts
+++ b/frontend/src/app/_elements/graph/graph.component.ts
@@ -1,6 +1,7 @@
import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
-import Dataset from 'src/app/_data/Dataset';
-import Model from 'src/app/_data/Model';
+import { RgbColor } from '@syncfusion/ej2-angular-heatmap';
+import Dataset, { ColumnInfo } from 'src/app/_data/Dataset';
+import Model, { Layer } from 'src/app/_data/Model';
@Component({
selector: 'app-graph',
@@ -15,17 +16,19 @@ export class GraphComponent implements AfterViewInit {
canvas!: ElementRef;
@Input() model?: Model;
- @Input() inputCols: number = 1;
+ //@Input() inputCols: number = 1;
@Input() lineThickness: number = 2;
@Input() nodeRadius: number = 15;
- @Input() lineColor: string = '#00a8e8';
+ @Input() lineColor1: RgbColor = new RgbColor(0, 168, 232);
+ @Input() lineColor2: RgbColor = new RgbColor(0, 70, 151);
@Input() nodeColor: string = '#222277';
@Input() borderColor: string = '#00a8e8';
- @Input() inputNodeColor: string = '#ffdd11';
- @Input() outputNodeColor: string = '#44ee22';
+ @Input() inputNodeColor: string = '#00a8e8';
+ @Input() outputNodeColor: string = '#dfd7d7';
- private ctx?: CanvasRenderingContext2D;
+ private ctx!: CanvasRenderingContext2D;
+ @Input() inputColumns?: string[] = [];
constructor() { }
@@ -42,16 +45,16 @@ export class GraphComponent implements AfterViewInit {
this.resize();
}
- layers?: Node[][];
+ layers: Node[][] = [];
update() {
- this.layers = [];
+ this.layers.length = 0;
let inputNodeIndex = 0;
const inputLayer: Node[] = [];
- while (inputNodeIndex < this.inputCols) {
+ while (this.inputColumns && inputNodeIndex < this.inputColumns.length) {
const x = 0.5 / (this.model!.hiddenLayers + 2);
- const y = (inputNodeIndex + 0.5) / this.inputCols;
+ const y = (inputNodeIndex + 0.5) / this.inputColumns.length;
const node = new Node(x, y, this.inputNodeColor);
inputLayer.push(node);
inputNodeIndex += 1;
@@ -62,9 +65,9 @@ export class GraphComponent implements AfterViewInit {
while (layerIndex < this.model!.hiddenLayers + 1) {
const newLayer: Node[] = [];
let nodeIndex = 0;
- while (nodeIndex < this.model!.hiddenLayerNeurons) {
+ while (nodeIndex < this.model!.layers[layerIndex - 1].neurons) {
const x = (layerIndex + 0.5) / (this.model!.hiddenLayers + 2);
- const y = (nodeIndex + 0.5) / this.model!.hiddenLayerNeurons;
+ const y = (nodeIndex + 0.5) / this.model!.layers[layerIndex - 1].neurons;
const node = new Node(x, y, this.nodeColor);
newLayer.push(node);
nodeIndex += 1;
@@ -80,7 +83,7 @@ export class GraphComponent implements AfterViewInit {
}
draw() {
- this.ctx!.clearRect(0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height);
+ this.ctx.clearRect(0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height);
let index = 0;
while (index < this.layers!.length - 1) {
@@ -93,29 +96,38 @@ export class GraphComponent implements AfterViewInit {
}
for (let layer of this.layers!) {
- for (let node of layer) {
- this.drawNode(node);
- }
+ layer.forEach((node, index) => {
+ this.drawNode(node, 0.5 / layer.length + 0.5);
+ });
}
}
+ bezierOffset = 5;
+
drawLine(node1: Node, node2: Node) {
- this.ctx!.strokeStyle = this.lineColor;
- this.ctx!.lineWidth = this.lineThickness;
- this.ctx!.beginPath();
- this.ctx!.moveTo(node1.x * this.width, node1.y * this.height);
- this.ctx!.lineTo(node2.x * this.width, node2.y * this.height);
- this.ctx!.stroke();
+ const lineColor: RgbColor = this.lerpColor(this.lineColor1, this.lineColor2, node1.y);
+ this.ctx.strokeStyle = `rgb(${lineColor.R}, ${lineColor.G}, ${lineColor.B})`;
+ this.ctx.lineWidth = this.lineThickness;
+ this.ctx.beginPath();
+ this.ctx.moveTo(node1.x * this.width, node1.y * this.height);
+ //this.ctx.lineTo(node2.x * this.width, node2.y * this.height);
+ const middle = (node1.x + (node2.x - node1.x) / 2) * this.width;
+ this.ctx.bezierCurveTo(
+ middle, node1.y * this.height,
+ middle, node2.y * this.height,
+ node2.x * this.width, node2.y * this.height);
+ this.ctx.stroke();
}
- drawNode(node: Node) {
- this.ctx!.fillStyle = node.color;
- this.ctx!.strokeStyle = this.borderColor;
- this.ctx!.lineWidth = this.lineThickness;
- this.ctx!.beginPath();
- this.ctx!.arc(node.x * this.width, node.y * this.height, this.nodeRadius, 0, 2 * Math.PI);
- this.ctx!.fill();
- this.ctx!.stroke();
+ drawNode(node: Node, sizeMult: number) {
+ const lineColor: RgbColor = this.lerpColor(this.lineColor1, this.lineColor2, node.y);
+ this.ctx.strokeStyle = `rgb(${lineColor.R}, ${lineColor.G}, ${lineColor.B})`;
+ this.ctx.fillStyle = node.color;
+ this.ctx.lineWidth = this.lineThickness;
+ this.ctx.beginPath();
+ this.ctx.arc(node.x * this.width, node.y * this.height, this.nodeRadius * sizeMult, 0, 2 * Math.PI);
+ this.ctx.fill();
+ this.ctx.stroke();
}
width = 200;
@@ -134,6 +146,16 @@ export class GraphComponent implements AfterViewInit {
this.draw();
}
+
+ lerpColor(value1: RgbColor, value2: RgbColor, amount: number): RgbColor {
+ const newColor = new RgbColor(0, 0, 0);
+ amount = amount < 0 ? 0 : amount;
+ amount = amount > 1 ? 1 : amount;
+ newColor.R = value1.R + (value2.R - value1.R) * amount;
+ newColor.G = value1.G + (value2.G - value1.G) * amount;
+ newColor.B = value1.B + (value2.B - value1.B) * amount;
+ return newColor;
+ };
}
class Node {
diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.css b/frontend/src/app/_elements/item-dataset/item-dataset.component.css
deleted file mode 100644
index dc851671..00000000
--- a/frontend/src/app/_elements/item-dataset/item-dataset.component.css
+++ /dev/null
@@ -1,23 +0,0 @@
-.card{
- margin-top:0;
- padding: 0;
-}
-.p-2{
- margin: 0;
- padding: 0;
-}
-hr{
- margin: 0;
- padding: 0;
-}
-b{
- margin-left: 5px;
- margin-right: 10px;
-}
-th{
- margin: 10px;
- padding: 10px;
-}
-p{
- text-align: justify;
-} \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.html b/frontend/src/app/_elements/item-dataset/item-dataset.component.html
deleted file mode 100644
index 11ff61c3..00000000
--- a/frontend/src/app/_elements/item-dataset/item-dataset.component.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<div class="card" style="min-width: 12rem;">
-<div class="card-header d-flex mb-2 justify-content-" style="padding: 0;margin: 0;">
-
- <div class=" p-2 float-left "><b style="color: gray;">Naziv</b></div>
- <div class=" p-2 float-left"><b>{{dataset.name}}</b></div>
-</div>
-<div class="card-body overflow-hidden">
- <b style="color: gray;">Opis</b>
- <hr style="width: 20%;"> <p> {{dataset.description}}</p>
- <hr>
- <div class="d-flex justify-content-center">
- <div class=" p-2" >
- <h4><span class="badge bg-secondary">{{dataset.extension}}</span></h4>
- </div>
- <div class="p-2">
- <span class="material-icons">{{visibleicon}}</span>
- </div>
- <div class="p-2">
- <span class="material-icons">{{accessibleicon}}</span>
- </div>
- </div>
- <hr>
- <div class="col text-center">
-<button (click)=toggleDisplayDiv() class="btn btn-primary btn-sm active " mat-raised-button color="primary" style="margin: 0.5rem;">Kolone</button>
- <div [hidden]="isShowDiv" style="overflow: scroll; overflow-y: hidden;">
- <table class="table table-bordered table-md" >
- <thead>
- <th scope="col" *ngFor="let column of dataset.columnInfo" >{{column.columnName}}</th>
- </thead>
- </table>
- </div>
-</div>
- <table>
- <tr><td><span class="material-icons">calendar_today</span></td><td><span style="color: grey;"> <b> Kreirano</b></span></td><td>{{dataset.dateCreated |date}}</td></tr>
- <tr><td><span class="material-icons">edit_calendar</span></td><td><span style="color: grey;"> <b> Poslednja izmena</b></span></td><td>{{dataset.lastUpdated |date}}</td></tr>
- </table>
-
-</div>
-<div class="card-footer">
-
- </div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.ts b/frontend/src/app/_elements/item-dataset/item-dataset.component.ts
deleted file mode 100644
index 44b95310..00000000
--- a/frontend/src/app/_elements/item-dataset/item-dataset.component.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import Dataset from 'src/app/_data/Dataset';
-
-@Component({
- selector: 'app-item-dataset',
- templateUrl: './item-dataset.component.html',
- styleUrls: ['./item-dataset.component.css']
-})
-export class ItemDatasetComponent {
-
- @Input() dataset: Dataset = new Dataset();
- visibleicon='';
- accessibleicon='';
- isShowDiv = true;
- toggleDisplayDiv() {
- this.isShowDiv = !this.isShowDiv;
- }
- constructor() {
- }
- ngOnInit(): void {
- if(this.dataset.isPublic==true)
- {
- this.visibleicon='visibility'
- }
- else
- {
- this.visibleicon='visibility_off';
- }
-
- if(this.dataset.accessibleByLink==true)
- {
- this.accessibleicon='link'
- }
- else
- {
- this.accessibleicon='link_off';
- }
- }
-}
-
diff --git a/frontend/src/app/_elements/item-experiment/item-experiment.component.html b/frontend/src/app/_elements/item-experiment/item-experiment.component.html
deleted file mode 100644
index 51fbfef3..00000000
--- a/frontend/src/app/_elements/item-experiment/item-experiment.component.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<div class="card" style="min-width: 12rem;">
- <div class="card-header">
- Naziv eksperimenta: <b>{{experiment.name}}</b>
- </div>
- <div class="card-body overflow-hidden">
- <p class="card-text">
- Opis: {{experiment.description}}
- </p>
- </div>
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-experiment/item-experiment.component.ts b/frontend/src/app/_elements/item-experiment/item-experiment.component.ts
deleted file mode 100644
index 31900d35..00000000
--- a/frontend/src/app/_elements/item-experiment/item-experiment.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import Experiment from 'src/app/_data/Experiment';
-
-@Component({
- selector: 'app-item-experiment',
- templateUrl: './item-experiment.component.html',
- styleUrls: ['./item-experiment.component.css']
-})
-export class ItemExperimentComponent{
-
- @Input() experiment: Experiment = new Experiment();
-
- constructor() { }
-
-}
diff --git a/frontend/src/app/_elements/item-model/item-model.component.css b/frontend/src/app/_elements/item-model/item-model.component.css
deleted file mode 100644
index 5ea24c72..00000000
--- a/frontend/src/app/_elements/item-model/item-model.component.css
+++ /dev/null
@@ -1,23 +0,0 @@
-.card{
- margin: 0.5rem;
- padding: 0;
-}
-.p-2{
- margin: 0;
- padding: 0;
-}
-hr{
- margin: 0;
- padding: 0;
-}
-b{
- margin-left: 5px;
- margin-right: 10px;
-}
-th{
- margin: 10px;
- padding: 10px;
-}
-p{
- text-align: justify;
-} \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-model/item-model.component.html b/frontend/src/app/_elements/item-model/item-model.component.html
deleted file mode 100644
index 447f023e..00000000
--- a/frontend/src/app/_elements/item-model/item-model.component.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<div class="card" style="min-width: 12rem;">
- <div class="card-header d-flex mb-2 justify-content-" style="padding: 0;margin: 0;">
-
- <div class=" p-2 float-left "><b style="color: gray;">Naziv</b></div>
- <div class=" p-2 float-left"><b>{{model.name}}</b></div>
- </div>
- <div class="card-body overflow-hidden">
- <app-graph [model]="model"></app-graph>
- <br>
- <b style="color: gray;">Opis</b><hr style="width: 20%;">
- <p class="card-text">
- {{model.description}}
- </p>
- <hr>
-
- <div>
- <table>
- <tr><td><span class="material-icons">calendar_today</span></td><td><span style="color: grey;"> <b> Kreirano</b></span></td><td>{{model.dateCreated |date}}</td></tr>
- <tr><td><span class="material-icons">edit_calendar</span></td><td><span style="color: grey;"> <b> Poslednja izmena</b></span></td><td>{{model.lastUpdated |date}}</td></tr>
- </table>
- </div>
-
- </div>
- <button (click)=toggleDisplayDiv() class="btn btn-default btn-lg " mat-raised-button color="primary" style="margin: 0.5rem;">Parametri</button>
- <div [hidden]="isShowDiv">
- <!-- <table>
- <tr>
- <td><span style="color: grey;"> <b> Nasumično raspoređivanje podataka</b></span></td><td>{{randomOrd}}</td>
- </tr>
- <tr>
- <td><span style="color: grey;"> <b> Podela podataka na trening i test skup</b></span></td><td>{{randomOrd}}</td>
- </tr>
- <tr>
- <td><span style="color: grey;"> <b> Veličina skupa za treniranje</b></span></td><td>{{randomOrd}}</td>
- </tr>
- </table>-->
- <hr>
- <table>
- <tr>
- <td><span style="color: grey;"> <b> Tip problema</b></span></td><td>{{model.type}}</td>
- </tr>
- <tr>
- <td><span style="color: grey;"> <b> Optimizator</b></span></td><td>{{model.optimizer}}</td>
- </tr>
- <tr>
- <td> <span style="color: grey;"> <b> Funkcija gubitka</b></span></td><td>{{model.lossFunction}}</td>
- </tr>
- <tr>
- <td><span style="color: grey;"> <b> Batch size</b></span></td><td>{{model.batchSize}}</td>
- </tr>
- <tr>
- <td><span style="color: grey;"> <b> Broj epoha</b></span></td><td>{{model.epochs}}</td>
- </tr>
-
- </table>
-
- </div>
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-model/item-model.component.ts b/frontend/src/app/_elements/item-model/item-model.component.ts
deleted file mode 100644
index b837667b..00000000
--- a/frontend/src/app/_elements/item-model/item-model.component.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import Model from 'src/app/_data/Model';
-
-@Component({
- selector: 'app-item-model',
- templateUrl: './item-model.component.html',
- styleUrls: ['./item-model.component.css']
-})
-export class ItemModelComponent implements OnInit {
-
- @Input() model: Model = new Model();
- isShowDiv = true;
- randomOrd='';
-
- toggleDisplayDiv() {
- this.isShowDiv = !this.isShowDiv;
- }
-
- constructor() { }
-
- ngOnInit(): void {
- /*if(this.model.randomOrder)
- {
- this.randomOrd='Da';
- }
- else
- {
- this.randomOrd='Ne';
- }
-*/
- }
-
-}
diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.html b/frontend/src/app/_elements/item-predictor/item-predictor.component.html
deleted file mode 100644
index 3199dcc8..00000000
--- a/frontend/src/app/_elements/item-predictor/item-predictor.component.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<div class="card" style="min-width: 12rem;">
- <div class="card-header d-flex mb-2 justify-content-" style="padding: 0;margin: 0;">
-
- <div class=" p-2 float-left "><b style="color: gray;">Prediktor</b></div>
-
- </div>
- <div class="card-body overflow-hidden">
- <b style="color: gray;">Opis</b><hr style="width: 20%;">
- <p class="card-text">
- {{predictor.description}}
- </p>
-
- <b style="color: gray;">Ulazne kolone</b>
- <div style="overflow: scroll; overflow-y: hidden;">
-
- <table class="table table-bordered table-md" >
- <thead>
- <th scope="col" *ngFor="let column of predictor.inputs" >{{column}}</th>
- </thead>
- </table>
- </div>
- <b style="color: gray;">Izlazna kolona: </b><b>{{predictor.output}}</b>
- <hr>
- <div>
- <table>
- <tr><td><span class="material-icons">calendar_today</span></td><td><span style="color: grey;"> <b> Kreirano</b></span></td><td>{{predictor.dateCreated |date}}</td></tr>
- </table>
- </div>
- </div>
- <div class="card-footer text-center">
- <button class="btn btn-md col-4" style="background-color:#003459; color:white;"
- (click)="openPredictor();">Iskoristi</button>
-
- </div>
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.ts b/frontend/src/app/_elements/item-predictor/item-predictor.component.ts
deleted file mode 100644
index 246032e0..00000000
--- a/frontend/src/app/_elements/item-predictor/item-predictor.component.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import { Router } from '@angular/router';
-import Predictor from 'src/app/_data/Predictor';
-
-@Component({
- selector: 'app-item-predictor',
- templateUrl: './item-predictor.component.html',
- styleUrls: ['./item-predictor.component.css']
-})
-export class ItemPredictorComponent implements OnInit {
-
- @Input() predictor: Predictor = new Predictor();
-
- constructor(private router: Router) { }
-
- ngOnInit(): void {
- }
-
- openPredictor() {
- this.router.navigate(['predict/'+ this.predictor._id]);
- }
-
-}
diff --git a/frontend/src/app/_elements/metric-view/metric-view.component.css b/frontend/src/app/_elements/metric-view/metric-view.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_elements/metric-view/metric-view.component.css
diff --git a/frontend/src/app/_elements/metric-view/metric-view.component.html b/frontend/src/app/_elements/metric-view/metric-view.component.html
new file mode 100644
index 00000000..3a6cce8d
--- /dev/null
+++ b/frontend/src/app/_elements/metric-view/metric-view.component.html
@@ -0,0 +1,3 @@
+<div>
+
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/metric-view/metric-view.component.spec.ts b/frontend/src/app/_elements/metric-view/metric-view.component.spec.ts
new file mode 100644
index 00000000..c3ecc67f
--- /dev/null
+++ b/frontend/src/app/_elements/metric-view/metric-view.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MetricViewComponent } from './metric-view.component';
+
+describe('MetricViewComponent', () => {
+ let component: MetricViewComponent;
+ let fixture: ComponentFixture<MetricViewComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ MetricViewComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MetricViewComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/metric-view/metric-view.component.ts b/frontend/src/app/_elements/metric-view/metric-view.component.ts
new file mode 100644
index 00000000..3840692a
--- /dev/null
+++ b/frontend/src/app/_elements/metric-view/metric-view.component.ts
@@ -0,0 +1,49 @@
+import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { LineChartComponent } from '../_charts/line-chart/line-chart.component';
+
+@Component({
+ selector: 'app-metric-view',
+ templateUrl: './metric-view.component.html',
+ styleUrls: ['./metric-view.component.css']
+})
+export class MetricViewComponent implements OnInit {
+ @ViewChild(LineChartComponent) linechartComponent!: LineChartComponent;
+
+ constructor() { }
+
+ ngOnInit(): void {
+ }
+
+ history: any[] = [];
+
+ update(history: any[]) {
+ const myAcc: number[] = [];
+ const myMae: number[] = [];
+ const myMse: number[] = [];
+ const myLoss: number[] = [];
+
+ const myEpochs: number[] = [];
+ this.history = history;
+ this.history.forEach((metrics, epoch) => {
+ myEpochs.push(epoch + 1);
+ for (let key in metrics) {
+ let value = metrics[key];
+ console.log(key, ':::', value, epoch);
+ if (key === 'accuracy') {
+ myAcc.push(parseFloat(value));
+ }
+ else if (key === 'loss') {
+ myLoss.push(parseFloat(value));
+ }
+ else if (key === 'mae') {
+ myMae.push(parseFloat(value));
+ }
+ else if (key === 'mse') {
+ myMse.push(parseFloat(value));
+ }
+ }
+ });
+
+ this.linechartComponent.update(myEpochs, myAcc, myLoss, myMae, myMse);
+ }
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/model-load/model-load.component.css b/frontend/src/app/_elements/model-load/model-load.component.css
deleted file mode 100644
index c716f964..00000000
--- a/frontend/src/app/_elements/model-load/model-load.component.css
+++ /dev/null
@@ -1,17 +0,0 @@
-.btnType1 {
- background-color: #003459;
- color: white;
- padding-top: 2vh;
- padding-bottom: 2vh;
-}
-.btnType2 {
- background-color: white;
- color: #003459;
- border-color: #003459;
- padding-top: 2vh;
- padding-bottom: 2vh;
-}
-.selectedModelClass {
- /*border-color: 2px solid #003459;*/
- background-color: lightblue;
-} \ No newline at end of file
diff --git a/frontend/src/app/_elements/navbar/navbar.component.css b/frontend/src/app/_elements/navbar/navbar.component.css
index e69de29b..fcfad876 100644
--- a/frontend/src/app/_elements/navbar/navbar.component.css
+++ b/frontend/src/app/_elements/navbar/navbar.component.css
@@ -0,0 +1,8 @@
+.dropdown-item:hover {
+ background-color: var(--ns-primary);
+}
+
+h4 {
+ margin-top: 0.82rem;
+ margin-right: 10px;
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/navbar/navbar.component.html b/frontend/src/app/_elements/navbar/navbar.component.html
index 7d0c4cd8..105151aa 100644
--- a/frontend/src/app/_elements/navbar/navbar.component.html
+++ b/frontend/src/app/_elements/navbar/navbar.component.html
@@ -1,35 +1,23 @@
-<header class="sticky-top p-3 bg-dark text-white">
+<header class="text-offwhite" style="background-color: #002b49;">
<div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
<a routerLink="" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
- <img src="../../../assets/svg/logo_no_text.svg" class="bi me-2" width="64" height="40">
+ <img src="../../../assets/images/logo.png" class="bi me-2" width="64" height="64">
+ <h4>Igr<span class="highlight">ann</span>onica</h4>
</a>
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
- <li><a routerLink="" class="nav-link px-2"
- [class]="(currentUrl === '') ? 'text-secondary' : 'text-white'">Početna</a></li>
- <li><a routerLink="experiment" class="nav-link px-2"
- [class]="(currentUrl === '/experiment') ? 'text-secondary' : 'text-white'">Napravi eksperiment</a>
+ <li><a routerLink="experiment" class="nav-link px-2" [class]="(currentUrl === '/experiment') ? 'text-primary' : 'text-offwhite'">Napravi eksperiment</a>
</li>
- <li><a routerLink="training" class="nav-link px-2"
- [class]="(currentUrl === '/training') ? 'text-secondary' : 'text-white'">Treniraj model</a>
- </li>
- <li><a routerLink="my-predictors" class="nav-link px-2"
- [class]="(currentUrl === '/my-predictors') ? 'text-secondary' : 'text-white' + (shared.loggedIn) ? '' : 'disabled'">Predvidi</a>
+ <li><a routerLink="archive" class="nav-link px-2" [class]="(currentUrl === '/archive') ? 'text-primary' : 'text-offwhite'">Arhiva</a>
</li>
</ul>
<div *ngIf="shared.loggedIn" class="dropdown text-end">
- <a href="#" class="d-block link-light text-decoration-none dropdown-toggle" id="dropdownUser1"
- data-bs-toggle="dropdown" aria-expanded="false">
- <img [src]="'/assets/profilePictures/'+ shared.photoId +'.png'" alt="mdo" width="32" height="32"
- class="rounded-circle">
+ <a href="#" class="d-block link-light text-decoration-none dropdown-toggle" id="dropdownUser1" data-bs-toggle="dropdown" aria-expanded="false">
+ <img [src]="'/assets/profilePictures/'+ shared.photoId +'.png'" alt="mdo" width="32" height="32" class="rounded-circle">
</a>
- <ul class="dropdown-menu text-small" aria-labelledby="dropdownUser1"
- style="position: absolute; inset: 0px 0px auto auto; margin: 0px; transform: translate(0px, 34px);"
- data-popper-placement="bottom-end">
- <li><a class="dropdown-item" routerLink="add-model">Nov model...</a></li>
- <li><a class="dropdown-item" routerLink="settings">Podešavanja</a></li>
+ <ul class="dropdown-menu text-small ns-bg-dark-100" aria-labelledby="dropdownUser1" style="position: absolute; inset: 0px 0px auto auto; margin: 0px; transform: translate(0px, 34px);" data-popper-placement="bottom-end">
<li><a class="dropdown-item" routerLink="profile">Moj profil</a></li>
<li>
<hr class="dropdown-divider">
@@ -38,12 +26,10 @@
</ul>
</div>
<div *ngIf="!shared.loggedIn" class="dropdown text-end">
- <button type="button" mat-raised-button color="primary" class="mx-2" data-bs-toggle="modal"
- data-bs-target="#modalForLogin">
+ <button type="button" mat-raised-button color="accent" class="mx-2" data-bs-toggle="modal" data-bs-target="#modalForLogin">
Prijavi se
</button>
- <button type="button" mat-raised-button color="primary" data-bs-toggle="modal"
- data-bs-target="#modalForRegister">
+ <button type="button" mat-raised-button color="accent" data-bs-toggle="modal" data-bs-target="#modalForRegister">
Registruj se
</button>
</div>
diff --git a/frontend/src/app/_elements/navbar/navbar.component.ts b/frontend/src/app/_elements/navbar/navbar.component.ts
index 368508ed..e2551f7a 100644
--- a/frontend/src/app/_elements/navbar/navbar.component.ts
+++ b/frontend/src/app/_elements/navbar/navbar.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Location } from '@angular/common';
import { AuthService } from '../../_services/auth.service';
import shared from 'src/app/Shared';
@@ -8,7 +8,8 @@ import { MatDialog } from '@angular/material/dialog';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
- styleUrls: ['./navbar.component.css']
+ styleUrls: ['./navbar.component.css'],
+ encapsulation: ViewEncapsulation.Emulated
})
export class NavbarComponent implements OnInit {
diff --git a/frontend/src/app/_elements/notifications/notifications.component.ts b/frontend/src/app/_elements/notifications/notifications.component.ts
index 9b460240..d64530b9 100644
--- a/frontend/src/app/_elements/notifications/notifications.component.ts
+++ b/frontend/src/app/_elements/notifications/notifications.component.ts
@@ -25,6 +25,7 @@ export class NotificationsComponent implements OnInit {
const existingNotification = this.notifications.find(x => x.id === mId)
const progress = ((currentEpoch + 1) / totalEpochs);
console.log("Ukupno epoha", totalEpochs, "Trenutna epoha:", currentEpoch);
+ console.log("stat:", stat);
if (!existingNotification)
this.notifications.push(new Notification(`Treniranje modela: ${mName}`, mId, progress, true));
else {
diff --git a/frontend/src/app/_elements/playlist/playlist.component.css b/frontend/src/app/_elements/playlist/playlist.component.css
new file mode 100644
index 00000000..353a094c
--- /dev/null
+++ b/frontend/src/app/_elements/playlist/playlist.component.css
@@ -0,0 +1,61 @@
+.ns-wrapper {
+ width: 100%;
+ max-width: 800px;
+ max-height: 600px;
+ height: 100%;
+ transform-style: preserve-3d;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+}
+
+.ns-cards {
+ position: relative;
+ width: 300%;
+ height: 25rem;
+ margin-bottom: 20px;
+}
+
+.ns-card {
+ position: absolute;
+ width: 60%;
+ height: 100%;
+ left: 0;
+ right: 0;
+ margin: auto;
+ transition: transform 0.4s ease;
+ cursor: pointer;
+}
+
+.ns-card:hover {
+ opacity: 1 !important;
+}
+
+input[type=radio] {
+ display: none;
+}
+
+#item-1:checked~.ns-cards #view-item-3,
+#item-2:checked~.ns-cards #view-item-1,
+#item-3:checked~.ns-cards #view-item-2 {
+ transform: translatex(-40%) scale(0.8);
+ opacity: 0.5;
+ z-index: 0;
+}
+
+#item-1:checked~.ns-cards #view-item-2,
+#item-2:checked~.ns-cards #view-item-3,
+#item-3:checked~.ns-cards #view-item-1 {
+ transform: translatex(40%) scale(0.8);
+ opacity: 0.5;
+ z-index: 0;
+}
+
+#item-1:checked~.ns-cards #view-item-1,
+#item-2:checked~.ns-cards #view-item-2,
+#item-3:checked~.ns-cards #view-item-3 {
+ transform: translatex(0) scale(1);
+ opacity: 1;
+ z-index: 1;
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/playlist/playlist.component.html b/frontend/src/app/_elements/playlist/playlist.component.html
new file mode 100644
index 00000000..b82de163
--- /dev/null
+++ b/frontend/src/app/_elements/playlist/playlist.component.html
@@ -0,0 +1,19 @@
+<div class="ns-wrapper" *ngIf="tableDatas && tableDatas.length==3">
+ <input type="radio" name="slider" id="item-1" value="0" [(ngModel)]="selectedId">
+ <input type="radio" name="slider" id="item-2" value="1" [(ngModel)]="selectedId">
+ <input type="radio" name="slider" id="item-3" value="2" [(ngModel)]="selectedId">
+ <div class="ns-cards">
+ <label class="ns-card ns-bg-dark-100 ns-border-primary rounded" for="item-1" id="view-item-1">
+ <app-datatable [tableData]="tableDatas[0]"></app-datatable>
+ </label>
+ <label class="ns-card ns-bg-dark-100 ns-border-primary rounded" for="item-2" id="view-item-2">
+ <app-datatable [tableData]="tableDatas[1]"></app-datatable>
+ </label>
+ <label class="ns-card ns-bg-dark-100 ns-border-primary rounded" for="item-3" id="view-item-3">
+ <app-datatable [tableData]="tableDatas[2]"></app-datatable>
+ </label>
+ </div>
+ <div class="ns-infobox text-offwhite">
+ <h2>{{datasets[getIndex(selectedId)].name}}</h2>
+ </div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/playlist/playlist.component.spec.ts b/frontend/src/app/_elements/playlist/playlist.component.spec.ts
new file mode 100644
index 00000000..0afe8041
--- /dev/null
+++ b/frontend/src/app/_elements/playlist/playlist.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PlaylistComponent } from './playlist.component';
+
+describe('PlaylistComponent', () => {
+ let component: PlaylistComponent;
+ let fixture: ComponentFixture<PlaylistComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ PlaylistComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PlaylistComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/playlist/playlist.component.ts b/frontend/src/app/_elements/playlist/playlist.component.ts
new file mode 100644
index 00000000..7529b36b
--- /dev/null
+++ b/frontend/src/app/_elements/playlist/playlist.component.ts
@@ -0,0 +1,49 @@
+import { Component, Input, OnInit } from '@angular/core';
+import Dataset from 'src/app/_data/Dataset';
+import { TableData } from 'src/app/_elements/datatable/datatable.component';
+import { CsvParseService } from 'src/app/_services/csv-parse.service';
+import { DatasetsService } from 'src/app/_services/datasets.service';
+
+@Component({
+ selector: 'app-playlist',
+ templateUrl: './playlist.component.html',
+ styleUrls: ['./playlist.component.css']
+})
+export class PlaylistComponent implements OnInit {
+
+ selectedId: string = "0";
+
+ @Input() datasets!: Dataset[];
+
+ tableDatas?: TableData[];
+
+ constructor(private datasetService: DatasetsService, private csv: CsvParseService) {
+
+ }
+
+ getIndex(str: string) {
+ return parseInt(str);
+ }
+
+ ngOnInit(): void {
+ this.tableDatas = [];
+
+ this.datasets.forEach((dataset, index) => {
+ if (index < 3) {
+ this.datasetService.getDatasetFile(dataset.fileId).subscribe((file: string | undefined) => {
+ if (file) {
+ const tableData = new TableData();
+ tableData.hasInput = true;
+ tableData.loaded = true;
+ tableData.numRows = dataset.rowCount;
+ tableData.numCols = dataset.columnInfo.length;
+ tableData.data = this.csv.csvToArray(file, (dataset.delimiter == "razmak") ? " " : (dataset.delimiter.toString() == "") ? "," : dataset.delimiter);
+ this.tableDatas!.push(tableData);
+ }
+ });
+ }
+ });
+
+ console.log(this.tableDatas);
+ }
+}
diff --git a/frontend/src/app/_elements/reactive-background/reactive-background.component.html b/frontend/src/app/_elements/reactive-background/reactive-background.component.html
index 756952fb..c63dd6ac 100644
--- a/frontend/src/app/_elements/reactive-background/reactive-background.component.html
+++ b/frontend/src/app/_elements/reactive-background/reactive-background.component.html
@@ -1 +1 @@
-<canvas id="bgCanvas" width="200" height="200" style="position: fixed; z-index: -1;"></canvas> \ No newline at end of file
+<canvas #bgCanvas width="200" height="200" style="position: fixed; z-index: -1;"></canvas> \ No newline at end of file
diff --git a/frontend/src/app/_elements/reactive-background/reactive-background.component.ts b/frontend/src/app/_elements/reactive-background/reactive-background.component.ts
index 980e3e6f..1a6157e3 100644
--- a/frontend/src/app/_elements/reactive-background/reactive-background.component.ts
+++ b/frontend/src/app/_elements/reactive-background/reactive-background.component.ts
@@ -1,14 +1,19 @@
-import { Component, Input, OnInit } from '@angular/core';
+import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
+import { CookieService } from 'ngx-cookie-service';
+import Shared from 'src/app/Shared';
@Component({
selector: 'app-reactive-background',
templateUrl: './reactive-background.component.html',
styleUrls: ['./reactive-background.component.css']
})
-export class ReactiveBackgroundComponent implements OnInit {
+export class ReactiveBackgroundComponent implements AfterViewInit {
+
+ @ViewChild('bgCanvas') canvasRef!: ElementRef;
@Input() numPoints: number = 450;
@Input() speed: number = 0.001; // 0-1
+ @Input() scrollSpeed: number = 1;
@Input() maxSize: number = 6;
@Input() minDistance: number = 0.07; //0-1
@@ -19,30 +24,43 @@ export class ReactiveBackgroundComponent implements OnInit {
@Input() pointColor: string = '#ffffff';
@Input() cursorLineColor: string = '#ff0000';
+ @Input() animate: boolean = true;
+ @Input() fill: number = 1.0;
+
+ private fleeSpeed = 0.005;
+
private points: Point[] = [];
private width = 200;
private height = 200;
private ratio = 1;
- private canvas?: HTMLCanvasElement;
- private ctx?: CanvasRenderingContext2D;
+ private canvas!: HTMLCanvasElement;
+ private ctx!: CanvasRenderingContext2D;
private time: number = 0;
- constructor() { }
+ constructor(private cookie: CookieService) { }
private mouseX = 0;
private mouseY = 0;
- ngOnInit(): void {
-
+ ngAfterViewInit(): void {
document.addEventListener('mousemove', (e) => {
this.mouseX = e.clientX / this.width;
this.mouseY = e.clientY / this.height;
})
- this.canvas = (<HTMLCanvasElement>document.getElementById('bgCanvas'));
+ document.addEventListener('mouseleave', _ => {
+ this.mouseX = -1;
+ this.mouseY = -1;
+ })
+
+ document.addEventListener('scroll', (e) => {
+ this.scrollBackground(e);
+ })
+
+ this.canvas = (<HTMLCanvasElement>this.canvasRef.nativeElement);
const ctx = this.canvas.getContext('2d');
if (ctx) {
this.ctx = ctx;
@@ -64,41 +82,77 @@ export class ReactiveBackgroundComponent implements OnInit {
this.resize();
setInterval(() => {
+ if (this.cookie.check('animateBackground')) {
+ this.animate = this.cookie.get('animateBackground') == 'true';
+ }
+ if (this.cookie.check('backgroundFill')) {
+ this.fill = parseFloat(this.cookie.get('backgroundFill'));
+ }
+
this.drawBackground();
}, 1000 / 60);
+
+ Shared.bgScroll.subscribe((amount) => {
+ this.scrollBackgroundFromSharedEvent(amount);
+ })
+ }
+
+ private lastScrollY: number = 0;
+
+ scrollBackgroundFromSharedEvent(amount: number) {
+ const scrolledAmount = amount - this.lastScrollY;
+ this.scrollPoints(scrolledAmount);
+ this.lastScrollY = amount;
+ }
+
+ scrollBackground(e: Event) {
+ const scrolledAmount = window.scrollY - this.lastScrollY;
+ this.scrollPoints(scrolledAmount);
+ this.lastScrollY = window.scrollY;
+ }
+
+ scrollPoints(amount: number) {
+ this.points.forEach((point, index) => {
+ if (index > this.numPoints * this.fill) return;
+ point.y = point.y - (amount / this.height) * this.scrollSpeed;
+ this.keepPointWithinBounds(point);
+ })
}
drawBackground() {
if (!this.ctx || !this.canvas) return;
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
- this.ctx.fillStyle = this.bgColor;
- this.ctx.fillRect(0, 0, this.width, this.height);
+ //this.ctx.fillStyle = this.bgColor;
+ //this.ctx.fillRect(0, 0, this.width, this.height);
this.points.forEach((point, index) => {
+ if (index > this.numPoints * this.fill) return;
+
this.drawLines(point, index);
this.drawPoint(point);
- this.updatePoint(point);
+
+ if (this.animate)
+ this.updatePoint(point);
});
//this.drawPoint(new Point(this.mouseX, this.mouseY, 12, 0));
-
- this.time += 1;
}
drawLines(p: Point, index: number) {
let i = index + 1;
- while (i < this.points.length) {
+ while (i < this.points.length * this.fill) {
const otherPoint = this.points[i];
const dist = this.distance(p.x, p.y, otherPoint.x, otherPoint.y);
if (dist < this.minDistance) {
const h = HEX[Math.round((1 - dist / this.minDistance) * 16)]
- this.ctx!.strokeStyle = this.lineColor + h + h;
- this.ctx!.beginPath();
- this.ctx!.moveTo(p.x * this.width, p.y * this.height);
- this.ctx!.lineTo(otherPoint.x * this.width, otherPoint.y * this.height);
- this.ctx!.stroke();
+ this.ctx.strokeStyle = this.lineColor + h;
+ this.ctx.lineWidth = this.maxSize / 2;
+ this.ctx.beginPath();
+ this.ctx.moveTo(p.x * this.width, p.y * this.height);
+ this.ctx.lineTo(otherPoint.x * this.width, otherPoint.y * this.height);
+ this.ctx.stroke();
}
i++;
@@ -106,10 +160,10 @@ export class ReactiveBackgroundComponent implements OnInit {
}
drawPoint(p: Point) {
- this.ctx!.fillStyle = this.pointColor;
- this.ctx!.beginPath();
- this.ctx!.arc(p.x * this.width, p.y * this.height, p.size, 0, 2 * Math.PI);
- this.ctx!.fill();
+ this.ctx.fillStyle = this.pointColor;
+ this.ctx.beginPath();
+ this.ctx.arc(p.x * this.width, p.y * this.height, p.size * this.screenDepth(p.x), 0, 2 * Math.PI);
+ this.ctx.fill();
}
resize() {
@@ -122,40 +176,66 @@ export class ReactiveBackgroundComponent implements OnInit {
this.canvas.height = this.height;
}
+ if (this.cookie.check('animateBackground')) {
+ this.animate = this.cookie.get('animateBackground') == 'true';
+ }
+ if (this.cookie.check('backgroundFill')) {
+ this.fill = parseFloat(this.cookie.get('backgroundFill'));
+ }
+
this.drawBackground();
}
updatePoint(p: Point) {
+ const mx = this.mouseX;
+ const my = this.mouseY;
+ const distToCursor = this.distance(p.x, p.y, mx, my);
+
+ if (distToCursor < this.cursorDistance) {
+
+ const t = (distToCursor / this.cursorDistance);
+ p.x -= ((mx - p.x) / distToCursor) * this.speed * (1 + t * 2);
+ p.y -= ((my - p.y) / distToCursor) * this.speed * (1 + t * 2);
+
+ p.direction = this.lerp(p.direction, Math.atan2(my - p.y, mx - p.x) * 180 / Math.PI, t);
+
+ const grd = this.ctx.createLinearGradient(p.x * this.width, p.y * this.height, mx * this.width, my * this.height);
+ const alpha = HEX[Math.round(p.size / this.maxSize * (HEX.length - 1))];
+ grd.addColorStop(0, this.cursorLineColor + alpha);
+ grd.addColorStop(0.5, this.cursorLineColor + '00');
+ this.ctx.strokeStyle = grd;
+ this.ctx.beginPath();
+ this.ctx.moveTo(p.x * this.width, p.y * this.height);
+ this.ctx.lineTo(mx * this.width, my * this.height);
+ this.ctx.stroke();
+ }
+
const vx = Math.sin(p.direction);
const vy = Math.cos(p.direction);
p.x = p.x + vx * this.speed;
p.y = p.y + vy * this.speed;
- const mx = this.mouseX;
- const my = this.mouseY;
- const distToCursor = this.distance(p.x, p.y, mx, my);
- if (distToCursor < this.cursorDistance) {
+ this.keepPointWithinBounds(p);
+ }
- p.x -= ((mx - p.x) / distToCursor) / 500;
- p.y -= ((my - p.y) / distToCursor) / 500;
-
- const grd = this.ctx!.createLinearGradient(p.x * this.width, p.y * this.height, mx * this.width, my * this.height);
- grd.addColorStop(0, this.cursorLineColor + 'ff');
- grd.addColorStop(1, this.cursorLineColor + '00');
- this.ctx!.strokeStyle = grd;
- this.ctx!.beginPath();
- this.ctx!.moveTo(p.x * this.width, p.y * this.height);
- this.ctx!.lineTo(mx * this.width, my * this.height);
- this.ctx!.stroke();
- }
+ lerp(start: number, end: number, amt: number) {
+ return (1 - amt) * start + amt * end
+ }
- p.x %= 1;
- p.y %= 1;
+ keepPointWithinBounds(p: Point) {
+ p.x = p.x % 1.0;
+ p.y = p.y % 1.0;
+ p.x = ((1 - Math.sign(p.x)) / 2) + p.x;
+ p.y = ((1 - Math.sign(p.y)) / 2) + p.y;
}
distance(x1: number, y1: number, x2: number, y2: number): number {
- return Math.sqrt(((x2 - x1) ** 2) + ((y2 / this.ratio - y1 / this.ratio) ** 2));
+ return Math.sqrt(((x2 - x1) ** 2) + ((y2 / this.ratio - y1 / this.ratio) ** 2) / this.screenDepth(x1)) * this.ratio;
+ }
+
+ screenDepth(x: number): number {
+ return (1.5 - Math.sin(x * Math.PI));
}
}
@@ -168,4 +248,4 @@ class Point {
) { }
}
-const HEX = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; \ No newline at end of file
+const HEX = ['00', '11', '22', '33', '44', '55', '66', '77', '88', '99', 'aa', 'bb', 'cc', 'dd', 'ee', 'ff']; \ No newline at end of file
diff --git a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.css b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.css
index e69de29b..bdfd06c9 100644
--- a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.css
+++ b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.css
@@ -0,0 +1,3 @@
+mat-dialog-container{
+ background: var(ns-bg-dark-50) !important;
+} \ No newline at end of file
diff --git a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.html b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.html
index 82365193..2d7e4d86 100644
--- a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.html
+++ b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.html
@@ -1,7 +1,9 @@
-<h2 mat-dialog-title class="text-muted">{{data.title}}</h2>
-<div mat-dialog-content class="mt-4" style="color: rgb(81, 76, 76);">
- {{data.message}}
-</div>
-<div mat-dialog-actions class="d-flex justify-content-center mt-4">
- <button mat-button cdkFocusInitial (click)="onOkClick()" style="background-color: lightgray;">OK</button>
-</div> \ No newline at end of file
+
+
+ <h2 mat-dialog-title >{{data.title}}</h2>
+ <div mat-dialog-content class="mt-4 text-offwhite" >
+ {{data.message}}
+ </div>
+ <div mat-dialog-actions class="d-flex justify-content-center mt-4">
+ <button mat-raised-button cdkFocusInitial (click)="onOkClick()" color="basic">OK</button>
+ </div> \ No newline at end of file
diff --git a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css
diff --git a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html
new file mode 100644
index 00000000..7ba286cb
--- /dev/null
+++ b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html
@@ -0,0 +1,16 @@
+<h1 mat-dialog-title>Enkodiranje svih kolona</h1>
+<div mat-dialog-content>
+ <p>Odaberite tip enkodinga za sve kolone zajedno:</p>
+ <mat-form-field>
+ <mat-select matNativeControl [(value)]="selectedEncodingType">
+ <mat-option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ <p>Da li ste sigurni u izbor?</p>
+</div>
+<div mat-dialog-actions>
+ <button mat-button [mat-dialog-close]="selectedEncodingType" cdkFocusInitial>Da</button>
+ <button mat-button (click)="onNoClick()">Odustani</button>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.spec.ts b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.spec.ts
index fda74dbe..77f30ae3 100644
--- a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.spec.ts
+++ b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { BrowseDatasetsComponent } from './browse-datasets.component';
+import { EncodingDialogComponent } from './encoding-dialog.component';
-describe('BrowseDatasetsComponent', () => {
- let component: BrowseDatasetsComponent;
- let fixture: ComponentFixture<BrowseDatasetsComponent>;
+describe('EncodingDialogComponent', () => {
+ let component: EncodingDialogComponent;
+ let fixture: ComponentFixture<EncodingDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ BrowseDatasetsComponent ]
+ declarations: [ EncodingDialogComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(BrowseDatasetsComponent);
+ fixture = TestBed.createComponent(EncodingDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts
new file mode 100644
index 00000000..3b7560bf
--- /dev/null
+++ b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts
@@ -0,0 +1,28 @@
+import { Component, OnInit } from '@angular/core';
+import { MatDialogRef } from '@angular/material/dialog';
+import { Encoding } from 'src/app/_data/Experiment';
+
+
+@Component({
+ selector: 'app-encoding-dialog',
+ templateUrl: './encoding-dialog.component.html',
+ styleUrls: ['./encoding-dialog.component.css']
+})
+export class EncodingDialogComponent implements OnInit {
+
+ selectedEncodingType?: Encoding;
+ Encoding = Encoding;
+ Object = Object;
+
+ constructor(public dialogRef: MatDialogRef<EncodingDialogComponent>)
+ {
+ this.selectedEncodingType = Encoding.Label;
+ }
+
+ ngOnInit(): void {
+ }
+
+ onNoClick() {
+ this.dialogRef.close();
+ }
+}
diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.css b/frontend/src/app/_modals/login-modal/login-modal.component.css
index e69de29b..f8ffe797 100644
--- a/frontend/src/app/_modals/login-modal/login-modal.component.css
+++ b/frontend/src/app/_modals/login-modal/login-modal.component.css
@@ -0,0 +1,37 @@
+.modal-content {
+ text-align: center;
+ width: 80%;
+ margin: auto;
+}
+
+.modal-footer {
+ text-align: center;
+}
+
+#loginButton {
+ color: white;
+ background-color: #003459;
+ margin-right: 10px;
+}
+
+#loginButton,
+#doNotLoginButton {
+ padding: 2% 6%;
+}
+
+.close-button {
+ margin: 2%;
+}
+
+#link {
+ text-decoration: underline;
+}
+
+#link:hover {
+ color: var(--offwhite);
+ font-size: 110%;
+}
+
+#wrong-creds {
+ color: var(--ns-warn);
+} \ No newline at end of file
diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.html b/frontend/src/app/_modals/login-modal/login-modal.component.html
index 03048155..cea6bf39 100644
--- a/frontend/src/app/_modals/login-modal/login-modal.component.html
+++ b/frontend/src/app/_modals/login-modal/login-modal.component.html
@@ -1,42 +1,49 @@
<!-- Modal -->
<div class="modal fade" id="modalForLogin" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
- <div class="modal-dialog modal-dialog-centered">
- <div class="modal-content">
- <div class="modal-header" style="background-color: #003459;">
- <button #closeButton type="button" class="btn-close" style="background-color:white;" data-bs-dismiss="modal" aria-label="Close" (click)="resetData()"></button>
- </div>
- <div class="modal-body px-5" style="color:#003459">
- <h1 class="text-center mt-2 mb-4">Prijavite se</h1>
- <form>
- <!-- Korisnicko ime -->
- <div class="form-outline mb-3">
- <label class="form-label" for="username">Korisničko ime</label>
- <input [(ngModel)]="username" name="username" type="text" id="username"
- class="form-control form-control" placeholder="Unesite korisničko ime..." />
- </div>
- <!-- Lozinka -->
- <div class="form-outline mb-3">
- <label class="form-label" for="password">Lozinka</label>
- <input [(ngModel)]="password" name="password" type="password" id="password"
- class="form-control form-control" placeholder="Unesite lozinku..." />
+ <div class="modal-dialog modal-dialog-centered">
+ <div class="modal-content bg-alt text-offwhite">
+ <button #closeButton type="button" class="close-button btn-clear" data-bs-dismiss="modal" aria-label="Close" (click)="resetData()">
+ <mat-icon>close</mat-icon>
+ </button>
+ <h1 class="login-heading mt-5 mb-5">Prijava</h1>
+ <form>
+ <!-- Korisnicko ime -->
+ <div class="mb-3">
+ <mat-form-field appearance="fill">
+ <mat-label>Korisničko ime</mat-label>
+ <input type="text" matInput [(ngModel)]="username" name="username" id="username">
+ <mat-icon matSuffix></mat-icon>
+ </mat-form-field>
+ </div>
+ <!-- Lozinka -->
+ <div class="mb-4">
+ <mat-form-field appearance="fill">
+ <mat-label>Lozinka</mat-label>
+ <input type="password" matInput [(ngModel)]="password" name="password" id="pass" #pass>
+ <ng-container matSuffix *ngIf="!passwordShown">
+ <mat-icon (click)="togglePasswordShown()">visibility_off</mat-icon>
+ </ng-container>
+ <ng-container matSuffix *ngIf="passwordShown">
+ <mat-icon (click)="togglePasswordShown()">visibility</mat-icon>
+ </ng-container>
+ </mat-form-field>
+ </div>
+ </form>
+
+ <div class="text-lg-start">
+ <p *ngIf="wrongCreds" class="small text-center" id="wrong-creds">Unesite ispravno korisničko ime i lozinku.</p>
</div>
- </form>
-
- <div class="text-center text-lg-start mt-5">
- <p *ngIf="wrongCreds" class="small fw-bold text-danger text-center">Unesite ispravan e-mail i lozinku.</p>
- </div>
- <div class="col-md-12 d-flex justify-content-center">
- <button type="button" class="btn btn-lg" style="color:white; background-color: #003459; margin-right: 10px;" (click)="doLogin()">Prijavite se</button>
- <button type="button" class="btn btn-lg btn-outline-secondary" data-bs-dismiss="modal" (click)="resetData()">Odustanite</button>
- </div>
- <br>
- </div>
- <div class="modal-footer justify-content-center">
- <p class="small fw-bold">Još uvek nemate nalog?
- <a data-bs-toggle="modal" data-bs-target="#modalForRegister" class="link-danger">Registrujte se</a>
- </p>
- </div>
+ <!--mat-raised-button-->
+ <div class="d-flex justify-content-center">
+ <button mat-raised-button id="loginButton" (click)="doLogin()">Prijavite se</button>
+ <button mat-stroked-button id="doNotloginButton" data-bs-dismiss="modal" (click)="resetData()">Odustanite</button>
+ </div>
+ <div class="modal-footer justify-content-center mt-5">
+ <p class="small mt-1">Nemate nalog?
+ <a data-bs-toggle="modal" data-bs-target="#modalForRegister"><span id="link" (click)="cleanWarnings()">Registrujte se</span></a>
+ </p>
+ </div>
+ </div>
</div>
- </div>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.ts b/frontend/src/app/_modals/login-modal/login-modal.component.ts
index b28d9799..062a0550 100644
--- a/frontend/src/app/_modals/login-modal/login-modal.component.ts
+++ b/frontend/src/app/_modals/login-modal/login-modal.component.ts
@@ -14,10 +14,13 @@ import {AfterViewInit, ElementRef} from '@angular/core';
export class LoginModalComponent implements OnInit {
@ViewChild('closeButton') closeButton?: ElementRef;
+ @ViewChild('pass') passwordInput!: ElementRef;
username: string = '';
password: string = '';
+ passwordShown: boolean = false;
+
wrongCreds: boolean = false;
constructor(
@@ -37,8 +40,11 @@ export class LoginModalComponent implements OnInit {
if (response == "Username doesn't exist" || response == "Wrong password") {
this.wrongCreds = true;
this.password = '';
+ this.passwordShown = false;
+ this.passwordInput.nativeElement.type = "password";
}
else {
+ this.wrongCreds = false;
this.authService.authenticate(response);
(<HTMLSelectElement>this.closeButton?.nativeElement).click();
this.userInfoService.getUserInfo().subscribe((response) => {
@@ -57,4 +63,17 @@ export class LoginModalComponent implements OnInit {
this.username = '';
this.password = '';
}
+
+ togglePasswordShown() {
+ this.passwordShown = !this.passwordShown;
+
+ if (this.passwordShown)
+ this.passwordInput.nativeElement.type = "text";
+ else
+ this.passwordInput.nativeElement.type = "password";
+ }
+
+ cleanWarnings() {
+ this.wrongCreds = false;
+ }
}
diff --git a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css
diff --git a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html
new file mode 100644
index 00000000..81aec5f8
--- /dev/null
+++ b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html
@@ -0,0 +1,13 @@
+<h1 mat-dialog-title>Popunjavanje nedostajućih vrednosti</h1>
+<div mat-dialog-content>
+ <p>Želim da:</p>
+ <mat-radio-group [(ngModel)]="selectedMissingValuesOption">
+ <mat-radio-button [value]="NullValueOptions.DeleteColumns" checked>obrišem sve kolone koje sadrže nedostajuće vrednosti</mat-radio-button>
+ <mat-radio-button [value]="NullValueOptions.DeleteRows">obrišem sve redove koji sadrže nedostajuće vrednosti</mat-radio-button>
+ </mat-radio-group>
+ <p>Da li ste sigurni u izbor?</p>
+</div>
+<div mat-dialog-actions>
+ <button mat-button [mat-dialog-close]="selectedMissingValuesOption" cdkFocusInitial>Da</button>
+ <button mat-button (click)="onNoClick()">Odustani</button>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.spec.ts b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.spec.ts
new file mode 100644
index 00000000..958925f4
--- /dev/null
+++ b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MissingvaluesDialogComponent } from './missingvalues-dialog.component';
+
+describe('MissingvaluesDialogComponent', () => {
+ let component: MissingvaluesDialogComponent;
+ let fixture: ComponentFixture<MissingvaluesDialogComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ MissingvaluesDialogComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MissingvaluesDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts
new file mode 100644
index 00000000..908edd9e
--- /dev/null
+++ b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts
@@ -0,0 +1,28 @@
+import { Component, OnInit } from '@angular/core';
+import { MatDialogRef } from '@angular/material/dialog';
+import { NullValueOptions } from 'src/app/_data/Experiment';
+
+@Component({
+ selector: 'app-missingvalues-dialog',
+ templateUrl: './missingvalues-dialog.component.html',
+ styleUrls: ['./missingvalues-dialog.component.css']
+})
+export class MissingvaluesDialogComponent implements OnInit {
+
+ selectedMissingValuesOption?: NullValueOptions;
+
+ NullValueOptions = NullValueOptions;
+
+ constructor(public dialogRef: MatDialogRef<MissingvaluesDialogComponent>)
+ {
+ this.selectedMissingValuesOption = NullValueOptions.DeleteColumns;
+ }
+
+ ngOnInit(): void {
+ }
+
+ onNoClick() {
+ this.dialogRef.close();
+ }
+
+}
diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.css b/frontend/src/app/_modals/register-modal/register-modal.component.css
index e69de29b..f8496973 100644
--- a/frontend/src/app/_modals/register-modal/register-modal.component.css
+++ b/frontend/src/app/_modals/register-modal/register-modal.component.css
@@ -0,0 +1,44 @@
+.modal-content {
+ text-align: center;
+ margin: auto;
+}
+
+.modal-footer {
+ text-align: center;
+}
+
+#registerButton {
+ color: white;
+ background-color: #003459;
+ margin-right: 10px;
+}
+
+#registerButton,
+#doNotRegisterButton {
+ padding: 2% 7%;
+}
+
+.close-button {
+ margin: 2%;
+}
+
+#link {
+ text-decoration: underline;
+}
+
+#link:hover {
+ color: var(--offwhite);
+ font-size: 110%;
+}
+
+.mat-form-field {
+ width: 80%;
+}
+
+.wrong-creds {
+ color: var(--ns-warn);
+}
+
+p {
+ font-size: 11px;
+} \ No newline at end of file
diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.html b/frontend/src/app/_modals/register-modal/register-modal.component.html
index 68025a46..d76af4d6 100644
--- a/frontend/src/app/_modals/register-modal/register-modal.component.html
+++ b/frontend/src/app/_modals/register-modal/register-modal.component.html
@@ -1,86 +1,85 @@
<!-- Modal -->
-<div class="modal fade" id="modalForRegister" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
- aria-labelledby="staticBackdropLabel" aria-hidden="true">
- <div class="modal-dialog modal-dialog-centered modal-dialog modal-lg">
- <div class="modal-content">
- <div class="modal-header" style="background-color: #003459;">
- <button id="closeButtonReg" type="button" class="btn-close" data-bs-dismiss="modal" style="background-color: white;"
- aria-label="Close" (click)="resetData()"></button>
- </div>
- <div class="modal-body" style="color:#003459">
- <h1 class="text-center mt-2 mb-4">Registracija</h1>
-
- <form class="mx-5">
- <!--Ime-->
- <div class="row">
- <div class="col-6 px-3 py-3">
- <label class="form-label" for="firstName">Ime</label>
- <input type="text" id="firstName" class="form-control" [(ngModel)]="firstName"
- name="firstName" placeholder="Unesite ime...">
- <small *ngIf="wrongFirstNameBool" class="form-text text-danger">Unesite ispravno
- ime.</small>
- </div>
- <!--Prezime-->
- <div class="col-6 px-3 py-3">
- <label class="form-label" for="lastName">Prezime</label>
- <input type="text" id="lastName" class="form-control" [(ngModel)]="lastName" name="lastName"
- placeholder="Unesite prezime..." />
- <small *ngIf="wrongLastNameBool" class="form-text text-danger">Unesite ispravno
- prezime.</small>
- </div>
- </div>
- <div class="row">
- <!--Korisnicko ime-->
- <div class="col-12 px-3 py-3">
- <label class="form-label" for="username-register">Korisničko ime</label>
- <input type="text" id="username-register" class="form-control" [(ngModel)]="username"
- name="username-register" placeholder="Unesite korisničko ime..." />
- <small *ngIf="wrongUsernameBool" class="form-text text-danger">Unesite ispravno korisničko
- ime.</small>
- </div>
- </div>
- <div class="row">
- <!--Email-->
- <div class="col-12 px-3 py-3">
- <label class="form-label" for="email">E-mail adresa</label>
- <input type="email" id="email" class="form-control" [(ngModel)]="email" name="email"
- placeholder="Unesite email adresu..." />
- <small *ngIf="wrongEmailBool" class="form-text text-danger">Unesite ispravno e-mail
- adresu.</small>
- </div>
- </div>
- <div class="row">
- <!-- Lozinka 1. -->
- <div class="col-6 px-3 py-3">
- <label class="form-label" for="pass1">Lozinka</label>
- <input type="password" id="pass1" class="form-control" [(ngModel)]="pass1" name="pass1"
- placeholder="Unesite lozinku..." />
- <small *ngIf="wrongPass1Bool" class="form-text text-danger">Lozinka se mora sastojati od
- najmanje 6 karaktera.</small>
- </div>
- <!-- Lozinka 2. -->
- <div class="col-6 px-3 py-3">
- <label class="form-label" for="pass2">Potvrdite lozinku</label>
- <input type="password" id="pass2" class="form-control" [(ngModel)]="pass2" name="pass2"
- placeholder="Ponovite lozinku..." />
- <small *ngIf="wrongPass2Bool" class="form-text text-danger">Lozinke se ne
- podudaraju.</small>
- </div>
- </div>
- </form>
- <div class="col-md-12 d-flex justify-content-center mt-5">
- <button type="button" class="btn btn-lg"
- style="color:white; background-color: #003459; margin-right: 10px;"
- (click)="doRegister()">Registrujte se</button>
- <button type="button" class="btn btn-lg btn-outline-secondary" style="margin-left: 15px;"
- data-bs-dismiss="modal" (click)="resetData()">Odustanite</button>
+<div class="modal fade" id="modalForRegister" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
+ <div class="modal-dialog modal-dialog-centered">
+ <div class="modal-content bg-alt text-offwhite">
+ <button #closeButton type="button" class="close-button btn-clear" data-bs-dismiss="modal" aria-label="Close" (click)="resetData()">
+ <mat-icon>close</mat-icon>
+ </button>
+ <h1 class="mt-5 mb-4">Registracija</h1>
+ <form class="mx-4">
+ <!--Ime-->
+ <div>
+ <mat-form-field appearance="fill">
+ <mat-label>Ime</mat-label>
+ <input type="text" matInput [(ngModel)]="firstName" name="firstName" id="firstName">
+ <mat-icon matSuffix></mat-icon>
+ </mat-form-field>
+ <p *ngIf="wrongFirstNameBool" class="wrong-creds">Unesite ispravno ime.</p>
+ </div>
+ <!--Prezime-->
+ <div>
+ <mat-form-field appearance="fill">
+ <mat-label>Prezime</mat-label>
+ <input type="text" matInput [(ngModel)]="lastName" name="lastName" id="lastName">
+ <mat-icon matSuffix></mat-icon>
+ </mat-form-field>
+ <p *ngIf="wrongLastNameBool" class="wrong-creds">Unesite ispravno prezime.</p>
+ </div>
+ <!--Korisnicko ime-->
+ <div>
+ <mat-form-field appearance="fill">
+ <mat-label>Korisničko ime</mat-label>
+ <input type="text" matInput [(ngModel)]="username" name="username-register" id="username-register">
+ <mat-icon matSuffix></mat-icon>
+ </mat-form-field>
+ <p *ngIf="wrongUsernameBool" class="wrong-creds">Unesite ispravno korisničko ime.</p>
+ </div>
+ <!--Email-->
+ <div>
+ <mat-form-field appearance="fill">
+ <mat-label>E-mail adresa</mat-label>
+ <input type="email" matInput [(ngModel)]="email" name="email" id="email">
+ <mat-icon matSuffix></mat-icon>
+ </mat-form-field>
+ <p *ngIf="wrongEmailBool" class="wrong-creds">Unesite ispravno e-mail adresu.</p>
+ </div>
+ <!-- Lozinka 1. -->
+ <div>
+ <mat-form-field appearance="fill">
+ <mat-label>Lozinka</mat-label>
+ <input type="password" matInput [(ngModel)]="pass1" name="pass1" id="pass1" #password1>
+ <ng-container matSuffix *ngIf="!password1Shown">
+ <mat-icon (click)="togglePasswordShown(1)">visibility_off</mat-icon>
+ </ng-container>
+ <ng-container matSuffix *ngIf="password1Shown">
+ <mat-icon (click)="togglePasswordShown(1)">visibility</mat-icon>
+ </ng-container>
+ </mat-form-field>
+ <p *ngIf="wrongPass1Bool" class="wrong-creds">Lozinka se mora sastojati od najmanje 6 karaktera.</p>
+ </div>
+ <!-- Lozinka 2. -->
+ <div>
+ <mat-form-field appearance="fill">
+ <mat-label>Potvrdite lozinku</mat-label>
+ <input type="password" matInput [(ngModel)]="pass2" name="pass2" id="pass2" #password2>
+ <ng-container matSuffix *ngIf="!password2Shown">
+ <mat-icon (click)="togglePasswordShown(2)">visibility_off</mat-icon>
+ </ng-container>
+ <ng-container matSuffix *ngIf="password2Shown">
+ <mat-icon (click)="togglePasswordShown(2)">visibility</mat-icon>
+ </ng-container>
+ </mat-form-field>
+ <p *ngIf="wrongPass2Bool" class="wrong-creds">Lozinke se ne podudaraju.</p>
</div>
- <br>
+ </form>
+ <div class="d-flex justify-content-center mt-2">
+ <button mat-raised-button id="registerButton" (click)="doRegister()">Registrujte se</button>
+ <button mat-stroked-button id="doNotRegisterButton" data-bs-dismiss="modal" (click)="resetData()">Odustanite</button>
</div>
- <div class="modal-footer justify-content-center">
- <p class="small fw-bold">Već imate kreiran nalog?
- <a id="linkToLoginModal" data-bs-toggle="modal" data-bs-target="#modalForLogin"
- class="link-danger">Prijavite se</a>
+ <br>
+ <div class="modal-footer justify-content-center mt-3">
+ <p class="small">Imate kreiran nalog?
+ <a data-bs-toggle="modal" data-bs-target="#modalForLogin"><span id="link" (click)="cleanWarnings()">Prijavite se</span></a>
</p>
</div>
</div>
diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.ts b/frontend/src/app/_modals/register-modal/register-modal.component.ts
index 11f6727d..3726b2e0 100644
--- a/frontend/src/app/_modals/register-modal/register-modal.component.ts
+++ b/frontend/src/app/_modals/register-modal/register-modal.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { AuthService } from 'src/app/_services/auth.service';
import User from 'src/app/_data/User';
import { DOCUMENT } from '@angular/common';
@@ -34,6 +34,13 @@ export class RegisterModalComponent implements OnInit {
shared = shared;
+ password1Shown: boolean = false;
+ password2Shown: boolean = false;
+ @ViewChild('password1') password1Input!: ElementRef;
+ @ViewChild('password2') password2Input!: ElementRef;
+ @ViewChild('closeButton') closeButton!: ElementRef;
+
+
constructor(
private authService: AuthService,
@Inject(DOCUMENT) document: Document
@@ -48,6 +55,8 @@ export class RegisterModalComponent implements OnInit {
resetData() {
this.firstName = this.lastName = this.username = this.email = this.pass1 = this.pass2 = '';
this.wrongFirstNameBool = this.wrongLastNameBool = this.wrongUsernameBool = this.wrongEmailBool = this.wrongPass1Bool = this.wrongPass2Bool = false;
+ this.password1Shown = false;
+ this.password2Shown = false;
}
isCorrectName(element: string): boolean {
@@ -76,7 +85,7 @@ export class RegisterModalComponent implements OnInit {
this.wrongFirstNameBool = false;
return;
}
- (<HTMLSelectElement>document.getElementById('firstName')).focus();
+ //(<HTMLSelectElement>document.getElementById('firstName')).focus();
this.wrongFirstNameBool = true;
}
lastNameValidation() {
@@ -84,7 +93,7 @@ export class RegisterModalComponent implements OnInit {
this.wrongLastNameBool = false;
return;
}
- (<HTMLSelectElement>document.getElementById('lastName')).focus();
+ //(<HTMLSelectElement>document.getElementById('lastName')).focus();
this.wrongLastNameBool = true;
}
usernameValidation() {
@@ -92,7 +101,7 @@ export class RegisterModalComponent implements OnInit {
this.wrongUsernameBool = false;
return;
}
- (<HTMLSelectElement>document.getElementById('username-register')).focus();
+ //(<HTMLSelectElement>document.getElementById('username-register')).focus();
this.wrongUsernameBool = true;
}
emailValidation() {
@@ -100,7 +109,7 @@ export class RegisterModalComponent implements OnInit {
this.wrongEmailBool = false;
return;
}
- (<HTMLSelectElement>document.getElementById('email')).focus();
+ //(<HTMLSelectElement>document.getElementById('email')).focus();
this.wrongEmailBool = true;
}
passwordValidation() {
@@ -111,7 +120,11 @@ export class RegisterModalComponent implements OnInit {
}
this.pass1 = ''; //brisi obe ukucane lozinke
this.pass2 = '';
- (<HTMLSelectElement>document.getElementById('pass1')).focus();
+ this.password1Shown = false;
+ this.password2Shown = false;
+ this.password1Input.nativeElement.type = "password";
+ this.password2Input.nativeElement.type = "password";
+ //(<HTMLSelectElement>document.getElementById('pass1')).focus();
this.wrongPass1Bool = true;
this.wrongPass2Bool = true;
}
@@ -148,7 +161,7 @@ export class RegisterModalComponent implements OnInit {
this.authService.login(this.username, this.pass1).subscribe((response) => {
this.authService.authenticate(response);
- (<HTMLSelectElement>document.getElementById('closeButtonReg')).click();
+ this.closeButton.nativeElement.click();
//(<HTMLSelectElement>document.getElementById('linkToLoginModal')).click();
}, (error) => console.warn(error));
}
@@ -165,5 +178,25 @@ export class RegisterModalComponent implements OnInit {
}
}
+ togglePasswordShown(whichPassword: number) {
+ if (whichPassword == 1) {
+ this.password1Shown = !this.password1Shown;
+
+ if (this.password1Shown)
+ this.password1Input.nativeElement.type = "text";
+ else
+ this.password1Input.nativeElement.type = "password";
+ }
+ else {
+ this.password2Shown = !this.password2Shown;
+ if (this.password2Shown)
+ this.password2Input.nativeElement.type = "text";
+ else
+ this.password2Input.nativeElement.type = "password";
+ }
+ }
+ cleanWarnings() {
+ this.resetData();
+ }
}
diff --git a/frontend/src/app/_pages/archive/archive.component.css b/frontend/src/app/_pages/archive/archive.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_pages/archive/archive.component.css
diff --git a/frontend/src/app/_pages/archive/archive.component.html b/frontend/src/app/_pages/archive/archive.component.html
new file mode 100644
index 00000000..fc3c4763
--- /dev/null
+++ b/frontend/src/app/_pages/archive/archive.component.html
@@ -0,0 +1,49 @@
+<div class="d-flex flex-column align-items-center my-5">
+ <app-folder></app-folder>
+
+ <!--<div class="my-5" style="height: fit-content;">
+ <app-playlist [datasets]="publicDatasets"></app-playlist>
+ </div>-->
+
+ <!--<div id="cards" class="row align-items-view align-items-stretch justify-content-center">
+ <div class="card shadowed bg-light text-light col-3 m-3" style="width: 18rem;">
+ <div class="card-body">
+ <mat-icon width="48px" height="48px" style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">model_training
+ </mat-icon>
+ <h3 class="card-title my-2">Moji eksperimenti</h3>
+ <p class="card-text">
+ <a class="stretched-link" routerLink="my-models">Pregledajte</a> vaše modele, menjajte ih, napravite nove modele, ili ih obrišite.
+ </p>
+ </div>
+ </div>
+ <div class="card shadowed bg-light text-light col-3 m-3" style="width: 18rem;">
+ <div class="card-body">
+ <mat-icon width="48px" height="48px" style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">storage</mat-icon>
+ <h3 class="card-title my-2">Izvori podataka</h3>
+ <p class="card-text">
+ <a class="stretched-link" routerLink="my-datasets">Preuredite</a> vaše izvore podataka, ili dodajte novi.
+ </p>
+ </div>
+ </div>
+ <div class="card shadowed bg-light text-light col-3 m-3" style="width: 18rem;">
+ <div class="card-body">
+ <mat-icon width="48px" height="48px" style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">model_training
+ </mat-icon>
+ <h3 class="card-title my-2">Modeli</h3>
+ <p class="card-text">
+ <a class="stretched-link" routerLink="my-models">Pregledajte</a> vaše modele, menjajte ih, napravite nove modele, ili ih obrišite.
+ </p>
+ </div>
+ </div>
+ <div class="card shadowed bg-light text-light col-3 m-3" style="width: 18rem;">
+ <div class="card-body">
+ <mat-icon width="48px" height="48px" style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">batch_prediction
+ </mat-icon>
+ <h3 class="card-title my-2">Rezultati treniranja</h3>
+ <p class="card-text">
+ <a class="stretched-link" routerLink="my-predictors">Pregledajte</a> sve vaše trenirane modele, koristite ih da predvidite vrednosti za red ili skup podataka, ili ih obrišite.
+ </p>
+ </div>
+ </div>
+ </div>-->
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/archive/archive.component.spec.ts b/frontend/src/app/_pages/archive/archive.component.spec.ts
new file mode 100644
index 00000000..41fc8e77
--- /dev/null
+++ b/frontend/src/app/_pages/archive/archive.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ArchiveComponent } from './archive.component';
+
+describe('ArchiveComponent', () => {
+ let component: ArchiveComponent;
+ let fixture: ComponentFixture<ArchiveComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ArchiveComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ArchiveComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_pages/archive/archive.component.ts b/frontend/src/app/_pages/archive/archive.component.ts
new file mode 100644
index 00000000..47f96218
--- /dev/null
+++ b/frontend/src/app/_pages/archive/archive.component.ts
@@ -0,0 +1,25 @@
+import { Component, OnInit } from '@angular/core';
+import Dataset from 'src/app/_data/Dataset';
+import { DatasetsService } from 'src/app/_services/datasets.service';
+
+@Component({
+ selector: 'app-archive',
+ templateUrl: './archive.component.html',
+ styleUrls: ['./archive.component.css']
+})
+export class ArchiveComponent implements OnInit {
+
+ publicDatasets: Dataset[] = [];
+
+ constructor(private datasetsService: DatasetsService) { }
+
+ ngOnInit(): void {
+ this.datasetsService.getPublicDatasets().subscribe((datasets) => {
+ this.publicDatasets = datasets;
+ this.publicDatasets.forEach((element, index) => {
+ this.publicDatasets[index] = (<Dataset>element);
+ })
+ });
+ }
+
+}
diff --git a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.html b/frontend/src/app/_pages/browse-datasets/browse-datasets.component.html
deleted file mode 100644
index fa38a1bc..00000000
--- a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.html
+++ /dev/null
@@ -1 +0,0 @@
-<p>browse-datasets works!</p>
diff --git a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.ts b/frontend/src/app/_pages/browse-datasets/browse-datasets.component.ts
deleted file mode 100644
index dba6c25e..00000000
--- a/frontend/src/app/_pages/browse-datasets/browse-datasets.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-
-@Component({
- selector: 'app-browse-datasets',
- templateUrl: './browse-datasets.component.html',
- styleUrls: ['./browse-datasets.component.css']
-})
-export class BrowseDatasetsComponent implements OnInit {
-
- constructor() { }
-
- ngOnInit(): void {
- }
-
-}
diff --git a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.css b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.css
deleted file mode 100644
index b4ac9669..00000000
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.css
+++ /dev/null
@@ -1,7 +0,0 @@
-#container {
- border-radius: 8px;
-}
-
-#wrapper {
- color: #003459;
-} \ No newline at end of file
diff --git a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html
deleted file mode 100644
index 27e06884..00000000
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-<div id="wrapper">
-
- <div id="container" class="container p-5" style="background-color: white; min-height: 100%;">
- <div class="row mt-3 mb-2 d-flex justify-content-center">
-
- <div class="col-sm-6" style="margin-bottom: 10px;">
- <p class="glyphicon glyphicon-search"></p>
- <input type="text" class="form-control" placeholder="Pretraga" [(ngModel)]="term">
-
- </div>
-
- <div class="row">
- <div class="col-sm-4" style="margin-bottom: 10px;" *ngFor="let predictor of publicPredictors | filter:term">
- <div class="card h-100">
- <div class="card-body">
- <h3 class="card-title"><b>{{predictor.name}}</b></h3>
- <p class="card-text">{{predictor.description}}</p>
- <a class="btn btn-primary" (click)="openPredictor(predictor._id)">Iskoristi</a>
- </div>
- <div class="card-footer text-muted">
- Kreirao: {{predictor.username}} <br>
- Datum kreiranja: {{predictor.dateCreated |date}}
- </div>
- </div>
- </div>
-
-
- </div>
- <div class="text-center"*ngIf="( publicPredictors != undefined && publicPredictors|filter:term).length === 0">
- <h2>Nema rezultata</h2>
- </div>
- </div>
-
- </div>
-
-
-
-
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.spec.ts b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.spec.ts
deleted file mode 100644
index 6d13fedf..00000000
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { BrowsePredictorsComponent } from './browse-predictors.component';
-
-describe('BrowsePredictorsComponent', () => {
- let component: BrowsePredictorsComponent;
- let fixture: ComponentFixture<BrowsePredictorsComponent>;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ BrowsePredictorsComponent ]
- })
- .compileComponents();
- });
-
- beforeEach(() => {
- fixture = TestBed.createComponent(BrowsePredictorsComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
deleted file mode 100644
index 891b3cab..00000000
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { PredictorsService } from 'src/app/_services/predictors.service';
-import Predictor from 'src/app/_data/Predictor';
-import {Router} from '@angular/router'
-@Component({
- selector: 'app-browse-predictors',
- templateUrl: './browse-predictors.component.html',
- styleUrls: ['./browse-predictors.component.css']
-})
-export class BrowsePredictorsComponent implements OnInit {
-
- publicPredictors? :Predictor[];
- term: string="";
- constructor(private predictors: PredictorsService,private router:Router) {
- this.predictors.getPublicPredictors().subscribe((predictors) => {
- this.publicPredictors = predictors;
- });
- }
-
- ngOnInit(): void {
- }
- openPredictor(id:string):void{
- this.router.navigate(['predict/'+id]);
- };
-
-}
diff --git a/frontend/src/app/_pages/experiment/experiment.component.css b/frontend/src/app/_pages/experiment/experiment.component.css
new file mode 100644
index 00000000..aca0562a
--- /dev/null
+++ b/frontend/src/app/_pages/experiment/experiment.component.css
@@ -0,0 +1,55 @@
+ul {
+ list-style: none;
+}
+
+.holder {
+ display: flex;
+ flex-direction: row;
+ align-items: stretch;
+}
+
+.sidenav {
+ width: 250px;
+ background-color: var(--ns-bg-dark-50);
+}
+
+@media only screen and (max-width: 400px) {
+ .sidenav {
+ width: 100%;
+ background-color: var(--ns-bg-dark-100);
+ }
+ .holder {
+ flex-direction: column;
+ }
+}
+
+mat-stepper {
+ background-color: transparent;
+}
+
+.label {
+ color: white;
+}
+
+.steps-container {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ overflow-y: auto;
+}
+
+.step-content {
+ position: relative;
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+}
+
+.step-content-inside {
+ width: 90%;
+ height: 90%;
+ overflow-y: auto;
+} \ No newline at end of file
diff --git a/frontend/src/app/_pages/experiment/experiment.component.html b/frontend/src/app/_pages/experiment/experiment.component.html
new file mode 100644
index 00000000..08d709b2
--- /dev/null
+++ b/frontend/src/app/_pages/experiment/experiment.component.html
@@ -0,0 +1,40 @@
+<div class="container-fluid p-0 text-offwhite holder" style="height: calc(100vh - 64px);">
+ <div class="d-flex flex-colum align-items-center sidenav">
+ <mat-stepper orientation="vertical" (selectionChange)="changePage($event)">
+ <mat-step>
+ <!--editable="false"-->
+ <ng-template matStepLabel><span class="label">Izvor podataka</span></ng-template>
+ <ng-template matStepContent>
+ <p>Izaberite vas izvor podataka</p>
+ </ng-template>
+ </mat-step>
+ <mat-step>
+ <ng-template matStepLabel> <span class="label">Odabir kolona</span></ng-template>
+ <ng-template matStepContent>
+ <p>Pripremite podatke i izaberite izlazne kolone</p>
+ </ng-template>
+ </mat-step>
+ <mat-step>
+ <ng-template matStepLabel><span class="label">Treniranje</span></ng-template>
+ <p>Odaberite parametre i trenirajte model</p>
+ </mat-step>
+ </mat-stepper>
+ </div>
+ <div #stepsContainer class="steps-container">
+ <div #steps id="step_1" class="step-content">
+ <div class="step-content-inside">
+ <app-folder [type]="FolderType.Dataset" [tabsToShow]="[TabType.MyDatasets, TabType.PublicDatasets, TabType.File]" (okPressed)="goToPage(1)"></app-folder>
+ </div>
+ </div>
+ <div #steps id="step_2" class="step-content">
+ <div class="step-content-inside">
+ <app-column-table (okPressed)="goToPage(2)"></app-column-table>
+ </div>
+ </div>
+ <div #steps id="step_3" class="step-content">
+ <div class="step-content-inside">
+ <app-folder [type]="FolderType.Model" [tabsToShow]="[TabType.MyModels, TabType.PublicModels, TabType.File]" (okPressed)="goToPage(0)"></app-folder>
+ </div>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/experiment/experiment.component.spec.ts b/frontend/src/app/_pages/experiment/experiment.component.spec.ts
index fd2bbd30..fd2bbd30 100644
--- a/frontend/src/app/experiment/experiment.component.spec.ts
+++ b/frontend/src/app/_pages/experiment/experiment.component.spec.ts
diff --git a/frontend/src/app/_pages/experiment/experiment.component.ts b/frontend/src/app/_pages/experiment/experiment.component.ts
new file mode 100644
index 00000000..70f941b6
--- /dev/null
+++ b/frontend/src/app/_pages/experiment/experiment.component.ts
@@ -0,0 +1,95 @@
+import { AfterViewInit, Component, ElementRef, ViewChild, ViewChildren } from '@angular/core';
+import { StepperSelectionEvent } from '@angular/cdk/stepper';
+import { MatStepper } from '@angular/material/stepper';
+import Shared from 'src/app/Shared';
+import { FolderType } from 'src/app/_data/FolderFile';
+import { TabType } from 'src/app/_elements/folder/folder.component';
+
+@Component({
+ selector: 'app-experiment',
+ templateUrl: './experiment.component.html',
+ styleUrls: ['./experiment.component.css']
+})
+export class ExperimentComponent implements AfterViewInit {
+
+ @ViewChild(MatStepper) stepper!: MatStepper;
+ @ViewChild('stepsContainer') stepsContainer!: ElementRef;
+ @ViewChildren('steps') steps!: ElementRef[];
+
+ event: number = 0;
+
+ constructor() { }
+
+ stepHeight = this.calcStepHeight();
+
+ calcStepHeight() {
+ return window.innerHeight - 64;
+ }
+
+ ngAfterViewInit(): void {
+ window.addEventListener('resize', () => {
+ this.updatePageHeight();
+ })
+ this.updatePageHeight();
+
+ setInterval(() => {
+ this.updatePageIfScrolled();
+ }, 100);
+
+ this.stepsContainer.nativeElement.addEventListener('scroll', (event: Event) => {
+ Shared.emitBGScrollEvent(this.stepsContainer.nativeElement.scrollTop);
+ });
+ }
+
+ updatePageIfScrolled() {
+ if (this.scrolling) return;
+ const currentPage = Math.round(this.stepsContainer.nativeElement.scrollTop / this.stepHeight)
+ this.stepper.selectedIndex = currentPage;
+ }
+
+ updatePageHeight() {
+ this.stepHeight = this.calcStepHeight();
+ const stepHeight = `${this.stepHeight}px`;
+ this.stepsContainer.nativeElement.style.minHeight = stepHeight;
+ this.steps.forEach(step => {
+ step.nativeElement.style.minHeight = stepHeight;
+ })
+ }
+
+ changePage(event: StepperSelectionEvent) {
+ this.updatePage(<number>event.selectedIndex)
+ }
+
+ goToPage(pageNum: number) {
+ this.stepper.selectedIndex = pageNum;
+ this.updatePage(pageNum);
+ }
+
+ scrollTimeout: any;
+
+ updatePage(pageNum: number) {
+ this.scrolling = true;
+ this.event = pageNum;
+ let scrollAmount = 0;
+ this.steps.forEach((step, index) => {
+ if (index == pageNum) {
+ scrollAmount = step.nativeElement.offsetTop;
+ }
+ })
+ clearTimeout(this.scrollTimeout);
+ this.scrollTimeout = setTimeout(() => {
+ this.scrolling = false;
+ }, 800);
+ this.stepsContainer.nativeElement.scroll({
+ top: scrollAmount,
+ behavior: 'smooth' //auto, smooth, initial, inherit
+ });
+ }
+
+ scrolling: boolean = false;
+
+ FolderType = FolderType;
+
+ TabType = TabType;
+
+}
diff --git a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.html b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.html
deleted file mode 100644
index 84f5ebaf..00000000
--- a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.html
+++ /dev/null
@@ -1,38 +0,0 @@
-
-<div id="wrapper">
-
- <div id="container" class="container p-5" style="background-color: white; min-height: 100%;">
- <div class="row mt-3 mb-2 d-flex justify-content-center">
-
- <div class="col-sm-6" style="margin-bottom: 10px;">
- <input type="text" class="form-control" placeholder="Pretraga" [(ngModel)]="term">
- </div>
-
- <div class="row">
- <div class="col-sm-4" style="margin-bottom: 10px;" *ngFor="let dataset of publicDatasets | filter:term">
- <div class="card h-100">
- <div class="card-body">
- <h3 class="card-title"><b>{{dataset.name}}</b></h3>
- <p class="card-text">{{dataset.description}}</p>
- <a class="btn btn-primary" (click)="addDataset(dataset)">Dodaj dataset</a>
- </div>
- <div class="card-footer text-muted">
- Kreirao: {{dataset.username}} <br>
- Datum kreiranja: {{dataset.dateCreated |date}}
- </div>
- </div>
- </div>
-
-
- </div>
- <div class="text-center"*ngIf="( publicDatasets != undefined && publicDatasets|filter:term).length === 0">
- <h2>Nema rezultata</h2>
- </div>
- </div>
-
- </div>
-
-
-
-
-</div>
diff --git a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.spec.ts b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.spec.ts
deleted file mode 100644
index 6ab894fd..00000000
--- a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { FilterDatasetsComponent } from './filter-datasets.component';
-
-describe('FilterDatasetsComponent', () => {
- let component: FilterDatasetsComponent;
- let fixture: ComponentFixture<FilterDatasetsComponent>;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ FilterDatasetsComponent ]
- })
- .compileComponents();
- });
-
- beforeEach(() => {
- fixture = TestBed.createComponent(FilterDatasetsComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/_pages/home/home.component.css b/frontend/src/app/_pages/home/home.component.css
index e69de29b..22137c24 100644
--- a/frontend/src/app/_pages/home/home.component.css
+++ b/frontend/src/app/_pages/home/home.component.css
@@ -0,0 +1,20 @@
+.logo {
+ margin: 0 !important;
+}
+
+#title {
+ color: var(--offwhite);
+}
+
+h1 {
+ font-size: 64px !important;
+ font-weight: 900 !important;
+ margin-top: 1rem;
+ margin-bottom: 2.5rem;
+}
+
+.card {
+ margin: 2.5rem !important;
+ padding: 3rem;
+ width: 26rem !important;
+} \ No newline at end of file
diff --git a/frontend/src/app/_pages/home/home.component.html b/frontend/src/app/_pages/home/home.component.html
index 08f95a69..508382da 100644
--- a/frontend/src/app/_pages/home/home.component.html
+++ b/frontend/src/app/_pages/home/home.component.html
@@ -1,56 +1,32 @@
-<div class="d-flex flex-column align-items-center bg-light">
- <img src="../../../assets/svg/logo.svg" class="bi me-2" width="256" height="256" role="img">
- <div *ngIf="shared.loggedIn" class="d-flex flex-column align-items-center">
- <h2 class="my-4">Započnite sa treniranjem!</h2>
- <div id="cards" class="row align-items-stretch justify-content-center">
- <div class="card shadow col-3 m-1" style="width: 18rem;">
- <div class="card-body">
- <mat-icon width="48px" height="48px"
- style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">storage</mat-icon>
- <h3 class="card-title my-2">Moji izvori podataka</h3>
- <p class="card-text">
- <a class="stretched-link" routerLink="my-datasets">Preuredite</a> vaše izvore
- podataka, ili
- dodajte novi.
- </p>
- </div>
- </div>
- <div class="card shadow col-3 m-1" style="width: 18rem;">
- <div class="card-body">
- <mat-icon width="48px" height="48px"
- style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">model_training
- </mat-icon>
- <h3 class="card-title my-2">Moji modeli</h3>
- <p class="card-text">
- <a class="stretched-link" routerLink="my-models">Pregledajte</a> vaše modele, menjajte ih,
- napravite nove modele, ili
- ih obrišite.
- </p>
- </div>
+<div class="d-flex flex-column align-items-center">
+ <div class="logo">
+ <img src="../../../assets/images/logo.png" class="bi me-2" width="256" height="256" role="img">
+ </div>
+
+ <div id="title">
+ <h1>Igr<span class="highlight">ann</span>onica</h1>
+ </div>
+
+ <div id="cards" class="row align-items-view align-items-stretch justify-content-center">
+ <div class="card shadowed bg-light text-light col-3 m-3" style="width: 18rem;">
+ <div class="card-body">
+ <mat-icon width="48px" height="48px" style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">model_training</mat-icon>
+ <h3 class="card-title my-2">Experimentiši</h3>
+ <p class="card-text">
+ U tri koraka <a class="stretched-link" routerLink="experiment">napravite novu neuronsku mrežu</a>. Koristite postojeće izvore podataka, modele, itd.
+ </p>
</div>
- <div class="card shadow col-3 m-1" style="width: 18rem;">
- <div class="card-body">
- <mat-icon width="48px" height="48px"
- style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">batch_prediction
- </mat-icon>
- <h3 class="card-title my-2">Rezultati treniranja</h3>
- <p class="card-text">
- <a class="stretched-link" routerLink="my-predictors">Pregledajte</a> sve vaše trenirane
- modele,
- koristite ih da predvidite vrednosti za red ili skup podataka, ili ih obrišite.
- </p>
- </div>
+ </div>
+ <div class="card shadowed bg-light text-light col-3 m-3" style="width: 18rem;">
+ <div class="card-body">
+ <mat-icon width="48px" height="48px" style="font-size: 48px; margin-left: 50%; transform: translateX(-100%);">storage
+ </mat-icon>
+ <h3 class="card-title my-2">Arhiva</h3>
+ <p class="card-text">
+ <a class="stretched-link" routerLink="archive">Upravljajte</a> izvorima podataka, eksperimentima, modelima, i rezultatima treniranja. Pogledajte podatke koje su podelili drugi korisnici.
+ </p>
</div>
</div>
-
</div>
- <h2 class="my-4">Pogledajte javne izvore podataka!</h2>
- <app-carousel [items]="publicDatasets" [type]="'Dataset'">
- </app-carousel>
- <h3><a routerLink="browse-datasets">Pogledaj sve javne izvore podataka...</a></h3>
- <h2 class="my-4">Iskoristite već trenirane modele!</h2>
- <app-carousel [items]="publicPredictors" [type]="'Predictor'">
- </app-carousel>
- <h3><a routerLink="browse-predictors">Pogledaj sve javne trenirane modele...</a></h3>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/home/home.component.ts b/frontend/src/app/_pages/home/home.component.ts
index 0575c4c0..28ba2cbb 100644
--- a/frontend/src/app/_pages/home/home.component.ts
+++ b/frontend/src/app/_pages/home/home.component.ts
@@ -1,7 +1,6 @@
import { Component, OnInit } from '@angular/core';
import Dataset from 'src/app/_data/Dataset';
import Predictor from 'src/app/_data/Predictor';
-import { ItemDatasetComponent } from 'src/app/_elements/item-dataset/item-dataset.component';
import shared from 'src/app/Shared';
import { DatasetsService } from 'src/app/_services/datasets.service';
import { PredictorsService } from 'src/app/_services/predictors.service';
@@ -14,7 +13,6 @@ import { PredictorsService } from 'src/app/_services/predictors.service';
export class HomeComponent implements OnInit {
publicDatasets: Dataset[] = [];
- publicPredictors: Predictor[] = [];
shared = shared;
@@ -25,9 +23,6 @@ export class HomeComponent implements OnInit {
this.publicDatasets[index] = (<Dataset>element);
})
});
- this.predictorsService.getPublicPredictors().subscribe((predictors) => {
- this.publicPredictors = predictors;
- });
}
ngOnInit(): void {
diff --git a/frontend/src/app/_pages/my-datasets/my-datasets.component.css b/frontend/src/app/_pages/my-datasets/my-datasets.component.css
deleted file mode 100644
index 57889937..00000000
--- a/frontend/src/app/_pages/my-datasets/my-datasets.component.css
+++ /dev/null
@@ -1,8 +0,0 @@
-#header {
- background-color: #003459;
- padding-top: 20px;
- padding-bottom: 15px;
- text-align: center;
- color: white;
- border-radius: 5px;
-} \ No newline at end of file
diff --git a/frontend/src/app/_pages/my-datasets/my-datasets.component.html b/frontend/src/app/_pages/my-datasets/my-datasets.component.html
deleted file mode 100644
index 0c83dc85..00000000
--- a/frontend/src/app/_pages/my-datasets/my-datasets.component.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<div id="header">
- <h1>Moji setovi podataka</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 dataset of myDatasets">
- <app-item-dataset [dataset]="dataset"></app-item-dataset>
-
- <div class="panel-footer row"><!-- panel-footer -->
- <div class="col-xs-6 text-center">
- <div>
- <div>
- <button (click)="deleteThisDataset(dataset)" mat-raised-button color="warn" style="min-width: 10rem;float: right" ><mat-icon>delete</mat-icon></button>
- </div>
-
- </div>
- </div>
- </div><!-- end panel-footer -->
- </div>
- </div>
- <div class="text-center" *ngIf="this.myDatasets.length == 0" >
- <h2>Nema rezultata</h2>
- </div>
- </div>
-
-
- </div>
-
-
-
-
-
- </div>
diff --git a/frontend/src/app/_pages/my-datasets/my-datasets.component.spec.ts b/frontend/src/app/_pages/my-datasets/my-datasets.component.spec.ts
deleted file mode 100644
index fc1fc3f3..00000000
--- a/frontend/src/app/_pages/my-datasets/my-datasets.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { MyDatasetsComponent } from './my-datasets.component';
-
-describe('MyDatasetsComponent', () => {
- let component: MyDatasetsComponent;
- let fixture: ComponentFixture<MyDatasetsComponent>;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ MyDatasetsComponent ]
- })
- .compileComponents();
- });
-
- beforeEach(() => {
- fixture = TestBed.createComponent(MyDatasetsComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/_pages/my-datasets/my-datasets.component.ts b/frontend/src/app/_pages/my-datasets/my-datasets.component.ts
deleted file mode 100644
index 8857e371..00000000
--- a/frontend/src/app/_pages/my-datasets/my-datasets.component.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import {Router} from '@angular/router';
-import { DatasetsService } from 'src/app/_services/datasets.service';
-import Dataset from 'src/app/_data/Dataset';
-import { JwtHelperService } from '@auth0/angular-jwt';
-import { CookieService } from 'ngx-cookie-service';
-import shared from 'src/app/Shared';
-import { share } from 'rxjs';
-
-@Component({
- selector: 'app-my-datasets',
- templateUrl: './my-datasets.component.html',
- styleUrls: ['./my-datasets.component.css']
-})
-export class MyDatasetsComponent implements OnInit {
- myDatasets: Dataset[] = [];
-
- constructor(private datasetsS : DatasetsService) {
-
-
-
- }
-
- ngOnInit(): void {
-
- this.datasetsS.getMyDatasets().subscribe((response) => {
- this.myDatasets = response;
- }, (error) => {
- if (error.error == "Dataset with...") {
- shared.openDialog("Greska", "Niste dobro uneli nesto");
- }
- });
- }
-
-/*
- editModel(): void{
- this.modelsS.editModel().subscribe(m => {
- this.myModel = m;
-
- })
- }
-*/
-
-deleteThisDataset(dataset: Dataset): void{
- shared.openYesNoDialog('Brisanje seta podataka','Da li ste sigurni da želite da obrišete ovaj set podataka?',() => {
- this.datasetsS.deleteDataset(dataset).subscribe((response) => {
- this.getAllMyDatasets();
- }, (error) =>{
- if (error.error == "Dataset with name = {name} deleted") {
- shared.openDialog("Greška","Greška pri brisanju dataseta!");
- }
- });
- });
-}
-
- getAllMyDatasets(): void{
- this.datasetsS.getMyDatasets().subscribe(m => {
- this.myDatasets = m;
- });
- }
-
-
-}
diff --git a/frontend/src/app/_pages/my-models/my-models.component.css b/frontend/src/app/_pages/my-models/my-models.component.css
deleted file mode 100644
index 19d29595..00000000
--- a/frontend/src/app/_pages/my-models/my-models.component.css
+++ /dev/null
@@ -1,12 +0,0 @@
-button{
- margin-left: 5%;
- margin-right: 5%;
-}
-#header {
- background-color: #003459;
- padding-top: 20px;
- padding-bottom: 15px;
- text-align: center;
- color: white;
- border-radius: 5px;
-} \ No newline at end of file
diff --git a/frontend/src/app/_pages/my-predictors/my-predictors.component.css b/frontend/src/app/_pages/my-predictors/my-predictors.component.css
deleted file mode 100644
index ccb9fb7b..00000000
--- a/frontend/src/app/_pages/my-predictors/my-predictors.component.css
+++ /dev/null
@@ -1,13 +0,0 @@
-#header {
- background-color: #003459;
- padding-top: 20px;
- padding-bottom: 15px;
- text-align: center;
- color: white;
- border-radius: 5px;
-}
-
-.row{
- margin-top: 10px;
- margin-bottom: 30px;
-} \ No newline at end of file
diff --git a/frontend/src/app/_pages/my-predictors/my-predictors.component.html b/frontend/src/app/_pages/my-predictors/my-predictors.component.html
deleted file mode 100644
index 31fa786c..00000000
--- a/frontend/src/app/_pages/my-predictors/my-predictors.component.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<div id="header">
- <h1>Trenirani 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 predictor of predictors">
- <app-item-predictor [predictor]="predictor"></app-item-predictor>
- <div>
- <button (click)="deleteThisPredictor(predictor)" mat-raised-button color="warn" style="min-width: 10rem;float: right" ><mat-icon>delete</mat-icon></button>
- </div>
- </div>
- </div>
-</div>
-</div>
-</div>
-
-
-
diff --git a/frontend/src/app/_pages/my-predictors/my-predictors.component.spec.ts b/frontend/src/app/_pages/my-predictors/my-predictors.component.spec.ts
deleted file mode 100644
index 37dddf6d..00000000
--- a/frontend/src/app/_pages/my-predictors/my-predictors.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { MyPredictorsComponent } from './my-predictors.component';
-
-describe('MyPredictorsComponent', () => {
- let component: MyPredictorsComponent;
- let fixture: ComponentFixture<MyPredictorsComponent>;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ MyPredictorsComponent ]
- })
- .compileComponents();
- });
-
- beforeEach(() => {
- fixture = TestBed.createComponent(MyPredictorsComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/_pages/my-predictors/my-predictors.component.ts b/frontend/src/app/_pages/my-predictors/my-predictors.component.ts
deleted file mode 100644
index 4dc5300d..00000000
--- a/frontend/src/app/_pages/my-predictors/my-predictors.component.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import Predictor from 'src/app/_data/Predictor';
-import { PredictorsService } from 'src/app/_services/predictors.service';
-import shared from 'src/app/Shared';
-@Component({
- selector: 'app-my-predictors',
- templateUrl: './my-predictors.component.html',
- styleUrls: ['./my-predictors.component.css']
-})
-export class MyPredictorsComponent implements OnInit {
- predictors: Predictor[] = [];
- constructor(private predictorsS : PredictorsService) {
- }
- ngOnInit(): void {
- this.predictorsS.getMyPredictors().subscribe((response) => {
- this.predictors = response;
- }, (error) => {
- if (error.error == "Predictor with...") {
- shared.openDialog("Greska", "Greska");
- }
- });
- }
-
- deleteThisPredictor(predictor: Predictor): void{
- shared.openYesNoDialog('Brisanje prediktora','Da li ste sigurni da želite da obrišete prediktor?',() => {
- this.predictorsS.deletePredictor(predictor).subscribe((response) => {
- this.getAllMyPredictors();
- }, (error) =>{
- if (error.error == "Predictor with name = {name} deleted") {
- shared.openDialog("Obaveštenje", "Greška prilikom brisanja prediktora.");
- }
- });
- });
- }
-
- getAllMyPredictors(): void{
- this.predictorsS.getMyPredictors().subscribe(p => {
- this.predictors = p;
- });
- }
-
-
-}
diff --git a/frontend/src/app/_pages/playground/playground.component.css b/frontend/src/app/_pages/playground/playground.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_pages/playground/playground.component.css
diff --git a/frontend/src/app/_pages/playground/playground.component.html b/frontend/src/app/_pages/playground/playground.component.html
new file mode 100644
index 00000000..1dd7e331
--- /dev/null
+++ b/frontend/src/app/_pages/playground/playground.component.html
@@ -0,0 +1,18 @@
+<div class="position-fixed d-flex flex-col align-items-center justify-content-center" style="top: 50%; left: 50%; transform: translateX(-50%);">
+ <div class="d-flex flex-row align-items-center justify-content-center mt-5">
+ <h2 class="text-light my-2">
+ Broj tačaka:
+ </h2>
+ <mat-slider class="mx-3" [(ngModel)]="backgroundFill" min="0" max="1" step="0.01" (input)="updateFillPref($event)">
+ </mat-slider>
+
+ </div>
+ <div class="d-flex flex-row align-items-center justify-content-center mt-5">
+ <h2 class="text-light my-2">
+ Animacija: </h2>
+ <mat-slide-toggle class="mx-3" [(ngModel)]="animateBackground" (change)="updateAnimPref()"></mat-slide-toggle>
+
+ </div>
+</div>
+<div style="height: 5000px;">
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/model-load/model-load.component.spec.ts b/frontend/src/app/_pages/playground/playground.component.spec.ts
index 1dafd966..bf66b27e 100644
--- a/frontend/src/app/_elements/model-load/model-load.component.spec.ts
+++ b/frontend/src/app/_pages/playground/playground.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ModelLoadComponent } from './model-load.component';
+import { PlaygroundComponent } from './playground.component';
-describe('ModelLoadComponent', () => {
- let component: ModelLoadComponent;
- let fixture: ComponentFixture<ModelLoadComponent>;
+describe('PlaygroundComponent', () => {
+ let component: PlaygroundComponent;
+ let fixture: ComponentFixture<PlaygroundComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ ModelLoadComponent ]
+ declarations: [ PlaygroundComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(ModelLoadComponent);
+ fixture = TestBed.createComponent(PlaygroundComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_pages/playground/playground.component.ts b/frontend/src/app/_pages/playground/playground.component.ts
new file mode 100644
index 00000000..831132a4
--- /dev/null
+++ b/frontend/src/app/_pages/playground/playground.component.ts
@@ -0,0 +1,35 @@
+import { Component, OnInit } from '@angular/core';
+import { MatSliderChange } from '@angular/material/slider';
+import { CookieService } from 'ngx-cookie-service';
+
+@Component({
+ selector: 'app-playground',
+ templateUrl: './playground.component.html',
+ styleUrls: ['./playground.component.css']
+})
+export class PlaygroundComponent implements OnInit {
+
+ animateBackground = true;
+ backgroundFill = 1.0;
+
+ constructor(private cookie: CookieService) { }
+
+ updateFillPref(event: MatSliderChange) {
+ this.backgroundFill = event.value!;
+ this.cookie.set('backgroundFill', "" + this.backgroundFill);
+ }
+
+ updateAnimPref() {
+ this.cookie.set('animateBackground', "" + this.animateBackground);
+ }
+
+ ngOnInit(): void {
+ if (this.cookie.check('animateBackground')) {
+ this.animateBackground = this.cookie.get('animateBackground') == 'true';
+ }
+ if (this.cookie.check('backgroundFill')) {
+ this.backgroundFill = parseFloat(this.cookie.get('backgroundFill'));
+ }
+ }
+
+}
diff --git a/frontend/src/app/_pages/predict/predict.component.css b/frontend/src/app/_pages/predict/predict.component.css
deleted file mode 100644
index dab059a5..00000000
--- a/frontend/src/app/_pages/predict/predict.component.css
+++ /dev/null
@@ -1,3 +0,0 @@
-#wrapper {
- color: #003459;
-} \ No newline at end of file
diff --git a/frontend/src/app/_pages/predict/predict.component.html b/frontend/src/app/_pages/predict/predict.component.html
deleted file mode 100644
index 13afa8e4..00000000
--- a/frontend/src/app/_pages/predict/predict.component.html
+++ /dev/null
@@ -1,73 +0,0 @@
-
-<div id="wrapper">
- <br>
- <div id="container" class="container p-5" style="background-color: white; min-height: 100%;">
-
- <div id="header">
- <h1>Iskoristite prediktor</h1>
- </div>
-
- <br>
-
- <div class="form-group row mt-3 mb-2 d-flex justify-content-left">
- <!--justify-content-center-->
- <h2> Izabrani prediktor: </h2>
- <div class="col-10">
- <label for="output" class="col-sm-5 col-form-label">Naziv prediktora: <b>{{predictor.name}}</b></label>
- </div>
- <div>
- <label for="output" class="col-sm-5 col-form-label">Opis prediktora: <b>{{predictor.description}}</b></label>
- </div>
-
-
- </div>
- <br>
- <label for="type" class="form-check-label" ><b>Informacije o prediktoru</b></label>
- <div class="col-5 mt-2">
- <label for="type" class="form-check-label" >Prediktor {{predictor.isPublic?"je":"nije"}} javni.</label>
- </div>
- <div class="col-5 mt-2">
- <label for="type" class="form-check-label" >Prediktor {{predictor.accessibleByLink?"je":"nije"}} dostupan za deljenje.</label>
- </div>
- <br>
- <div class="col-2">
- <label for="dateCreated" class="col-form-label">Datum:</label>
- <input type="text" class="form-control-plaintext" id="dateCreated" placeholder="--/--/--"
- value="{{predictor.dateCreated | date: 'dd/MM/yyyy'}}" readonly>
- </div>
-
-
- <br>
- <div >
- <!--input -->
- <h3>Popunite ulazne kolone:</h3>
- <div id="divInputs" class="form-check mt-2">
- <div *ngIf="predictor" class="form-group row mt-3 mb-2 d-flex justify-content-left">
- <div *ngFor="let input of predictor.inputs; let i = index">
- <label for="{{input}}" class="col-sm-2 col-form-label"><b>{{input}}</b></label>
- <input name="{{input}}" type="text" [(ngModel)]="inputs[i].value" >
-
- </div>
-
- </div>
- </div>
-
- <br>
-
- </div>
- <div>
- <label for="output" class="col-sm-2 col-form-label">Izlaz: <b>{{predictor.output}}</b></label>
- </div>
-
- <div class="form-group row mt-5 mb-3">
- <div class="col"></div>
- <button class="btn btn-lg col-4" style="background-color:#003459; color:white;"
- (click)="usePredictor();">Iskoristi prediktor</button>
- <div class="col"></div>
-
- </div>
-
-
-
- </div>
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/predict/predict.component.ts b/frontend/src/app/_pages/predict/predict.component.ts
deleted file mode 100644
index 39dec0ae..00000000
--- a/frontend/src/app/_pages/predict/predict.component.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { ActivatedRoute } from '@angular/router';
-import Predictor from 'src/app/_data/Predictor';
-import { PredictorsService } from 'src/app/_services/predictors.service';
-import shared from 'src/app/Shared';
-
-@Component({
- selector: 'app-predict',
- templateUrl: './predict.component.html',
- styleUrls: ['./predict.component.css']
-})
-export class PredictComponent implements OnInit {
-
- inputs : Column[] = [];
-
-
- predictor:Predictor;
- constructor(private predictS : PredictorsService, private route: ActivatedRoute) {
- this.predictor = new Predictor();
- }
-
- ngOnInit(): void {
- this.route.params.subscribe(url => {
- this.predictS.getPredictor(url["id"]).subscribe(p => {
-
- this.predictor = p;
- this.predictor.inputs.forEach((p,index)=> this.inputs[index] = new Column(p, ""));
- })
- });
- }
-
- usePredictor(): void{
- this.predictS.usePredictor(this.predictor, this.inputs).subscribe(p => {
- shared.openDialog("Obaveštenje", "Prediktor je uspešno poslat na probu."); //pisalo je "na treniranje" ??
- })
- }
-}
-
-
-export class Column {
- constructor(
- public name : string,
- public value : (number | string)){
- }
-} \ No newline at end of file
diff --git a/frontend/src/app/_pages/profile/profile.component.css b/frontend/src/app/_pages/profile/profile.component.css
index 5565d105..428870da 100644
--- a/frontend/src/app/_pages/profile/profile.component.css
+++ b/frontend/src/app/_pages/profile/profile.component.css
@@ -1,44 +1,21 @@
-body{margin-top:20px;
-background-color:#f2f6fc;
-color:#69707a;
+.card{
+ background-color: transparent;
+ color:var(--offwhite)
}
-.img-account-profile {
- height: 10rem;
- border: 1px solid lightgray;
-}
-.rounded-circle {
- border-radius: 50% !important;
-}
-.card .card-header {
- font-weight: 500;
-}
-.card-header:first-child {
- border-radius: 0.35rem 0.35rem 0 0;
+
+.card-header{
+ background-color: var(--ns-primary-50);
+ color:var(--offwhite)
}
-.card-header {
- padding: 1rem 1.35rem;
- margin-bottom: 0;
- background-color: rgba(33, 40, 50, 0.03);
- border-bottom: 1px solid rgba(33, 40, 50, 0.125);
+.card-body{
+ background-color: var(--ns-bg-dark-50);
}
-.form-control, .dataTable-input {
- display: block;
+
+mat-form-field{
width: 100%;
- padding: 0.875rem 1.125rem;
- font-size: 0.875rem;
- font-weight: 400;
- line-height: 1;
- color: #69707a;
- background-color: #fff;
- background-clip: padding-box;
- border: 1px solid #c5ccd6;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- border-radius: 0.35rem;
- transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
-.selectedPicture {
- border: 2px solid darkgray;
+.danger-Text{
+ color:var(--ns-warn)
}
+
diff --git a/frontend/src/app/_pages/profile/profile.component.html b/frontend/src/app/_pages/profile/profile.component.html
index 557d69fd..37df4f14 100644
--- a/frontend/src/app/_pages/profile/profile.component.html
+++ b/frontend/src/app/_pages/profile/profile.component.html
@@ -27,17 +27,21 @@
<div class="row gx-3 mb-3">
<!-- Form Group (password)-->
<div class="col-md-6">
- <label class="small mb-1" for="inputPassword">Važeća lozinka</label>
- <input class="form-control" id="inputPassword" name="inputPassword" type="password" [(ngModel)]="this.oldPass" placeholder="Trenutna lozinka">
- <small *ngIf="wrongPassBool" class="form-text text-danger">Neispravna lozinka.</small>
- <small *ngIf="wrongOldPassBool" class="form-text text-danger">Pogrešan format.</small>
+ <small *ngIf="wrongPassBool" class="form-text danger-Text">Neispravna lozinka.</small>
+ <mat-form-field appearance="fill">
+ <mat-label>Važeća lozinka</mat-label>
+ <input matInput id="inputPassword" name="inputPassword" type="password" placeholder="" [(ngModel)]="this.oldPass">
+ </mat-form-field>
+ <small *ngIf="wrongOldPassBool" class="form-text danger-Text">Pogrešan format.</small>
</div>
<!-- Form Group (new password)-->
<div class="col-md-6">
- <label class="small mb-1" for="inputNewPassword">Nova lozinka</label>
- <input class="form-control" id="inputNewPassword" name="inputNewPassword" type="password" [(ngModel)]="this.newPass1" placeholder="Ukucaj novu lozinku">
- <small *ngIf="wrongNewPassBool" class="form-text text-danger">Lozinke se ne podudaraju.</small>
- <small *ngIf="wrongNewPass1Bool" class="form-text text-danger">Pogrešan format.</small>
+ <mat-form-field appearance="fill">
+ <mat-label>Nova lozinka</mat-label>
+ <input matInput id="inputNewPassword" name="inputNewPassword" type="password" placeholder="" [(ngModel)]="this.newPass1">
+ </mat-form-field>
+ <small *ngIf="wrongNewPassBool" class="form-text danger-Text">Lozinke se ne podudaraju.</small>
+ <small *ngIf="wrongNewPass1Bool" class="form-text danger-Text">Pogrešan format.</small>
</div>
</div>
@@ -46,15 +50,17 @@
<div class="col-md-6">
<div class="col text-center">
<!-- Save changes button-->
- <button class="btn btn-primary text-center mt-4" type="button" (click)="savePasswordChanges()">Promeni lozinku</button>
+ <button mat-raised-button color="primary" (click)="savePasswordChanges()">Promeni lozinku</button>
</div>
</div>
<!-- Form Group (new password again)-->
<div class="col-md-6">
- <label class="small mb-1" for="inputNewPasswordAgain">Ponovo nova lozinka</label>
- <input class="form-control" id="inputNewPasswordAgain" name="inputNewPasswordAgain" type="password" [(ngModel)]="this.newPass2" placeholder="Ukucaj novu lozinku">
- <small *ngIf="wrongNewPassBool" class="form-text text-danger">Lozinke se ne podudaraju.</small>
- <small *ngIf="wrongNewPass2Bool" class="form-text text-danger">Pogrešan format.</small>
+ <mat-form-field appearance="fill">
+ <mat-label>Ponovo nova lozinka</mat-label>
+ <input matInput id="inputNewPasswordAgain" name="inputNewPasswordAgain" placeholder="" type="password" [(ngModel)]="this.newPass2">
+ </mat-form-field>
+ <small *ngIf="wrongNewPassBool" class="form-text danger-Text">Lozinke se ne podudaraju.</small>
+ <small *ngIf="wrongNewPass2Bool" class="form-text danger-Text">Pogrešan format.</small>
</div>
</div>
</div>
@@ -74,15 +80,19 @@
<div class="row gx-3 mb-3">
<!-- Form Group (username)-->
<div class="col-md-6">
- <label class="small mb-1" for="inputUsername">Korisničko ime (kako će ostali korisnici videti tvoje ime)</label>
- <input class="form-control" id="inputUsername" name="inputUsername" type="text" [(ngModel)]="this.username">
- <small *ngIf="wrongUsernameBool" class="form-text text-danger">Pogrešan format.</small>
+ <mat-form-field appearance="fill">
+ <mat-label>Korisničko ime (kako će ostali korisnici videti tvoje ime)</mat-label>
+ <input matInput id="inputUsername" name="inputUsername" type="text" [(ngModel)]="this.username">
+ </mat-form-field>
+ <small *ngIf="wrongUsernameBool" class="form-text danger-Text">Pogrešan format.</small>
</div>
<!-- Form Group (email address)-->
<div class="col-md-6">
- <label class="small mb-1" for="inputEmailAddress">Email adresa</label>
- <input class="form-control" id="inputEmailAddress" name="inputEmailAddress" type="email" [(ngModel)]="this.email">
- <small *ngIf="wrongEmailBool" class="form-text text-danger">Pogrešan format.</small>
+ <mat-form-field appearance="fill">
+ <mat-label>Email adresa</mat-label>
+ <input matInput id="inputEmailAddress" name="inputEmailAddress" type="email" [(ngModel)]="this.email">
+ </mat-form-field>
+ <small *ngIf="wrongEmailBool" class="form-text danger-Text">Pogrešan format.</small>
</div>
</div>
@@ -90,15 +100,19 @@
<div class="row gx-3 mb-3">
<!-- Form Group (first name)-->
<div class="col-md-6">
- <label class="small mb-1" for="inputFirstName">Ime</label>
- <input class="form-control" id="inputFirstName" name="inputFirstName" type="text" [(ngModel)]="this.firstName">
- <small *ngIf="wrongFirstNameBool" class="form-text text-danger">Pogrešan format.</small>
+ <mat-form-field appearance="fill">
+ <mat-label>Ime</mat-label>
+ <input matInput id="inputFirstName" name="inputFirstName" type="text" [(ngModel)]="this.firstName">
+ </mat-form-field>
+ <small *ngIf="wrongFirstNameBool" class="form-text danger-Text">Pogrešan format.</small>
</div>
<!-- Form Group (last name)-->
<div class="col-md-6">
- <label class="small mb-1" for="inputLastName">Prezime</label>
- <input class="form-control" id="inputLastName" name="inputLastName" type="text" [(ngModel)]="this.lastName">
- <small *ngIf="wrongLastNameBool" class="form-text text-danger">Pogrešan format.</small>
+ <mat-form-field appearance="fill">
+ <mat-label>Prezime</mat-label>
+ <input matInput id="inputLastName" name="inputLastName" type="text" [(ngModel)]="this.lastName">
+ </mat-form-field>
+ <small *ngIf="wrongLastNameBool" class="form-text danger-Text">Pogrešan format.</small>
</div>
</div>
@@ -121,7 +135,7 @@
<div class="row mt-5">
<div class="col text-center">
<!-- Save changes button-->
- <button class="btn btn-primary text-center" type="button" (click)="saveInfoChanges()">Sačuvaj izmene</button>
+ <button mat-raised-button color="primary" (click)="saveInfoChanges()" >Sačuvaj izmene</button>
</div>
</div>
</form>
diff --git a/frontend/src/app/_pages/test/test.component.css b/frontend/src/app/_pages/test/test.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_pages/test/test.component.css
diff --git a/frontend/src/app/_pages/test/test.component.html b/frontend/src/app/_pages/test/test.component.html
new file mode 100644
index 00000000..94679055
--- /dev/null
+++ b/frontend/src/app/_pages/test/test.component.html
@@ -0,0 +1,5 @@
+<app-pie-chart></app-pie-chart>
+<app-doughnut-chart></app-doughnut-chart>
+<app-barchart></app-barchart>
+<app-box-plot></app-box-plot>
+<app-heatmap></app-heatmap> \ No newline at end of file
diff --git a/frontend/src/app/_pages/test/test.component.spec.ts b/frontend/src/app/_pages/test/test.component.spec.ts
new file mode 100644
index 00000000..e0f9bcc9
--- /dev/null
+++ b/frontend/src/app/_pages/test/test.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TestComponent } from './test.component';
+
+describe('TestComponent', () => {
+ let component: TestComponent;
+ let fixture: ComponentFixture<TestComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ TestComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TestComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_pages/test/test.component.ts b/frontend/src/app/_pages/test/test.component.ts
new file mode 100644
index 00000000..b3c0d8cf
--- /dev/null
+++ b/frontend/src/app/_pages/test/test.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-test',
+ templateUrl: './test.component.html',
+ styleUrls: ['./test.component.css']
+})
+export class TestComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit(): void {
+ }
+
+}
diff --git a/frontend/src/app/_services/auth.service.ts b/frontend/src/app/_services/auth.service.ts
index ef340684..dd46615d 100644
--- a/frontend/src/app/_services/auth.service.ts
+++ b/frontend/src/app/_services/auth.service.ts
@@ -1,9 +1,9 @@
-import { Injectable } from '@angular/core';
+import { EventEmitter, Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { JwtHelperService } from '@auth0/angular-jwt';
import { CookieService } from 'ngx-cookie-service';
import shared from '../Shared';
-import { Configuration } from '../configuration.service';
+import { Configuration } from './configuration.service';
const jwtHelper = new JwtHelperService();
@@ -13,6 +13,7 @@ const jwtHelper = new JwtHelperService();
export class AuthService {
shared = shared;
+ public loggedInEvent: EventEmitter<boolean> = new EventEmitter();
constructor(private http: HttpClient, private cookie: CookieService) { }
@@ -52,7 +53,7 @@ export class AuthService {
var property = jwtHelper.decodeToken(this.cookie.get('token'));
var username = property['name'];
if (username != "") {
-
+
this.refresher = setTimeout(() => {
this.http.post(`${Configuration.settings.apiURL}/auth/renewJwt`, {}, { headers: this.authHeader(), responseType: 'text' }).subscribe((response) => {
this.authenticate(response);
diff --git a/frontend/src/app/configuration.service.spec.ts b/frontend/src/app/_services/configuration.service.spec.ts
index ec51dfa5..4b9322b5 100644
--- a/frontend/src/app/configuration.service.spec.ts
+++ b/frontend/src/app/_services/configuration.service.spec.ts
@@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing';
-import { ConfigurationService } from './configuration.service';
+import { Configuration as ConfigurationService } from './configuration.service';
describe('ConfigurationService', () => {
let service: ConfigurationService;
diff --git a/frontend/src/app/configuration.service.ts b/frontend/src/app/_services/configuration.service.ts
index 4d2b0987..cda1091a 100644
--- a/frontend/src/app/configuration.service.ts
+++ b/frontend/src/app/_services/configuration.service.ts
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
-import { IConfig } from '../app/_data/IConfig'
+import { IConfig } from '../_data/IConfig'
@Injectable()
export class Configuration {
diff --git a/frontend/src/app/_services/datasets.service.ts b/frontend/src/app/_services/datasets.service.ts
index b2272f0a..3b6e6b64 100644
--- a/frontend/src/app/_services/datasets.service.ts
+++ b/frontend/src/app/_services/datasets.service.ts
@@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
-import { Configuration } from '../configuration.service';
+import { Configuration } from './configuration.service';
import Dataset from '../_data/Dataset';
import { AuthService } from './auth.service';
@@ -27,6 +27,9 @@ export class DatasetsService {
getDatasetFile(fileId: any): any {
return this.http.get(`${Configuration.settings.apiURL}/file/csvRead/true/${fileId}`, { headers: this.authService.authHeader(), responseType: 'text' });
}
+ getDatasetFilePartial(fileId: any, startRow: number, rowNum: number): Observable<any> {
+ return this.http.get(`${Configuration.settings.apiURL}/file/csvRead/true/${fileId}/${startRow}/${rowNum}`, { headers: this.authService.authHeader(), responseType: 'text' });
+ }
editDataset(dataset: Dataset): Observable<Dataset> {
return this.http.put<Dataset>(`${Configuration.settings.apiURL}/dataset/` + dataset._id, dataset, { headers: this.authService.authHeader() });
diff --git a/frontend/src/app/_services/experiments.service.ts b/frontend/src/app/_services/experiments.service.ts
index 0d0d372b..bdaf62a7 100644
--- a/frontend/src/app/_services/experiments.service.ts
+++ b/frontend/src/app/_services/experiments.service.ts
@@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
-import { Configuration } from '../configuration.service';
+import { Configuration } from './configuration.service';
import Experiment from '../_data/Experiment';
import { AuthService } from './auth.service';
diff --git a/frontend/src/app/_services/models.service.ts b/frontend/src/app/_services/models.service.ts
index 44383828..d79e2781 100644
--- a/frontend/src/app/_services/models.service.ts
+++ b/frontend/src/app/_services/models.service.ts
@@ -4,7 +4,7 @@ import Model from '../_data/Model';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
import Dataset from '../_data/Dataset';
-import { Configuration } from '../configuration.service';
+import { Configuration } from '../_services/configuration.service';
@Injectable({
providedIn: 'root'
diff --git a/frontend/src/app/_services/predictors.service.ts b/frontend/src/app/_services/predictors.service.ts
index a24ee708..e2033e3e 100644
--- a/frontend/src/app/_services/predictors.service.ts
+++ b/frontend/src/app/_services/predictors.service.ts
@@ -1,9 +1,8 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
-import { Configuration } from '../configuration.service';
+import { Configuration } from './configuration.service';
import Predictor from '../_data/Predictor';
-import { Column } from '../_pages/predict/predict.component';
import { AuthService } from './auth.service';
@Injectable({
@@ -31,3 +30,10 @@ export class PredictorsService {
return this.http.get<Predictor[]>(`${Configuration.settings.apiURL}/predictor/mypredictors`, { headers: this.authService.authHeader() });
}
}
+
+export class Column {
+ constructor(
+ public name: string,
+ public value: (number | string)) {
+ }
+} \ No newline at end of file
diff --git a/frontend/src/app/_services/signal-r.service.ts b/frontend/src/app/_services/signal-r.service.ts
index b279b5ca..234636fe 100644
--- a/frontend/src/app/_services/signal-r.service.ts
+++ b/frontend/src/app/_services/signal-r.service.ts
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import * as signalR from "@microsoft/signalr";
import { CookieService } from 'ngx-cookie-service';
-import { Configuration } from '../configuration.service';
+import { Configuration } from './configuration.service';
@Injectable({
providedIn: 'root'
})
diff --git a/frontend/src/app/_services/user-info.service.ts b/frontend/src/app/_services/user-info.service.ts
index 5d3394f6..8efeb903 100644
--- a/frontend/src/app/_services/user-info.service.ts
+++ b/frontend/src/app/_services/user-info.service.ts
@@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
-import { Configuration } from '../configuration.service';
+import { Configuration } from './configuration.service';
import User from '../_data/User';
import { AuthService } from './auth.service';
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 238668d9..f5f1ccae 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -3,33 +3,21 @@ import { RouterModule, Routes } from '@angular/router';
import { AuthGuardService } from './_services/auth-guard.service';
import { HomeComponent } from './_pages/home/home.component';
-import { MyDatasetsComponent } from './_pages/my-datasets/my-datasets.component';
-import { MyModelsComponent } from './_pages/my-models/my-models.component';
-import { MyPredictorsComponent } from './_pages/my-predictors/my-predictors.component';
-import { BrowsePredictorsComponent } from './_pages/browse-predictors/browse-predictors.component';
-import { BrowseDatasetsComponent } from './_pages/browse-datasets/browse-datasets.component';
-import { SettingsComponent } from './_pages/settings/settings.component';
import { ProfileComponent } from './_pages/profile/profile.component';
-import { PredictComponent } from './_pages/predict/predict.component';
-import { FilterDatasetsComponent } from './_pages/filter-datasets/filter-datasets.component';
-import { ExperimentComponent } from './experiment/experiment.component';
-import { TrainingComponent } from './training/training.component';
+import { PlaygroundComponent } from './_pages/playground/playground.component';
+import { ExperimentComponent } from './_pages/experiment/experiment.component';
+import { ArchiveComponent } from './_pages/archive/archive.component';
+import { ColumnTableComponent } from './_elements/column-table/column-table.component';
+import { TestComponent } from './_pages/test/test.component';
const routes: Routes = [
{ path: '', component: HomeComponent, data: { title: 'Početna strana' } },
- /*{ path: 'add-model', component: AddModelComponent, data: { title: 'Dodaj model' } },*/
- { path: 'experiment', component: ExperimentComponent, data: { title: 'Dodaj eksperiment' } },
- { path: 'training', component: TrainingComponent, data: { title: 'Treniraj model' } },
- { path: 'training/:id', component: TrainingComponent, data: { title: 'Treniraj model' } },
- { path: 'my-datasets', component: MyDatasetsComponent, canActivate: [AuthGuardService], data: { title: 'Moji izvori podataka' } },
- { path: 'my-models', component: MyModelsComponent, canActivate: [AuthGuardService], data: { title: 'Moji modeli' } },
- { path: 'my-predictors', component: MyPredictorsComponent, canActivate: [AuthGuardService], data: { title: 'Moji trenirani modeli' } },
- { path: 'settings', component: SettingsComponent, canActivate: [AuthGuardService], data: { title: 'Podešavanja' } },
+ { path: 'experiment', component: ExperimentComponent, data: { title: 'Eksperiment' } },
+ { path: 'archive', component: ArchiveComponent, data: { title: 'Arhiva' } },
{ path: 'profile', component: ProfileComponent, canActivate: [AuthGuardService], data: { title: 'Profil' } },
- { path: 'browse-datasets', component: FilterDatasetsComponent, data: { title: 'Javni izvori podataka' } },
- { path: 'browse-predictors', component: BrowsePredictorsComponent, data: { title: 'Javni trenirani modeli' } },
- { path: 'predict/:id', component: PredictComponent, data: { title: 'Predvidi vrednosti' } },
-
+ { path: 'playground', component: PlaygroundComponent, data: { title: 'Zabava' } },
+ { path: 'sonja', component: ColumnTableComponent },
+ { path: 'test', component: TestComponent, data: { title: 'Test' } }
];
@NgModule({
diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html
index daf93cc1..d15793e7 100644
--- a/frontend/src/app/app.component.html
+++ b/frontend/src/app/app.component.html
@@ -1,10 +1,13 @@
-<app-reactive-background [bgColor]="'#003459'" [lineColor]="'#00a8e8'" [pointColor]="'#cfeffb'"
- [cursorLineColor]="'#888888'" [numPoints]="300">
+<app-gradient-background colorHorizontal1="rgba(0, 8, 45, 0.5)" colorHorizontal2="rgba(0, 52, 89, 0.5)" colorVertical1="rgba(0, 52, 89, 0.5)" colorVertical2="rgba(0, 152, 189, 0.5)"></app-gradient-background>
+<app-reactive-background [speed]="0.0005" [scrollSpeed]="0.25" [minDistance]="0.1" [maxSize]="3" [cursorDistance]="0.17" lineColor="#00a8e8" pointColor="rgba(0, 188, 252, 0.33)" cursorLineColor="#00a8e8" [numPoints]="300">
+</app-reactive-background>
+<app-reactive-background [speed]="0.0008" [scrollSpeed]="0.5" [minDistance]="0.12" [maxSize]="4" [cursorDistance]="0.19" lineColor="#00a8e8" pointColor="rgba(0, 188, 252, 0.66)" cursorLineColor="#00a8e8" [numPoints]="200">
+</app-reactive-background>
+<app-reactive-background [speed]="0.001" [scrollSpeed]="1" [minDistance]="0.14" [maxSize]="5" [cursorDistance]="0.22" lineColor="#00a8e8" pointColor="rgba(0, 188, 252, 1)" cursorLineColor="#00a8e8" [numPoints]="100">
</app-reactive-background>
<app-navbar></app-navbar>
-<div class="container h-100">
- <router-outlet></router-outlet>
- <!--<app-barchart></app-barchart>
- <app-scatterchart></app-scatterchart>-->
-</div>
+<a class="bg-controls" style="z-index: 1000;" routerLink="playground">
+ <mat-icon color="accent">settings_suggest</mat-icon>
+</a>
+<router-outlet></router-outlet>
<app-notifications></app-notifications> \ No newline at end of file
diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts
index 59f247ed..f9bc2726 100644
--- a/frontend/src/app/app.component.ts
+++ b/frontend/src/app/app.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { AfterViewInit, Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter, map } from 'rxjs';
@@ -11,9 +11,12 @@ import Shared from './Shared';
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
-export class AppComponent implements OnInit {
+export class AppComponent implements OnInit, AfterViewInit {
+ constructor(private router: Router, private titleService: Title, private authService: AuthService, private signalRService: SignalRService, private http: HttpClient) {
- constructor(private router: Router, private titleService: Title,private authService:AuthService,private signalRService:SignalRService,private http:HttpClient) { }
+ }
+ ngAfterViewInit(): void {
+ }
ngOnInit() {
this.router.events
@@ -36,23 +39,10 @@ export class AppComponent implements OnInit {
this.titleService.setTitle(`${title} - Igrannonica`);
}
});
- if(!this.authService.isAuthenticated())
- {
- this.authService.addGuestToken();
- }
- this.signalRService.startConnection();
- //this.startHttpRequest();
-
-
-
-
- }
- private startHttpRequest = () => {
- this.http.get('http://localhost:5283/chatHub')
- .subscribe(res => {
- console.log(res);
- })
+ if (!this.authService.isAuthenticated()) {
+ this.authService.addGuestToken();
+ }
+ this.signalRService.startConnection();
+ //this.startHttpRequest();
}
-
-
}
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index c4f89ad8..fc6d3c6b 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -8,46 +8,47 @@ import { MatIconModule } from '@angular/material/icon';
import { NgMultiSelectDropDownModule } from 'ng-multiselect-dropdown';
import { NgChartsModule } from 'ng2-charts';
import { Ng2SearchPipeModule } from 'ng2-search-filter';
-import { AppComponent } from './app.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-import { DatasetLoadComponent } from './_elements/dataset-load/dataset-load.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-import { LoginModalComponent } from './_modals/login-modal/login-modal.component';
import { ReactiveFormsModule } from '@angular/forms';
-import { RegisterModalComponent } from './_modals/register-modal/register-modal.component';
-
+import { AppComponent } from './app.component';
+// Modules and modals
+import { Configuration } from './_services/configuration.service';
import { MaterialModule } from './material.module';
+import { LoginModalComponent } from './_modals/login-modal/login-modal.component';
+import { RegisterModalComponent } from './_modals/register-modal/register-modal.component';
+import { AlertDialogComponent } from './_modals/alert-dialog/alert-dialog.component';
+import { YesNoDialogComponent } from './_modals/yes-no-dialog/yes-no-dialog.component';
+import { EncodingDialogComponent } from './_modals/encoding-dialog/encoding-dialog.component';
+import { MissingvaluesDialogComponent } from './_modals/missingvalues-dialog/missingvalues-dialog.component';
+// Pages
import { HomeComponent } from './_pages/home/home.component';
-import { NavbarComponent } from './_elements/navbar/navbar.component';
-import { ItemPredictorComponent } from './_elements/item-predictor/item-predictor.component';
-import { ItemDatasetComponent } from './_elements/item-dataset/item-dataset.component';
-import { CarouselComponent } from './_elements/carousel/carousel.component';
-import { SettingsComponent } from './_pages/settings/settings.component';
import { ProfileComponent } from './_pages/profile/profile.component';
-import { MyPredictorsComponent } from './_pages/my-predictors/my-predictors.component';
-import { MyDatasetsComponent } from './_pages/my-datasets/my-datasets.component';
-import { MyModelsComponent } from './_pages/my-models/my-models.component';
-import { BrowseDatasetsComponent } from './_pages/browse-datasets/browse-datasets.component';
-import { BrowsePredictorsComponent } from './_pages/browse-predictors/browse-predictors.component';
-import { PredictComponent } from './_pages/predict/predict.component';
-import { ScatterchartComponent } from './scatterchart/scatterchart.component';
-import { BarchartComponent } from './barchart/barchart.component';
+import { ExperimentComponent } from './_pages/experiment/experiment.component';
+import { PlaygroundComponent } from './_pages/playground/playground.component';
+import { ArchiveComponent } from './_pages/archive/archive.component';
+// Charts
+import { ScatterchartComponent } from './_elements/_charts/scatterchart/scatterchart.component';
+import { BarchartComponent } from './_elements/_charts/barchart/barchart.component';
+import { PieChartComponent } from './_elements/_charts/pie-chart/pie-chart.component';
+import { BoxPlotComponent } from './_elements/_charts/box-plot/box-plot.component';
+// Elements
+import { NavbarComponent } from './_elements/navbar/navbar.component';
import { NotificationsComponent } from './_elements/notifications/notifications.component';
import { DatatableComponent } from './_elements/datatable/datatable.component';
-import { FilterDatasetsComponent } from './_pages/filter-datasets/filter-datasets.component';
import { ReactiveBackgroundComponent } from './_elements/reactive-background/reactive-background.component';
-import { ItemModelComponent } from './_elements/item-model/item-model.component';
-import { AnnvisualComponent } from './_elements/annvisual/annvisual.component';
-import { ExperimentComponent } from './experiment/experiment.component';
import { LoadingComponent } from './_elements/loading/loading.component';
-import { ModelLoadComponent } from './_elements/model-load/model-load.component';
-import { AlertDialogComponent } from './_modals/alert-dialog/alert-dialog.component';
-import { AddNewDatasetComponent } from './_elements/add-new-dataset/add-new-dataset.component';
import { GraphComponent } from './_elements/graph/graph.component';
-import { TrainingComponent } from './training/training.component';
-import { ItemExperimentComponent } from './_elements/item-experiment/item-experiment.component';
-import { YesNoDialogComponent } from './_modals/yes-no-dialog/yes-no-dialog.component';
-import { Configuration } from './configuration.service';
+import { GradientBackgroundComponent } from './_elements/gradient-background/gradient-background.component';
+import { PlaylistComponent } from './_elements/playlist/playlist.component';
+import { FormDatasetComponent } from './_elements/form-dataset/form-dataset.component';
+import { FormModelComponent } from './_elements/form-model/form-model.component';
+import { ColumnTableComponent } from './_elements/column-table/column-table.component';
+import { FolderComponent } from './_elements/folder/folder.component';
+import { TestComponent } from './_pages/test/test.component';
+import { DoughnutChartComponent } from './_elements/_charts/doughnut-chart/doughnut-chart.component';
+import { HeatmapComponent } from './_elements/_charts/heatmap/heatmap.component';
+import { HeatMapAllModule } from '@syncfusion/ej2-angular-heatmap';
export function initializeApp(appConfig: Configuration) {
return () => appConfig.load();
@@ -55,39 +56,36 @@ export function initializeApp(appConfig: Configuration) {
@NgModule({
declarations: [
AppComponent,
- DatasetLoadComponent,
LoginModalComponent,
RegisterModalComponent,
HomeComponent,
NavbarComponent,
- ItemPredictorComponent,
- ItemDatasetComponent,
- CarouselComponent,
- SettingsComponent,
ProfileComponent,
- MyPredictorsComponent,
- MyDatasetsComponent,
- MyModelsComponent,
- BrowseDatasetsComponent,
- BrowsePredictorsComponent,
- PredictComponent,
ScatterchartComponent,
BarchartComponent,
NotificationsComponent,
DatatableComponent,
- FilterDatasetsComponent,
ReactiveBackgroundComponent,
- ItemModelComponent,
- AnnvisualComponent,
ExperimentComponent,
LoadingComponent,
- ModelLoadComponent,
AlertDialogComponent,
- AddNewDatasetComponent,
GraphComponent,
- TrainingComponent,
- ItemExperimentComponent,
- YesNoDialogComponent
+ YesNoDialogComponent,
+ PlaygroundComponent,
+ GradientBackgroundComponent,
+ PlaylistComponent,
+ ArchiveComponent,
+ FormDatasetComponent,
+ FormModelComponent,
+ ColumnTableComponent,
+ PieChartComponent,
+ BoxPlotComponent,
+ FolderComponent,
+ EncodingDialogComponent,
+ MissingvaluesDialogComponent,
+ TestComponent,
+ DoughnutChartComponent,
+ HeatmapComponent
],
imports: [
BrowserModule,
@@ -102,6 +100,7 @@ export function initializeApp(appConfig: Configuration) {
MatIconModule,
NgChartsModule,
Ng2SearchPipeModule,
+ HeatMapAllModule
],
providers: [
Configuration,
diff --git a/frontend/src/app/experiment/experiment.component.css b/frontend/src/app/experiment/experiment.component.css
deleted file mode 100644
index 4a3d7741..00000000
--- a/frontend/src/app/experiment/experiment.component.css
+++ /dev/null
@@ -1,43 +0,0 @@
-#header {
- background-color: #003459;
- padding-top: 30px;
- padding-bottom: 20px;
-}
-
-#header h1 {
- font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
- text-align: center;
- color: white;
-}
-
-#container {
- border-radius: 8px;
-}
-
-#wrapper {
- color: #003459;
-}
-
-.btnType1 {
- background-color: #003459;
- color: white;
-}
-
-.btnType2 {
- background-color: white;
- color: #003459;
- border-color: #003459;
-}
-
-.selectedDatasetClass {
- /*border-color: 2px solid #003459;*/
- background-color: lightblue;
-}
-
-ul li:hover {
- background-color: lightblue;
-}
-
-h2 {
- color: #003459;
-} \ No newline at end of file
diff --git a/frontend/src/app/material.module.ts b/frontend/src/app/material.module.ts
index d16cef3d..baaae58b 100644
--- a/frontend/src/app/material.module.ts
+++ b/frontend/src/app/material.module.ts
@@ -1,21 +1,122 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
-import { MatDialogModule } from '@angular/material/dialog';
-import { MatButtonModule } from '@angular/material/button';
+// Material Form Controls
+import { MatAutocompleteModule } from '@angular/material/autocomplete';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
-import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatRadioModule } from '@angular/material/radio';
+import { MatSelectModule } from '@angular/material/select';
+import { MatSliderModule } from '@angular/material/slider';
+import { MatSlideToggleModule } from '@angular/material/slide-toggle';
+// Material Navigation
+import { MatMenuModule } from '@angular/material/menu';
+import { MatSidenavModule } from '@angular/material/sidenav';
+import { MatToolbarModule } from '@angular/material/toolbar';
+// Material Layout
+import { MatCardModule } from '@angular/material/card';
+import { MatDividerModule } from '@angular/material/divider';
+import { MatExpansionModule } from '@angular/material/expansion';
+import { MatGridListModule } from '@angular/material/grid-list';
+import { MatListModule } from '@angular/material/list';
+import { MatStepperModule } from '@angular/material/stepper';
+import { MatTabsModule } from '@angular/material/tabs';
+import { MatTreeModule } from '@angular/material/tree';
+// Material Buttons & Indicators
+import { MatButtonModule } from '@angular/material/button';
+import { MatButtonToggleModule } from '@angular/material/button-toggle';
+import { MatBadgeModule } from '@angular/material/badge';
+import { MatChipsModule } from '@angular/material/chips';
import { MatIconModule } from '@angular/material/icon';
-
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatRippleModule } from '@angular/material/core';
+// Material Popups & Modals
+import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatSnackBarModule } from '@angular/material/snack-bar';
+import { MatTooltipModule } from '@angular/material/tooltip';
+// Material Data tables
+import { MatPaginatorModule } from '@angular/material/paginator';
+import { MatSortModule } from '@angular/material/sort';
+import { MatTableModule } from '@angular/material/table';
@NgModule({
- exports: [
+ declarations: [],
+ imports: [
CommonModule,
- MatDialogModule,
- MatButtonModule,
+ MatAutocompleteModule,
+ MatCheckboxModule,
+ MatDatepickerModule,
MatFormFieldModule,
MatInputModule,
+ MatRadioModule,
+ MatSelectModule,
+ MatSliderModule,
+ MatSlideToggleModule,
+ MatMenuModule,
+ MatSidenavModule,
+ MatToolbarModule,
+ MatCardModule,
+ MatDividerModule,
+ MatExpansionModule,
+ MatGridListModule,
+ MatListModule,
+ MatStepperModule,
+ MatTabsModule,
+ MatTreeModule,
+ MatButtonModule,
+ MatButtonToggleModule,
+ MatBadgeModule,
+ MatChipsModule,
+ MatIconModule,
+ MatProgressSpinnerModule,
+ MatProgressBarModule,
+ MatRippleModule,
+ MatBottomSheetModule,
+ MatDialogModule,
+ MatSnackBarModule,
+ MatTooltipModule,
+ MatPaginatorModule,
+ MatSortModule,
+ MatTableModule
+ ],
+ exports: [
+ MatAutocompleteModule,
MatCheckboxModule,
- MatIconModule
+ MatDatepickerModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatRadioModule,
+ MatSelectModule,
+ MatSliderModule,
+ MatSlideToggleModule,
+ MatMenuModule,
+ MatSidenavModule,
+ MatToolbarModule,
+ MatCardModule,
+ MatDividerModule,
+ MatExpansionModule,
+ MatGridListModule,
+ MatListModule,
+ MatStepperModule,
+ MatTabsModule,
+ MatTreeModule,
+ MatButtonModule,
+ MatButtonToggleModule,
+ MatBadgeModule,
+ MatChipsModule,
+ MatIconModule,
+ MatProgressSpinnerModule,
+ MatProgressBarModule,
+ MatRippleModule,
+ MatBottomSheetModule,
+ MatDialogModule,
+ MatSnackBarModule,
+ MatTooltipModule,
+ MatPaginatorModule,
+ MatSortModule,
+ MatTableModule
]
})
-export class MaterialModule {} \ No newline at end of file
+export class MaterialModule { } \ No newline at end of file
diff --git a/frontend/src/app/training/training.component.css b/frontend/src/app/training/training.component.css
deleted file mode 100644
index 490c56b5..00000000
--- a/frontend/src/app/training/training.component.css
+++ /dev/null
@@ -1,39 +0,0 @@
-#header {
- background-color: #003459;
- padding-top: 30px;
- padding-bottom: 20px;
-}
-
-#header h1 {
- font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
- text-align: center;
- color: white;
-}
-
-#container {
- border-radius: 8px;
-}
-
-#wrapper {
- color: #003459;
-}
-
-.btnType1 {
- background-color: #003459;
- color: white;
-}
-
-.btnType2 {
- background-color: white;
- color: #003459;
- border-color: #003459;
-}
-
-.selectedExperimentClass {
- /*border-color: 2px solid #003459;*/
- background-color: lightblue;
-}
-
-ul li:hover {
- background-color: lightblue;
-} \ No newline at end of file
diff --git a/frontend/src/app/training/training.component.ts b/frontend/src/app/training/training.component.ts
deleted file mode 100644
index 027d2c22..00000000
--- a/frontend/src/app/training/training.component.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import Shared from '../Shared';
-import Experiment from '../_data/Experiment';
-import Model from '../_data/Model';
-import { DatasetsService } from '../_services/datasets.service';
-import { ExperimentsService } from '../_services/experiments.service';
-import { ModelsService } from '../_services/models.service';
-
-@Component({
- selector: 'app-training',
- templateUrl: './training.component.html',
- styleUrls: ['./training.component.css']
-})
-export class TrainingComponent{
-
- myExperiments?: Experiment[];
- selectedExperiment?: Experiment;
- selectedModel?: Model;
-
- trainingResult: any;
-
- term: string = "";
-
- constructor(private modelsService: ModelsService, private datasetsService: DatasetsService, private experimentsService: ExperimentsService) {
- this.experimentsService.getMyExperiments().subscribe((experiments) => {
- this.myExperiments = experiments;
- });
- }
-
- selectThisExperiment(experiment: Experiment) {
- this.selectedExperiment = experiment;
- }
-
- selectModel(model: Model) {
- this.selectedModel = model;
- }
-
- trainModel() {
- this.trainingResult = undefined;
-
- if (this.selectedExperiment == undefined) {
- Shared.openDialog("Greška", "Molimo Vas da izaberete eksperiment iz kolekcije.");
- return;
- }
- if (this.selectedModel == undefined) {
- Shared.openDialog("Greška", "Molimo Vas da izaberete model.");
- return;
- }
- this.modelsService.trainModel(this.selectedModel._id, this.selectedExperiment._id).subscribe((response: any) => {
- //console.log('Train model complete!', response);
- Shared.openDialog("Obaveštenje", "Treniranje modela je uspešno završeno!");
- this.trainingResult = response;
- });
- }
-}
diff --git a/frontend/src/assets/images/add_model_background.jpg b/frontend/src/assets/images/add_model_background.jpg
deleted file mode 100644
index d86f0566..00000000
--- a/frontend/src/assets/images/add_model_background.jpg
+++ /dev/null
Binary files differ
diff --git a/frontend/src/assets/images/logo.png b/frontend/src/assets/images/logo.png
index 2e15550a..dc8830de 100644
--- a/frontend/src/assets/images/logo.png
+++ b/frontend/src/assets/images/logo.png
Binary files differ
diff --git a/frontend/src/assets/images/logo_igrannonica_temp - Copy.png b/frontend/src/assets/images/logo_igrannonica_temp - Copy.png
new file mode 100644
index 00000000..a9d7d396
--- /dev/null
+++ b/frontend/src/assets/images/logo_igrannonica_temp - Copy.png
Binary files differ
diff --git a/frontend/src/assets/images/logo_igrannonica_temp.png b/frontend/src/assets/images/logo_igrannonica_temp.png
new file mode 100644
index 00000000..9e8e8855
--- /dev/null
+++ b/frontend/src/assets/images/logo_igrannonica_temp.png
Binary files differ
diff --git a/frontend/src/custom-theme.scss b/frontend/src/custom-theme.scss
index a6538c37..e8626080 100644
--- a/frontend/src/custom-theme.scss
+++ b/frontend/src/custom-theme.scss
@@ -1,35 +1,250 @@
+/**
+* Generated theme by Material Theme Generator
+* https://materialtheme.arcsine.dev
+* Fork at: https://materialtheme.arcsine.dev/?c=YHBhbGV0dGU$YHByaW1hcnk$YF48IzAwYThlOCIsIj9lcjwjYjNlNWY4IiwiO2VyPCMwMDhkZGV$LCIlPmBePCMwMDYzYWIiLCI~ZXI8I2IzZDBlNiIsIjtlcjwjMDA0Nzkxfiwid2Fybj5gXjwjZjliN2I3IiwiP2VyPCNmZGU5ZTkiLCI7ZXI8I2Y2OWY5Zn4sIj9UZXh0PCNkZmQ3ZDciLCI~PTwjMDAzNDU5IiwiO1RleHQ8I2RmZDdkNyIsIjs9PCMwMDM0NTl$LCJmb250cz5bYEA8KC00fixgQDwoLTN$LGBAPCgtMn4sYEA8KC0xfixgQDxoZWFkbGluZX4sYEA8dGl0bGV$LGBAPHN1YiktMn4sYEA8c3ViKS0xfixgQDxib2R5LTJ$LGBAPGJvZHktMX4sYEA8YnV0dG9ufixgQDxjYXB0aW9ufixgQDxpbnB1dCIsInNpemU$bnVsbH1dLCJpY29uczxGaWxsZWQiLCI~bmVzcz5mYWxzZSwidmVyc2lvbj4xM30=
+*/
-// Custom Theming for Angular Material
-// For more information: https://material.angular.io/guide/theming
@use '@angular/material' as mat;
-// Plus imports for other components in your app.
-
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
-// Be sure that you only ever include this mixin once!
-@include mat.core();
+// Fonts
+@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
+@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap');
+$fontConfig: ( display-4: mat.define-typography-level(112px, 112px, 300, 'Roboto', -0.0134em),
+display-3: mat.define-typography-level(56px, 56px, 400, 'Roboto', -0.0089em),
+display-2: mat.define-typography-level(45px, 48px, 400, 'Roboto', 0.0000em),
+display-1: mat.define-typography-level(34px, 40px, 400, 'Roboto', 0.0074em),
+headline: mat.define-typography-level(24px, 32px, 400, 'Roboto', 0.0000em),
+title: mat.define-typography-level(20px, 32px, 500, 'Roboto', 0.0075em),
+subheading-2: mat.define-typography-level(16px, 28px, 400, 'Roboto', 0.0094em),
+subheading-1: mat.define-typography-level(15px, 24px, 500, 'Roboto', 0.0067em),
+body-2: mat.define-typography-level(14px, 24px, 500, 'Roboto', 0.0179em),
+body-1: mat.define-typography-level(14px, 20px, 400, 'Roboto', 0.0179em),
+button: mat.define-typography-level(14px, 14px, 500, 'Roboto', 0.0893em),
+caption: mat.define-typography-level(12px, 20px, 400, 'Roboto', 0.0333em),
+input: mat.define-typography-level(inherit, 1.125, 400, 'Roboto', 1.5px));
+// Foreground Elements
+// Light Theme Text
+$dark-text: #dfd7d7;
+$dark-primary-text: rgba($dark-text,
+0.87);
+$dark-accent-text: rgba($dark-primary-text,
+0.54);
+$dark-disabled-text: rgba($dark-primary-text,
+0.38);
+$dark-dividers: rgba($dark-primary-text,
+0.12);
+$dark-focused: rgba($dark-primary-text,
+0.12);
+$mat-light-theme-foreground: ( base : black,
+divider : $dark-dividers,
+dividers : $dark-dividers,
+disabled : $dark-disabled-text,
+disabled-button : rgba($dark-text, 0.26),
+disabled-text : $dark-disabled-text,
+elevation : black,
+secondary-text : $dark-accent-text,
+hint-text : $dark-disabled-text,
+accent-text : $dark-accent-text,
+icon : $dark-accent-text,
+icons : $dark-accent-text,
+text : $dark-primary-text,
+slider-min : $dark-primary-text,
+slider-off : rgba($dark-text, 0.26),
+slider-off-active: $dark-disabled-text,
+);
+// Dark Theme text
+$light-text: #dfd7d7;
+$light-primary-text: $light-text;
+$light-accent-text: rgba($light-primary-text,
+0.7);
+$light-disabled-text: rgba($light-primary-text,
+0.5);
+$light-dividers: rgba($light-primary-text,
+0.12);
+$light-focused: rgba($light-primary-text,
+0.12);
+$mat-dark-theme-foreground: ( base : $light-text,
+divider : $light-dividers,
+dividers : $light-dividers,
+disabled : $light-disabled-text,
+disabled-button : rgba($light-text, 0.3),
+disabled-text : $light-disabled-text,
+elevation : black,
+hint-text : $light-disabled-text,
+secondary-text : $light-accent-text,
+accent-text : $light-accent-text,
+icon : $light-text,
+icons : $light-text,
+text : $light-text,
+slider-min : $light-text,
+slider-off : rgba($light-text, 0.3),
+slider-off-active: rgba($light-text, 0.3),
+);
+// Background config
+// Light bg
+$light-background : #003459;
+$light-bg-darker-5 : darken($light-background,
+5%);
+$light-bg-darker-10 : darken($light-background,
+10%);
+$light-bg-darker-20 : darken($light-background,
+20%);
+$light-bg-darker-30 : darken($light-background,
+30%);
+$light-bg-lighter-5 : lighten($light-background,
+5%);
+$dark-bg-tooltip : lighten(#003459,
+20%);
+$dark-bg-alpha-4 : rgba(#003459,
+0.04);
+$dark-bg-alpha-12 : rgba(#003459,
+0.12);
+$mat-light-theme-background: ( background : $light-background,
+status-bar : $light-bg-darker-20,
+app-bar : $light-bg-darker-5,
+hover : $dark-bg-alpha-4,
+card : $light-bg-lighter-5,
+dialog : $light-bg-lighter-5,
+tooltip : $dark-bg-tooltip,
+disabled-button : $dark-bg-alpha-12,
+raised-button : $light-bg-lighter-5,
+focused-button : $dark-focused,
+selected-button : $light-bg-darker-20,
+selected-disabled-button: $light-bg-darker-30,
+disabled-button-toggle : $light-bg-darker-10,
+unselected-chip : $light-bg-darker-10,
+disabled-list-option : $light-bg-darker-10,
+);
+// Dark bg
+$dark-background : #003459;
+$dark-bg-lighter-5 : lighten($dark-background,
+5%);
+$dark-bg-lighter-10 : lighten($dark-background,
+10%);
+$dark-bg-lighter-20 : lighten($dark-background,
+20%);
+$dark-bg-lighter-30 : lighten($dark-background,
+30%);
+$light-bg-alpha-4 : rgba(#003459,
+0.04);
+$light-bg-alpha-12 : rgba(#003459,
+0.12);
+// Background palette for dark themes.
+$mat-dark-theme-background: ( background : $dark-background,
+status-bar : $dark-bg-lighter-20,
+app-bar : $dark-bg-lighter-5,
+hover : $light-bg-alpha-4,
+card : $dark-bg-lighter-5,
+dialog : $dark-bg-lighter-5,
+tooltip : $dark-bg-lighter-20,
+disabled-button : $light-bg-alpha-12,
+raised-button : $dark-bg-lighter-5,
+focused-button : $light-focused,
+selected-button : $dark-bg-lighter-20,
+selected-disabled-button: $dark-bg-lighter-30,
+disabled-button-toggle : $dark-bg-lighter-10,
+unselected-chip : $dark-bg-lighter-20,
+disabled-list-option : $dark-bg-lighter-10,
+);
+// Compute font config
+@include mat.core($fontConfig);
+// Theme Config
+body {
+ --primary-color: #00a8e8;
+ --primary-lighter-color: #b3e5f8;
+ --primary-darker-color: #008dde;
+ --text-primary-color: #{$light-primary-text};
+ --text-primary-lighter-color: #{$dark-primary-text};
+ --text-primary-darker-color: #{$light-primary-text};
+}
+
+$mat-primary: ( main: #00a8e8,
+lighter: #b3e5f8,
+darker: #008dde,
+200: #00a8e8, // For slide toggle,
+contrast: ( main: $light-primary-text, lighter: $dark-primary-text, darker: $light-primary-text, ));
+$theme-primary: mat.define-palette($mat-primary,
+main,
+lighter,
+darker);
+body {
+ --accent-color: #0063ab;
+ --accent-lighter-color: #b3d0e6;
+ --accent-darker-color: #004791;
+ --text-accent-color: #{$light-primary-text};
+ --text-accent-lighter-color: #{$dark-primary-text};
+ --text-accent-darker-color: #{$light-primary-text};
+}
-// Define the palettes for your theme using the Material Design palettes available in palette.scss
-// (imported above). For each palette, you can optionally specify a default, lighter, and darker
-// hue. Available color palettes: https://material.io/design/color/
-$frontend-primary: mat.define-palette(mat.$indigo-palette);
-$frontend-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
+$mat-accent: ( main: #0063ab,
+lighter: #b3d0e6,
+darker: #004791,
+200: #0063ab, // For slide toggle,
+contrast: ( main: $light-primary-text, lighter: $dark-primary-text, darker: $light-primary-text, ));
+$theme-accent: mat.define-palette($mat-accent,
+main,
+lighter,
+darker);
+body {
+ --warn-color: #f9b7b7;
+ --warn-lighter-color: #fde9e9;
+ --warn-darker-color: #f69f9f;
+ --text-warn-color: #{$dark-primary-text};
+ --text-warn-lighter-color: #{$dark-primary-text};
+ --text-warn-darker-color: #{$dark-primary-text};
+}
-// The warn palette is optional (defaults to red).
-$frontend-warn: mat.define-palette(mat.$red-palette);
+$mat-warn: ( main: #f9b7b7,
+lighter: #fde9e9,
+darker: #f69f9f,
+200: #f9b7b7, // For slide toggle,
+contrast: ( main: $dark-primary-text, lighter: $dark-primary-text, darker: $dark-primary-text, ));
+$theme-warn: mat.define-palette($mat-warn,
+main,
+lighter,
+darker);
+;
+$theme: ( primary: $theme-primary,
+accent: $theme-accent,
+warn: $theme-warn,
+is-dark: true,
+foreground: $mat-dark-theme-foreground,
+background: $mat-dark-theme-background,
+);
+$altTheme: ( primary: $theme-primary,
+accent: $theme-accent,
+warn: $theme-warn,
+is-dark: false,
+foreground: $mat-light-theme-foreground,
+background: $mat-light-theme-background,
+);
+// Theme Init
+@include mat.all-component-themes($theme);
+.theme-alternate {
+ @include mat.all-component-themes($altTheme);
+}
-// Create the theme object. A theme consists of configurations for individual
-// theming systems such as "color" or "typography".
-$frontend-theme: mat.define-light-theme((
- color: (
- primary: $frontend-primary,
- accent: $frontend-accent,
- warn: $frontend-warn,
- )
-));
+// Specific component overrides, pieces that are not in line with the general theming
+// Handle buttons appropriately, with respect to line-height
+.mat-raised-button,
+.mat-stroked-button,
+.mat-flat-button {
+ padding: 0 1.15em;
+ margin: 0 .65em;
+ min-width: 3em;
+ line-height: 36.4px
+}
-// Include theme styles for core and each component used in your app.
-// Alternatively, you can import and @include the theme mixins for each component
-// that you are using.
-@include mat.all-component-themes($frontend-theme);
+.mat-standard-chip {
+ padding: .5em .85em;
+ min-height: 2.5em;
+}
+.material-icons {
+ font-size: 24px;
+ font-family: 'Material Icons', 'Material Icons';
+ .mat-badge-content {
+ font-family: 'Roboto';
+ }
+} \ No newline at end of file
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 802b8bd0..e65d8d7c 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -1,5 +1,7 @@
@import '~bootstrap/dist/css/bootstrap.min.css';
-body {
- /*background-image: url('/assets/images/add_model_background.jpg');*/
- background-color: #003459;
-} \ No newline at end of file
+@import './styles/theme.css';
+@import './styles/layout.css';
+@import './styles/helper.css';
+@import './styles/scrollbar.css';
+@import './styles/fx.css';
+@import 'material-icons/iconfont/material-icons.css'; \ No newline at end of file
diff --git a/frontend/src/styles/fx.css b/frontend/src/styles/fx.css
new file mode 100644
index 00000000..9c29ad58
--- /dev/null
+++ b/frontend/src/styles/fx.css
@@ -0,0 +1,24 @@
+.shadowed:hover {
+ box-shadow: rgba(0, 152, 189, 0.4) 0px 5px, rgba(0, 152, 189, 0.3) 0px 10px, rgba(0, 152, 189, 0.2) 0px 15px, rgba(0, 152, 189, 0.1) 0px 20px, rgba(0, 152, 189, 0.05) 0px 25px;
+}
+
+.shadowed:first-child:hover {
+ box-shadow: rgba(0, 152, 189, 0.4) -5px 5px, rgba(0, 152, 189, 0.3) -10px 10px, rgba(0, 152, 189, 0.2) -15px 15px, rgba(0, 152, 189, 0.1) -20px 20px, rgba(0, 152, 189, 0.05) -25px 25px;
+}
+
+.shadowed:last-child:hover {
+ box-shadow: rgba(0, 152, 189, 0.4) 5px 5px, rgba(0, 152, 189, 0.3) 10px 10px, rgba(0, 152, 189, 0.2) 15px 15px, rgba(0, 152, 189, 0.1) 20px 20px, rgba(0, 152, 189, 0.05) 25px 25px;
+}
+
+.shadow-accent:hover {
+ box-shadow: rgba(0, 152, 189, 0.4) 0px 5px, rgba(0, 152, 189, 0.3) 0px 10px, rgba(0, 152, 189, 0.2) 0px 15px, rgba(0, 152, 189, 0.1) 0px 20px, rgba(0, 152, 189, 0.05) 0px 25px;
+ animation-name: holo-hover;
+ animation-duration: 300ms;
+ transform: perspective(100em) rotateX(10deg);
+}
+
+@keyframes holo-hover {
+ to {
+ transform: perspective(100em) rotateX(10deg);
+ }
+} \ No newline at end of file
diff --git a/frontend/src/styles/helper.css b/frontend/src/styles/helper.css
new file mode 100644
index 00000000..d4772134
--- /dev/null
+++ b/frontend/src/styles/helper.css
@@ -0,0 +1,144 @@
+@keyframes logo-animation {
+ from {
+ transform: perspective(100em) rotateX(50deg) rotateZ(0deg);
+ }
+ to {
+ transform: perspective(100em) rotateX(50deg) rotateZ(360deg);
+ }
+}
+
+.ann-logo {
+ animation-name: logo-animation;
+ animation-duration: 3140ms;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+}
+
+.bg-controls {
+ position: fixed;
+ bottom: 10px;
+ right: 10px;
+}
+
+.center-horizontal {
+ margin-top: 50%;
+ margin-left: auto;
+ transform: translateX(-50%);
+}
+
+.footer-center {
+ position: relative;
+ height: 1rem;
+ text-align: center;
+}
+
+.row-height {
+ white-space: nowrap;
+ height: 1rem;
+}
+
+.icon-double>*:nth-child(2) {
+ margin-left: -1rem;
+}
+
+.no-wrap {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.btn-clear {
+ border: unset;
+ background-color: unset;
+ outline: unset;
+ position: relative;
+}
+
+.input-icon {
+ color: var(--offwhite);
+ transform: translateY(25%);
+}
+
+.input-icon:hover {
+ color: var(--ns-primary);
+}
+
+.f-row {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.icon-toggle {
+ color: var(--offwhite);
+ height: 100%;
+}
+
+.icon-toggle>* {
+ margin-top: 5px;
+}
+
+.icon-toggle:active {
+ background-color: var(--ns-primary);
+}
+
+.icon-toggle-on {
+ background-color: var(--ns-primary);
+}
+
+.icon-toggle-on>* {
+ transform: scale(1.3);
+}
+
+.force-link {
+ color: var(--offwhite) !important;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.text-primary {
+ color: var(--ns-primary) !important;
+}
+
+.btn-icon {
+ color: var(--offwhite) !important;
+ background-color: var(--ns-primary);
+ border-radius: 50%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ margin: 3px;
+ width: 28px;
+ height: 28px;
+}
+
+.bg-blur {
+ backdrop-filter: blur(2px);
+}
+
+.chart-wrapper {
+ width: 150px;
+ height: 150px;
+ margin: auto;
+}
+
+.close-button {
+ background-color: none;
+ color: white;
+ position: absolute;
+ top: 5px;
+ right: 5px;
+}
+
+input:-webkit-autofill,
+textarea:-webkit-autofill,
+select:-webkit-autofill {
+ -webkit-box-shadow: 0 0 0 1000px var(--ns-bg) inset !important;
+ -webkit-text-fill-color: var(--ns-accent) !important;
+}
+
+a {
+ color: var(--ns-accent) !important;
+} \ No newline at end of file
diff --git a/frontend/src/styles/layout.css b/frontend/src/styles/layout.css
new file mode 100644
index 00000000..c0af31c3
--- /dev/null
+++ b/frontend/src/styles/layout.css
@@ -0,0 +1,78 @@
+/*Mora da se ispravi za media kada je ekran premali pa se poredjaju u kolonu*/
+
+html,
+body {
+ height: 100%;
+}
+
+.align-items-view>*:first-child {
+ transform: perspective(100em) rotateY(25deg) translateZ(1em);
+}
+
+.align-items-view>* {
+ transform: perspective(100em) translateZ(-2em);
+}
+
+.align-items-view>*:last-child {
+ transform: perspective(100em) rotateY(-25deg) translateZ(1em);
+}
+
+.ns-row {
+ width: 98%;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ margin: 0;
+ padding: 0;
+}
+
+.ns-col {
+ flex-grow: 1;
+ padding: 2px;
+ margin-bottom: 0;
+ padding-bottom: 0;
+ flex-grow: 1;
+ flex-shrink: 0;
+ flex-basis: 50%;
+}
+
+@media screen and (min-width: 1200px) {
+ .ns-col {
+ flex-basis: 25%;
+ }
+}
+
+@media screen and (min-width: 1600px) {
+ .ns-col {
+ flex-basis: 12.5%;
+ width: 10%;
+ }
+}
+
+*/
+/*.break-1,
+.break-2 {
+ height: 1px;
+ width: 100%;
+}
+
+@media screen and (min-width: 1200px) {
+ .break-1 {
+ display: none;
+ }
+}
+
+@media screen and (min-width: 1600px) {
+ .break-2 {
+ display: none;
+ }
+}*/
+
+.center-center {
+ text-align: center;
+ margin-right: 10px;
+ padding-right: 10px;
+ padding-bottom: 15px;
+ font-size: 20px;
+ font-weight: 600;
+} \ No newline at end of file
diff --git a/frontend/src/styles/scrollbar.css b/frontend/src/styles/scrollbar.css
new file mode 100644
index 00000000..7fb79329
--- /dev/null
+++ b/frontend/src/styles/scrollbar.css
@@ -0,0 +1,28 @@
+/* width */
+
+::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+}
+
+
+/* Track */
+
+::-webkit-scrollbar-track {
+ background: rgba(0, 0, 0, 0);
+}
+
+
+/* Handle */
+
+::-webkit-scrollbar-thumb {
+ background: rgba(0, 188, 252, 0.6);
+ border-radius: 25px;
+}
+
+
+/* Handle on hover */
+
+::-webkit-scrollbar-thumb:hover {
+ background: rgba(0, 188, 252, 0.8);
+} \ No newline at end of file
diff --git a/frontend/src/styles/theme.css b/frontend/src/styles/theme.css
new file mode 100644
index 00000000..ee7a2e61
--- /dev/null
+++ b/frontend/src/styles/theme.css
@@ -0,0 +1,68 @@
+:root {
+ --ns-primary: #0063AB;
+ --ns-primary-25: rgba(0, 99, 171, 0.25);
+ --ns-primary-50: rgba(0, 99, 171, 0.5);
+ --ns-accent: #00a8e8;
+ --ns-bg: #003459;
+ --ns-bg-light-30: rgba(0, 152, 189, 0.3);
+ --ns-bg-dark-100: rgba(0, 65, 101, 1.0);
+ --ns-bg-dark-50: rgba(0, 65, 101, 0.5);
+ --offwhite: #dfd7d7;
+ --ns-warn: #f9b7b7;
+ --ns-alt: #002b49;
+}
+
+body {
+ /*background-image: url('/assets/images/add_model_background.jpg');*/
+ background-color: var(--ns-bg);
+}
+
+.bg-light {
+ background-color: var(--ns-bg-light-30) !important;
+}
+
+.bg-alt {
+ background-color: var(--ns-alt);
+}
+
+.ns-border-primary {
+ border: 1px solid var(--ns-primary);
+}
+
+.ns-bg-dark-50 {
+ background-color: var(--ns-bg-dark-50) !important;
+}
+
+.ns-bg-dark-100 {
+ background-color: var(--ns-bg-dark-100) !important;
+}
+
+a {
+ color: var(--ns-primary) !important;
+}
+
+.text-offwhite {
+ color: var(--offwhite) !important;
+}
+
+.highlight {
+ color: var(--ns-accent);
+}
+
+
+/* Ripple effect */
+
+.bubble {
+ background-position: center;
+ transition: background 0.2s;
+}
+
+.bubble:hover {
+ background: var(--ns-primary-50) radial-gradient(circle, transparent 1%, var(--ns-accent) 1%) center/15000%;
+}
+
+.bubble:active {
+ background-color: #6eb9f7;
+ background-size: 100%;
+ transition: background 0s;
+} \ No newline at end of file