aboutsummaryrefslogtreecommitdiff
path: root/frontend/src
diff options
context:
space:
mode:
authorDanijel Andjelkovic <adanijel99@gmail.com>2022-03-24 06:31:08 +0100
committerDanijel Andjelkovic <adanijel99@gmail.com>2022-03-24 06:31:08 +0100
commit042482a1bbd6ea3460acf3d71bfe3ef64b05524a (patch)
treee79413f97a8c9f97c978b5048ab89278ab0e6a41 /frontend/src
parent0aa45260963dbf0a52726f791c3813928a1bcebc (diff)
parent1113f094ffee030fd9892deb7577927419860013 (diff)
Merge branch 'dev' of http://gitlab.pmf.kg.ac.rs/igrannonica/neuronstellar into dev
# Conflicts: # frontend/src/app/app.module.ts
Diffstat (limited to 'frontend/src')
-rw-r--r--frontend/src/app/Shared.ts3
-rw-r--r--frontend/src/app/_data/ProfilePictures.ts63
-rw-r--r--frontend/src/app/_data/User.ts2
-rw-r--r--frontend/src/app/_elements/navbar/navbar.component.html2
-rw-r--r--frontend/src/app/_elements/navbar/navbar.component.ts6
-rw-r--r--frontend/src/app/_modals/register-modal/register-modal.component.ts6
-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.html39
-rw-r--r--frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts15
-rw-r--r--frontend/src/app/_pages/filter-datasets/filter-datasets.component.css0
-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/filter-datasets/filter-datasets.component.ts39
-rw-r--r--frontend/src/app/_pages/home/home.component.html1
-rw-r--r--frontend/src/app/_pages/my-models/my-models.component.html1
-rw-r--r--frontend/src/app/_pages/profile/profile.component.css8
-rw-r--r--frontend/src/app/_pages/profile/profile.component.html118
-rw-r--r--frontend/src/app/_pages/profile/profile.component.ts103
-rw-r--r--frontend/src/app/_services/auth.service.ts4
-rw-r--r--frontend/src/app/_services/datasets.service.spec.ts16
-rw-r--r--frontend/src/app/_services/datasets.service.ts24
-rw-r--r--frontend/src/app/_services/predictors.service.spec.ts16
-rw-r--r--frontend/src/app/_services/predictors.service.ts21
-rw-r--r--frontend/src/app/_services/user-info.service.ts12
-rw-r--r--frontend/src/app/_services/web-socket.service.ts2
-rw-r--r--frontend/src/app/app-routing.module.ts4
-rw-r--r--frontend/src/app/app.module.ts11
-rw-r--r--frontend/src/assets/profilePictures/1.pngbin0 -> 27411 bytes
-rw-r--r--frontend/src/assets/profilePictures/10.pngbin0 -> 42749 bytes
-rw-r--r--frontend/src/assets/profilePictures/11.pngbin0 -> 39817 bytes
-rw-r--r--frontend/src/assets/profilePictures/12.pngbin0 -> 22224 bytes
-rw-r--r--frontend/src/assets/profilePictures/13.pngbin0 -> 31624 bytes
-rw-r--r--frontend/src/assets/profilePictures/14.pngbin0 -> 30103 bytes
-rw-r--r--frontend/src/assets/profilePictures/2.pngbin0 -> 37797 bytes
-rw-r--r--frontend/src/assets/profilePictures/3.pngbin0 -> 37815 bytes
-rw-r--r--frontend/src/assets/profilePictures/4.pngbin0 -> 35414 bytes
-rw-r--r--frontend/src/assets/profilePictures/5.pngbin0 -> 37866 bytes
-rw-r--r--frontend/src/assets/profilePictures/6.pngbin0 -> 28790 bytes
-rw-r--r--frontend/src/assets/profilePictures/7.pngbin0 -> 47893 bytes
-rw-r--r--frontend/src/assets/profilePictures/8.pngbin0 -> 37226 bytes
-rw-r--r--frontend/src/assets/profilePictures/9.pngbin0 -> 25994 bytes
-rw-r--r--frontend/src/index.html6
42 files changed, 505 insertions, 87 deletions
diff --git a/frontend/src/app/Shared.ts b/frontend/src/app/Shared.ts
index 0adcd4d6..31afb1a6 100644
--- a/frontend/src/app/Shared.ts
+++ b/frontend/src/app/Shared.ts
@@ -1,7 +1,8 @@
class Shared {
constructor(
public loggedIn: boolean,
- public username: string = ''
+ public username: string = '',
+ public photoId: string = '1'
) { }
}
diff --git a/frontend/src/app/_data/ProfilePictures.ts b/frontend/src/app/_data/ProfilePictures.ts
new file mode 100644
index 00000000..217810d9
--- /dev/null
+++ b/frontend/src/app/_data/ProfilePictures.ts
@@ -0,0 +1,63 @@
+export class Picture {
+ photoId!: number;
+ path!: string;
+}
+
+export const PICTURES = [
+ {
+ photoId: 1,
+ path: "/assets/profilePictures/1.png"
+ },
+ {
+ photoId: 2,
+ path: "/assets/profilePictures/2.png"
+ },
+ {
+ photoId: 3,
+ path: "/assets/profilePictures/3.png"
+ },
+ {
+ photoId: 4,
+ path: "/assets/profilePictures/4.png"
+ },
+ {
+ photoId: 5,
+ path: "/assets/profilePictures/5.png"
+ },
+ {
+ photoId: 6,
+ path: "/assets/profilePictures/6.png"
+ },
+ {
+ photoId: 7,
+ path: "/assets/profilePictures/7.png"
+ },
+ {
+ photoId: 8,
+ path: "/assets/profilePictures/8.png"
+ },
+ {
+ photoId: 9,
+ path: "/assets/profilePictures/9.png"
+ },
+ {
+ photoId: 10,
+ path: "/assets/profilePictures/10.png"
+ },
+ {
+ photoId: 11,
+ path: "/assets/profilePictures/11.png"
+ },
+ {
+ photoId: 12,
+ path: "/assets/profilePictures/12.png"
+ },
+ {
+ photoId: 13,
+ path: "/assets/profilePictures/13.png"
+ },
+ {
+ photoId: 14,
+ path: "/assets/profilePictures/14.png"
+ }
+] \ No newline at end of file
diff --git a/frontend/src/app/_data/User.ts b/frontend/src/app/_data/User.ts
index 58383d38..be42ed0a 100644
--- a/frontend/src/app/_data/User.ts
+++ b/frontend/src/app/_data/User.ts
@@ -1,5 +1,5 @@
export default class User {
- _id: string = '';
+ _id?: string = '';
constructor(
public username: string = '',
public email: string = '',
diff --git a/frontend/src/app/_elements/navbar/navbar.component.html b/frontend/src/app/_elements/navbar/navbar.component.html
index 52e26e6b..82a1ea07 100644
--- a/frontend/src/app/_elements/navbar/navbar.component.html
+++ b/frontend/src/app/_elements/navbar/navbar.component.html
@@ -18,7 +18,7 @@
<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="https://github.com/mdo.png" alt="mdo" width="32" height="32" class="rounded-circle">
+ <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);"
diff --git a/frontend/src/app/_elements/navbar/navbar.component.ts b/frontend/src/app/_elements/navbar/navbar.component.ts
index c16e3e9d..5fd98c8f 100644
--- a/frontend/src/app/_elements/navbar/navbar.component.ts
+++ b/frontend/src/app/_elements/navbar/navbar.component.ts
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { AuthService } from '../../_services/auth.service';
import shared from 'src/app/Shared';
+import { UserInfoService } from 'src/app/_services/user-info.service';
@Component({
selector: 'app-navbar',
@@ -13,7 +14,7 @@ export class NavbarComponent implements OnInit {
currentUrl: string;
shared = shared;
- constructor(public location: Location, private auth: AuthService) {
+ constructor(public location: Location, private auth: AuthService, private userInfoService: UserInfoService) {
this.currentUrl = this.location.path();
this.location.onUrlChange(() => {
this.currentUrl = this.location.path();
@@ -22,6 +23,9 @@ export class NavbarComponent implements OnInit {
ngOnInit(): void {
this.auth.updateUser();
+ this.userInfoService.getUserInfo().subscribe((response) => {
+ shared.photoId = response.photoId;
+ });
}
logOut() {
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 c045f1ce..13ef7eba 100644
--- a/frontend/src/app/_modals/register-modal/register-modal.component.ts
+++ b/frontend/src/app/_modals/register-modal/register-modal.component.ts
@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { AuthService } from 'src/app/_services/auth.service';
+import User from 'src/app/_data/User';
@Component({
selector: 'app-register-modal',
@@ -124,12 +125,13 @@ export class RegisterModalComponent implements OnInit {
if (!(this.wrongFirstNameBool || this.wrongLastNameBool || this.wrongUsernameBool ||
this.wrongEmailBool || this.wrongPass1Bool || this.wrongPass2Bool)) { //sve ok, registruj ga
- let user = {
+ let user: User = {
firstName: this.firstName,
lastName: this.lastName,
username: this.username,
password: this.pass1,
- email: this.email
+ email: this.email,
+ photoId: "1"
}
this.authService.register(user)
diff --git a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.css b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.css
index e69de29b..b4ac9669 100644
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.css
+++ b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.css
@@ -0,0 +1,7 @@
+#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
index 01c4af82..a4ab6e2c 100644
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html
+++ b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html
@@ -1 +1,38 @@
-<p>browse-predictors works!</p>
+
+<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 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)">Otvori</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.ts b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
index b4fb2a9d..4f96fc36 100644
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
+++ b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
@@ -1,5 +1,7 @@
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',
@@ -7,9 +9,18 @@ import { Component, OnInit } from '@angular/core';
})
export class BrowsePredictorsComponent implements OnInit {
- constructor() { }
+ 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.navigateByUrl('/predict?id='+id);
+ };
}
diff --git a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.css b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.css
diff --git a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.html b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.html
new file mode 100644
index 00000000..84f5ebaf
--- /dev/null
+++ b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.html
@@ -0,0 +1,38 @@
+
+<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
new file mode 100644
index 00000000..6ab894fd
--- /dev/null
+++ b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.spec.ts
@@ -0,0 +1,25 @@
+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/filter-datasets/filter-datasets.component.ts b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts
new file mode 100644
index 00000000..bc13a51c
--- /dev/null
+++ b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts
@@ -0,0 +1,39 @@
+import { Component, OnInit } from '@angular/core';
+import { DatasetsService } from 'src/app/_services/datasets.service';
+import Dataset from 'src/app/_data/Dataset';
+import {Router} from '@angular/router'
+import { JwtHelperService } from '@auth0/angular-jwt';
+import { CookieService } from 'ngx-cookie-service';
+
+@Component({
+ selector: 'app-filter-datasets',
+ templateUrl: './filter-datasets.component.html',
+ styleUrls: ['./filter-datasets.component.css']
+})
+export class FilterDatasetsComponent implements OnInit {
+
+ publicDatasets?: Dataset[];
+ term: string = "";
+ constructor(private datasets: DatasetsService,private router:Router, private cookie: CookieService) {
+ this.datasets.getPublicDatasets().subscribe((datasets) => {
+ this.publicDatasets = datasets;
+ });
+ }
+
+ ngOnInit(): void {
+
+ }
+ addDataset(dataset: Dataset):void{
+ //this.router.navigateByUrl('/predict?id='+id);
+ const helper = new JwtHelperService();
+ const decodedToken = helper.decodeToken(this.cookie.get("token"));
+ dataset._id = "";
+ dataset.isPublic = false;
+ dataset.lastUpdated = new Date();
+ dataset.username = decodedToken.name;
+ this.datasets.addDataset(dataset).subscribe((response:string)=>{
+ console.log(response);
+ });
+ };
+
+}
diff --git a/frontend/src/app/_pages/home/home.component.html b/frontend/src/app/_pages/home/home.component.html
index 274f0fd8..689a302b 100644
--- a/frontend/src/app/_pages/home/home.component.html
+++ b/frontend/src/app/_pages/home/home.component.html
@@ -46,6 +46,7 @@
</div>
<h2 class="my-4">Pogledajte javne izvore podataka!</h2>
<app-carousel [items]="publicDatasets">
+
</app-carousel>
<h3><a routerLink="browse-datasets">Pogledaj sve javne izvore podataka...</a></h3>
<h2 class="my-4">Iskoristite već trenirane modele!</h2>
diff --git a/frontend/src/app/_pages/my-models/my-models.component.html b/frontend/src/app/_pages/my-models/my-models.component.html
index 2fea257d..e69de29b 100644
--- a/frontend/src/app/_pages/my-models/my-models.component.html
+++ b/frontend/src/app/_pages/my-models/my-models.component.html
@@ -1 +0,0 @@
-<p>my-models works!</p>
diff --git a/frontend/src/app/_pages/profile/profile.component.css b/frontend/src/app/_pages/profile/profile.component.css
index 8c2ffa88..5565d105 100644
--- a/frontend/src/app/_pages/profile/profile.component.css
+++ b/frontend/src/app/_pages/profile/profile.component.css
@@ -4,13 +4,11 @@ color:#69707a;
}
.img-account-profile {
height: 10rem;
+ border: 1px solid lightgray;
}
.rounded-circle {
border-radius: 50% !important;
}
-.card {
- box-shadow: 0 0.15rem 1.75rem 0 rgb(33 40 50 / 15%);
-}
.card .card-header {
font-weight: 500;
}
@@ -40,3 +38,7 @@ color:#69707a;
border-radius: 0.35rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
+
+.selectedPicture {
+ border: 2px solid darkgray;
+}
diff --git a/frontend/src/app/_pages/profile/profile.component.html b/frontend/src/app/_pages/profile/profile.component.html
index bece7c46..d082a003 100644
--- a/frontend/src/app/_pages/profile/profile.component.html
+++ b/frontend/src/app/_pages/profile/profile.component.html
@@ -1,4 +1,4 @@
-<div class="container-xl px-4 mt-4">
+<div class="container-xl px-4 mt-1">
<hr class="mt-0 mb-4">
<div class="row">
@@ -7,15 +7,60 @@
<div class="card mb-4 mb-xl-0">
<div class="card-header">Moj profil</div>
<div class="card-body text-center">
- <!-- Profile picture image-->
- <img class="img-account-profile rounded-circle mb-2" src="http://bootdey.com/img/Content/avatar/avatar1.png" alt="">
- <!-- Profile picture help block-->
- <div class="small font-italic text-muted mb-4">JPG or PNG no larger than 5 MB</div>
- <!-- Profile picture upload button-->
- <button class="btn btn-primary" type="button">Upload new image</button>
+ <div class=" image d-flex flex-column justify-content-center align-items-center">
+ <!-- Profile picture image-->
+ <img class="img-account-profile rounded-circle mb-2" src="{{this.photoPath}}" alt="profilePicture">
+ <!-- User's info -->
+ <span>@ {{this.user.username}}</span>
+ <span class="mt-3" style="font-weight: bold;">{{this.user.firstName}} {{this.user.lastName}}</span>
+ </div>
+ </div>
+ </div>
+
+ <!-- Password Change card -->
+ <div class="card mt-3">
+ <div class="card-header">Promena lozinke</div>
+ <div class="card-body">
+ <form>
+ <div class="row">
+ <!-- Form Row-->
+ <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>
+ </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>
+ </div>
+ </div>
+
+ <!-- Form Row-->
+ <div class="row gx-3 mb-3">
+ <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>
+ </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>
+ </div>
+ </div>
+ </div>
+ </form>
</div>
</div>
</div>
+
+ <!-- Info Change card -->
<div class="col-xl-8">
<!-- Account details card-->
<div class="card mb-4">
@@ -49,6 +94,22 @@
<input class="form-control" id="inputLastName" name="inputLastName" type="text" [(ngModel)]="this.lastName">
</div>
</div>
+
+ <div>
+ <label class="small mt-2 mb-3">Kliknite na sliku kako biste je odabrali za profilnu:</label>
+
+ <div class="container">
+ <div class="card-group">
+ <!--bootstrap card with 3 horizontal images-->
+ <div class="row overflow-auto" style="max-height: 200px;">
+ <div class="card col-md-3" *ngFor="let picture of this.pictures" (click)="this.photoId = picture.photoId.toString()"
+ [ngClass]="{'selectedPicture': this.photoId == picture.photoId.toString()}">
+ <img src="{{picture.path}}">
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
<div class="row mt-5">
<div class="col text-center">
@@ -65,48 +126,7 @@
<div class="row">
<div class="col-xl-4">
- <div class="card mb-4">
- <div class="card-header">Promena lozinke</div>
- <div class="card-body">
- <form>
-
- <div class="row">
- <!-- Form Row-->
- <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>
- </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>
- </div>
- </div>
-
- <!-- Form Row-->
- <div class="row gx-3 mb-3">
- <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>
- </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>
- </div>
- </div>
- </div>
-
- </form>
- </div>
- </div>
+
</div>
</div>
diff --git a/frontend/src/app/_pages/profile/profile.component.ts b/frontend/src/app/_pages/profile/profile.component.ts
index 4b474678..3e9a0d11 100644
--- a/frontend/src/app/_pages/profile/profile.component.ts
+++ b/frontend/src/app/_pages/profile/profile.component.ts
@@ -1,6 +1,12 @@
import { Component, OnInit } from '@angular/core';
import User from 'src/app/_data/User';
import { UserInfoService } from 'src/app/_services/user-info.service';
+import { AuthService } from 'src/app/_services/auth.service';
+import { Router } from '@angular/router';
+import { PICTURES } from 'src/app/_data/ProfilePictures';
+import { Picture } from 'src/app/_data/ProfilePictures';
+import shared from '../../Shared';
+
@Component({
selector: 'app-profile',
@@ -10,6 +16,7 @@ import { UserInfoService } from 'src/app/_services/user-info.service';
export class ProfileComponent implements OnInit {
user: User = new User();
+ pictures: Picture[] = PICTURES;
username: string = '';
email: string = '';
@@ -19,24 +26,46 @@ export class ProfileComponent implements OnInit {
newPass1: string = '';
newPass2: string = '';
photoId: string = '';
+ photoPath: string = '';
wrongPassBool: boolean = false;
wrongNewPassBool: boolean = false;
- constructor(private userInfoService: UserInfoService) { }
+ wrongFirstNameBool: boolean = false;
+ wrongLastNameBool: boolean = false;
+ wrongUsernameBool: boolean = false;
+ wrongEmailBool: boolean = false;
+ wrongOldPassBool: boolean = false;
+ wrongNewPass1Bool: boolean = false;
+ wrongNewPass2Bool: boolean = false;
+
+ pattName: RegExp = /^[a-zA-ZšŠđĐčČćĆžŽ]+([ \-][a-zA-ZšŠđĐčČćĆžŽ]+)*$/;
+ pattUsername: RegExp = /^[a-zA-Z0-9]{6,18}$/;
+ pattTwoSpaces: RegExp = / /;
+ pattEmail: RegExp = /^[a-zA-Z0-9]+([\.\-\+][a-zA-Z0-9]+)*\@([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}$/;
+ pattPassword: RegExp = /.{6,30}$/;
+
+
+ constructor(private userInfoService: UserInfoService, private authService: AuthService, private router: Router) { }
ngOnInit(): void {
- this.userInfoService.getUsersInfo().subscribe((response) => {
+ this.userInfoService.getUserInfo().subscribe((response) => {
this.user = response;
-
- this.user.password = 'sonja123';
+ shared.photoId = this.user.photoId;
this.username = this.user.username;
this.email = this.user.email;
this.firstName = this.user.firstName;
this.lastName = this.user.lastName;
this.photoId = this.user.photoId;
+
+ for (let i = 0; i < this.pictures.length; i++) {
+ if (this.pictures[i].photoId.toString() === this.photoId) {
+ this.photoPath = this.pictures[i].path;
+ break;
+ }
+ }
console.log(this.user);
});
}
@@ -49,14 +78,27 @@ export class ProfileComponent implements OnInit {
password: this.user.password,
firstName: this.firstName,
lastName: this.lastName,
- photoId: "1"
+ photoId: this.photoId
}
this.userInfoService.changeUserInfo(editedUser).subscribe((response: any) =>{
+ if (this.user.username != editedUser.username) { //promenio username, ide logout
+ this.user = editedUser;
+ alert("Nakon promene korisničkog imena, moraćete ponovo da se ulogujete.");
+ this.authService.logOut();
+ this.router.navigate(['']);
+ return;
+ }
this.user = editedUser;
console.log(this.user);
+ this.resetInfo();
}, (error: any) =>{
- console.log(error);
+ if (error.error == "Username already exists!") {
+ alert("Ukucano korisničko ime je već zauzeto!\nIzaberite neko drugo.");
+ (<HTMLSelectElement>document.getElementById("inputUsername")).focus();
+ //poruka obavestenja ispod inputa
+ this.resetInfo();
+ }
});
}
@@ -64,10 +106,10 @@ export class ProfileComponent implements OnInit {
if (this.newPass1 == '' && this.newPass2 == '') //ne zeli da promeni lozinku
return;
console.log("zeli da promeni lozinku");
+
if (this.newPass1 != this.newPass2) { //netacno ponovio novu lozinku
this.wrongNewPassBool = true;
- this.newPass1 = '';
- this.newPass2 = '';
+ this.resetNewPassInputs();
console.log("Netacno ponovljena lozinka");
return;
}
@@ -75,12 +117,49 @@ export class ProfileComponent implements OnInit {
this.wrongPassBool = false;
this.wrongNewPassBool = false;
- this.userInfoService.changeUserPassword(this.oldPass, this.newPass1).subscribe((response) => {
- this.user = response;
- console.log(this.user);
+ let passwordArray: string[] = [this.oldPass, this.newPass1];
+ this.userInfoService.changeUserPassword(passwordArray).subscribe((response: any) => {
+ console.log("PROMENIO LOZINKU");
+ this.resetNewPassInputs();
+ alert("Nakon promene lozinke, moraćete ponovo da se ulogujete.");
+ this.authService.logOut();
+ this.router.navigate(['']);
}, (error: any) => {
-
+ console.log("error poruka: ", error.error);
+ if (error.error == 'Wrong old password!') {
+ this.wrongPassBool = true;
+ (<HTMLSelectElement>document.getElementById("inputPassword")).focus();
+ return;
+ }
+ else if (error.error == 'Identical password!') {
+ alert("Stara i nova lozinka su identične.");
+ this.resetNewPassInputs();
+ (<HTMLSelectElement>document.getElementById("inputNewPassword")).focus();
+ return;
+ }
});
}
+ resetNewPassInputs() {
+ this.newPass1 = '';
+ this.newPass2 = '';
+ }
+
+ resetInfo() {
+ this.username = this.user.username;
+ this.email = this.user.email;
+ this.firstName = this.user.firstName;
+ this.lastName = this.user.lastName;
+ this.photoId = this.user.photoId;
+
+ for (let i = 0; i < this.pictures.length; i++) {
+ if (this.pictures[i].photoId.toString() === this.photoId) {
+ this.photoPath = this.pictures[i].path;
+ break;
+ }
+ }
+ shared.photoId = this.photoId;
+ }
+
+
}
diff --git a/frontend/src/app/_services/auth.service.ts b/frontend/src/app/_services/auth.service.ts
index 20ff45f3..449b8802 100644
--- a/frontend/src/app/_services/auth.service.ts
+++ b/frontend/src/app/_services/auth.service.ts
@@ -61,8 +61,10 @@ export class AuthService {
updateUser() {
if (this.cookie.check('token')) {
const token = this.cookie.get('token');
+ const decodedToken = jwtHelper.decodeToken(token);
+ console.log("decoded:", decodedToken);
this.shared.loggedIn = this.isAuthenticated();
- this.shared.username = jwtHelper.decodeToken(token).name;
+ this.shared.username = decodedToken.name;
this.enableAutoRefresh();
}
}
diff --git a/frontend/src/app/_services/datasets.service.spec.ts b/frontend/src/app/_services/datasets.service.spec.ts
new file mode 100644
index 00000000..87b46acd
--- /dev/null
+++ b/frontend/src/app/_services/datasets.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { DatasetsService } from './datasets.service';
+
+describe('DatasetsService', () => {
+ let service: DatasetsService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(DatasetsService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_services/datasets.service.ts b/frontend/src/app/_services/datasets.service.ts
new file mode 100644
index 00000000..fadcdeae
--- /dev/null
+++ b/frontend/src/app/_services/datasets.service.ts
@@ -0,0 +1,24 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { API_SETTINGS } from 'src/config';
+import Dataset from '../_data/Dataset';
+import { AuthService } from './auth.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DatasetsService {
+
+ constructor(private http: HttpClient, private authService: AuthService) { }
+
+ getPublicDatasets(): Observable<Dataset[]> {
+ return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/Dataset/publicdatasets`, { headers: this.authService.authHeader() });
+ }
+
+ addDataset(dataset:Dataset):any{
+ return this.http.post(`${API_SETTINGS.apiURL}/dataset/add`, dataset, { headers: this.authService.authHeader() });
+ }
+
+
+}
diff --git a/frontend/src/app/_services/predictors.service.spec.ts b/frontend/src/app/_services/predictors.service.spec.ts
new file mode 100644
index 00000000..7733780b
--- /dev/null
+++ b/frontend/src/app/_services/predictors.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { PredictorsService } from './predictors.service';
+
+describe('PredictorsService', () => {
+ let service: PredictorsService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(PredictorsService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_services/predictors.service.ts b/frontend/src/app/_services/predictors.service.ts
new file mode 100644
index 00000000..0cd7f0f6
--- /dev/null
+++ b/frontend/src/app/_services/predictors.service.ts
@@ -0,0 +1,21 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { API_SETTINGS } from 'src/config';
+import Predictor from '../_data/Predictor';
+import { AuthService } from './auth.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class PredictorsService {
+
+
+
+ constructor(private http: HttpClient, private authService: AuthService) { }
+
+ getPublicPredictors(): Observable<Predictor[]> {
+ return this.http.get<Predictor[]>(`${API_SETTINGS.apiURL}/Predictor/publicpredictors`, { headers: this.authService.authHeader() });
+ }
+
+}
diff --git a/frontend/src/app/_services/user-info.service.ts b/frontend/src/app/_services/user-info.service.ts
index b66a73e1..7ed2970c 100644
--- a/frontend/src/app/_services/user-info.service.ts
+++ b/frontend/src/app/_services/user-info.service.ts
@@ -12,15 +12,19 @@ export class UserInfoService {
constructor(private http: HttpClient, private authService: AuthService) { }
- getUsersInfo(): Observable<User> {
+ getUserInfo(): Observable<User> {
return this.http.get<User>(`${API_SETTINGS.apiURL}/user/myprofile`, { headers: this.authService.authHeader() });
}
changeUserInfo(user: User): any {
- return this.http.put(`${API_SETTINGS.apiURL}/user/${user._id}`, user, { headers: this.authService.authHeader() });
+ return this.http.put(`${API_SETTINGS.apiURL}/user/changeinfo`, user, { headers: this.authService.authHeader() });
}
- changeUserPassword(oldPassword: string, newPassword: string): Observable<User> {
- return this.http.put<User>(`${API_SETTINGS.apiURL}/user/`, { oldPassword, newPassword }, { headers: this.authService.authHeader() });
+ changeUserPassword(passwordArray: string[]): any {
+ return this.http.put(`${API_SETTINGS.apiURL}/user/changepass`, passwordArray, { headers: this.authService.authHeader(), responseType: 'text' });
+ }
+
+ deleteUser(): any {
+ return this.http.delete(`${API_SETTINGS.apiURL}/user/deleteprofile`, { headers: this.authService.authHeader() });
}
}
diff --git a/frontend/src/app/_services/web-socket.service.ts b/frontend/src/app/_services/web-socket.service.ts
index fc292a62..890ada6b 100644
--- a/frontend/src/app/_services/web-socket.service.ts
+++ b/frontend/src/app/_services/web-socket.service.ts
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
+import { ConstantBackoff, Websocket, WebsocketBuilder } from 'websocket-ts';
import { API_SETTINGS } from 'src/config';
-import { ConstantBackoff, Websocket, WebsocketBuilder } from 'websocket-ts/lib';
@Injectable({
providedIn: 'root'
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index 001d0b4f..a52d66a8 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -12,6 +12,7 @@ import { BrowseDatasetsComponent } from './_pages/browse-datasets/browse-dataset
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';
const routes: Routes = [
{ path: '', component: HomeComponent, data: { title: 'Početna strana' } },
@@ -23,7 +24,8 @@ const routes: Routes = [
{ path: 'profile', component: ProfileComponent, canActivate: [AuthGuardService], data: { title: 'Profil' } },
{ path: 'browse-datasets', component: BrowseDatasetsComponent, data: { title: 'Javni izvori podataka' } },
{ path: 'browse-predictors', component: BrowsePredictorsComponent, data: { title: 'Javni trenirani modeli' } },
- { path: 'predict', component: PredictComponent, data: { title: 'Predvidi vrednosti' } }
+ { path: 'predict', component: PredictComponent, data: { title: 'Predvidi vrednosti' } },
+ { path: 'filter-datasets', component: FilterDatasetsComponent, data: { title: 'Filter datasets' } }
];
@NgModule({
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index 3387de8c..4612e3a7 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -6,8 +6,8 @@ import { HttpClientModule } from '@angular/common/http';
import { MatSliderModule } from '@angular/material/slider';
import { MatIconModule } from '@angular/material/icon';
-import {NgChartsModule} from 'ng2-charts';
-
+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';
@@ -35,6 +35,7 @@ import { ScatterchartComponent } from './scatterchart/scatterchart.component';
import { BarchartComponent } from './barchart/barchart.component';
import { NotificationsComponent } from './_elements/notifications/notifications.component';
import { DatatableComponent } from './_elements/datatable/datatable.component';
+import { FilterDatasetsComponent } from './_pages/filter-datasets/filter-datasets.component';
@NgModule({
declarations: [
@@ -59,7 +60,8 @@ import { DatatableComponent } from './_elements/datatable/datatable.component';
ScatterchartComponent,
BarchartComponent,
NotificationsComponent,
- DatatableComponent
+ DatatableComponent,
+ FilterDatasetsComponent
],
imports: [
BrowserModule,
@@ -72,7 +74,8 @@ import { DatatableComponent } from './_elements/datatable/datatable.component';
ReactiveFormsModule,
MatSliderModule,
MatIconModule,
- NgChartsModule
+ NgChartsModule,
+ Ng2SearchPipeModule
],
providers: [],
bootstrap: [AppComponent]
diff --git a/frontend/src/assets/profilePictures/1.png b/frontend/src/assets/profilePictures/1.png
new file mode 100644
index 00000000..6e2f8b73
--- /dev/null
+++ b/frontend/src/assets/profilePictures/1.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/10.png b/frontend/src/assets/profilePictures/10.png
new file mode 100644
index 00000000..cbd270ca
--- /dev/null
+++ b/frontend/src/assets/profilePictures/10.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/11.png b/frontend/src/assets/profilePictures/11.png
new file mode 100644
index 00000000..982fdae4
--- /dev/null
+++ b/frontend/src/assets/profilePictures/11.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/12.png b/frontend/src/assets/profilePictures/12.png
new file mode 100644
index 00000000..2aedbdb0
--- /dev/null
+++ b/frontend/src/assets/profilePictures/12.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/13.png b/frontend/src/assets/profilePictures/13.png
new file mode 100644
index 00000000..f8d771d9
--- /dev/null
+++ b/frontend/src/assets/profilePictures/13.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/14.png b/frontend/src/assets/profilePictures/14.png
new file mode 100644
index 00000000..d3ec8ae1
--- /dev/null
+++ b/frontend/src/assets/profilePictures/14.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/2.png b/frontend/src/assets/profilePictures/2.png
new file mode 100644
index 00000000..d8dc7967
--- /dev/null
+++ b/frontend/src/assets/profilePictures/2.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/3.png b/frontend/src/assets/profilePictures/3.png
new file mode 100644
index 00000000..b4219c22
--- /dev/null
+++ b/frontend/src/assets/profilePictures/3.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/4.png b/frontend/src/assets/profilePictures/4.png
new file mode 100644
index 00000000..ef0701ef
--- /dev/null
+++ b/frontend/src/assets/profilePictures/4.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/5.png b/frontend/src/assets/profilePictures/5.png
new file mode 100644
index 00000000..8523f582
--- /dev/null
+++ b/frontend/src/assets/profilePictures/5.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/6.png b/frontend/src/assets/profilePictures/6.png
new file mode 100644
index 00000000..96540607
--- /dev/null
+++ b/frontend/src/assets/profilePictures/6.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/7.png b/frontend/src/assets/profilePictures/7.png
new file mode 100644
index 00000000..f0557738
--- /dev/null
+++ b/frontend/src/assets/profilePictures/7.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/8.png b/frontend/src/assets/profilePictures/8.png
new file mode 100644
index 00000000..835ba0ab
--- /dev/null
+++ b/frontend/src/assets/profilePictures/8.png
Binary files differ
diff --git a/frontend/src/assets/profilePictures/9.png b/frontend/src/assets/profilePictures/9.png
new file mode 100644
index 00000000..fd38fac4
--- /dev/null
+++ b/frontend/src/assets/profilePictures/9.png
Binary files differ
diff --git a/frontend/src/index.html b/frontend/src/index.html
index 0079969e..1461c9ae 100644
--- a/frontend/src/index.html
+++ b/frontend/src/index.html
@@ -1,5 +1,6 @@
<!doctype html>
<html lang="en">
+
<head>
<meta charset="utf-8">
<title>Frontend</title>
@@ -10,8 +11,9 @@
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
+
<body class="mat-typography">
<app-root></app-root>
- <script src="node_modules/chart.js/src/chart.js"></script>
</body>
-</html>
+
+</html> \ No newline at end of file