diff options
Diffstat (limited to 'frontend/src/app')
34 files changed, 555 insertions, 85 deletions
diff --git a/frontend/src/app/Shared.ts b/frontend/src/app/Shared.ts new file mode 100644 index 00000000..126dc846 --- /dev/null +++ b/frontend/src/app/Shared.ts @@ -0,0 +1,7 @@ +class Shared { + constructor( + public loggedIn: boolean + ) { } +} + +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 new file mode 100644 index 00000000..aaee50eb --- /dev/null +++ b/frontend/src/app/_data/Dataset.ts @@ -0,0 +1,13 @@ +export default class Dataset { + constructor( + public 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() + ) { } +}
\ No newline at end of file diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts index 216e1c36..1a120ca7 100644 --- a/frontend/src/app/_data/Model.ts +++ b/frontend/src/app/_data/Model.ts @@ -3,11 +3,13 @@ export default class Model { public name: string = 'Novi model', public description: string = '', public dateCreated: Date = new Date(), + public lastUpdated: Date = new Date(), public datasetId?: number, - //Test set settings + // Test set settings public inputColumns: number[] = [0], public columnToPredict: number = 1, + public randomOrder: boolean = true, public randomTestSet: boolean = true, public randomTestSetDistribution: number = 0.10, //0.1-0.9 (10% - 90%) @@ -31,6 +33,8 @@ export enum ANNType { Convolutional = 'konvoluciona' } +// replaceMissing srednja vrednost mean, median, najcesca vrednost (mode) +// removeOutliers export enum Encoding { Label = 'label', OneHot = 'one hot' diff --git a/frontend/src/app/_data/Predictor.ts b/frontend/src/app/_data/Predictor.ts new file mode 100644 index 00000000..77d9498b --- /dev/null +++ b/frontend/src/app/_data/Predictor.ts @@ -0,0 +1,10 @@ +export default class Dataset { + constructor( + public name: string = 'Novi izvor podataka', + public description: string = '', + public columns: string[] = [], + public isPublic: boolean = false, + public accessibleByLink: boolean = false, + public dateCreated: Date = new Date() + ) { } +}
\ No newline at end of file diff --git a/frontend/src/app/_elements/carousel/carousel.component.css b/frontend/src/app/_elements/carousel/carousel.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_elements/carousel/carousel.component.css diff --git a/frontend/src/app/_elements/carousel/carousel.component.html b/frontend/src/app/_elements/carousel/carousel.component.html new file mode 100644 index 00000000..ea522626 --- /dev/null +++ b/frontend/src/app/_elements/carousel/carousel.component.html @@ -0,0 +1,12 @@ +<div class="d-flex flex-row"> + <div class="mx-2" *ngFor="let item of items" [ngSwitch]="item.constructor.name"> + <ng-template ngSwitchCase="Dataset"> + <app-item-dataset [dataset]="item"> + </app-item-dataset> + </ng-template> + <ng-template ngSwitchCase="Predictor"> + <app-item-predictor> + </app-item-predictor> + </ng-template> + </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/carousel/carousel.component.spec.ts new file mode 100644 index 00000000..9196e044 --- /dev/null +++ b/frontend/src/app/_elements/carousel/carousel.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CarouselComponent } from './carousel.component'; + +describe('CarouselComponent', () => { + let component: CarouselComponent; + let fixture: ComponentFixture<CarouselComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ CarouselComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CarouselComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_elements/carousel/carousel.component.ts b/frontend/src/app/_elements/carousel/carousel.component.ts new file mode 100644 index 00000000..ed4fa4a5 --- /dev/null +++ b/frontend/src/app/_elements/carousel/carousel.component.ts @@ -0,0 +1,17 @@ +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[] = []; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.css b/frontend/src/app/_elements/item-dataset/item-dataset.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_elements/item-dataset/item-dataset.component.css diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.html b/frontend/src/app/_elements/item-dataset/item-dataset.component.html new file mode 100644 index 00000000..c1dc2609 --- /dev/null +++ b/frontend/src/app/_elements/item-dataset/item-dataset.component.html @@ -0,0 +1,15 @@ +<div class="card" style="width: 18rem;"> + <div class="card-header"> + {{dataset.name}} + </div> + <div class="card-body"> + <p class="card-text"> + {{dataset.description}} + </p> + <table class="table table-bordered table-sm"> + <thead> + <th scope="col" *ngFor="let column of dataset.header">{{column}}</th> + </thead> + </table> + </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/item-dataset/item-dataset.component.spec.ts new file mode 100644 index 00000000..603889b2 --- /dev/null +++ b/frontend/src/app/_elements/item-dataset/item-dataset.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemDatasetComponent } from './item-dataset.component'; + +describe('ItemDatasetComponent', () => { + let component: ItemDatasetComponent; + let fixture: ComponentFixture<ItemDatasetComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ItemDatasetComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemDatasetComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.ts b/frontend/src/app/_elements/item-dataset/item-dataset.component.ts new file mode 100644 index 00000000..e12de34d --- /dev/null +++ b/frontend/src/app/_elements/item-dataset/item-dataset.component.ts @@ -0,0 +1,15 @@ +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(); + + constructor() { + } +} diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.css b/frontend/src/app/_elements/item-predictor/item-predictor.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_elements/item-predictor/item-predictor.component.css diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.html b/frontend/src/app/_elements/item-predictor/item-predictor.component.html new file mode 100644 index 00000000..cbd53fc2 --- /dev/null +++ b/frontend/src/app/_elements/item-predictor/item-predictor.component.html @@ -0,0 +1 @@ +<p>item-predictor works!</p> diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.spec.ts b/frontend/src/app/_elements/item-predictor/item-predictor.component.spec.ts new file mode 100644 index 00000000..b5c2d91c --- /dev/null +++ b/frontend/src/app/_elements/item-predictor/item-predictor.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemPredictorComponent } from './item-predictor.component'; + +describe('ItemPredictorComponent', () => { + let component: ItemPredictorComponent; + let fixture: ComponentFixture<ItemPredictorComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ItemPredictorComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemPredictorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.ts b/frontend/src/app/_elements/item-predictor/item-predictor.component.ts new file mode 100644 index 00000000..fe65ccfd --- /dev/null +++ b/frontend/src/app/_elements/item-predictor/item-predictor.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-item-predictor', + templateUrl: './item-predictor.component.html', + styleUrls: ['./item-predictor.component.css'] +}) +export class ItemPredictorComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/src/app/_elements/navbar/navbar.component.css b/frontend/src/app/_elements/navbar/navbar.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_elements/navbar/navbar.component.css diff --git a/frontend/src/app/_elements/navbar/navbar.component.html b/frontend/src/app/_elements/navbar/navbar.component.html new file mode 100644 index 00000000..cea41e5a --- /dev/null +++ b/frontend/src/app/_elements/navbar/navbar.component.html @@ -0,0 +1,50 @@ +<header class="sticky-top p-3 bg-dark text-white"> + <div class="container"> + <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start"> + <a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none"> + <svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap"> + <use xlink:href="#bootstrap"></use> + </svg> + </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="add-model" class="nav-link px-2" + [class]="(currentUrl === '/add-model') ? 'text-secondary' : 'text-white'">Dodaj model</a></li> + <li><a routerLink="predict" class="nav-link px-2" + [class]="(currentUrl === '/predict') ? 'text-secondary' : 'text-white'">Predvidi</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="https://github.com/mdo.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" href="#">Nov model...</a></li> + <li><a class="dropdown-item" href="#">Podešavanja</a></li> + <li><a class="dropdown-item" href="#">Moj profil</a></li> + <li> + <hr class="dropdown-divider"> + </li> + <li><a class="dropdown-item" (click)="logOut()">Odjavi se</a></li> + </ul> + </div> + <div *ngIf="!shared.loggedIn" class="dropdown text-end"> + <button type="button" class="btn btn-primary mx-2" data-bs-toggle="modal" + data-bs-target="#modalForLogin"> + Prijavi se + </button> + <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalForRegister"> + Registruj se + </button> + </div> + </div> + </div> +</header> + +<app-login-modal></app-login-modal> +<app-register-modal></app-register-modal>
\ No newline at end of file diff --git a/frontend/src/app/_elements/navbar/navbar.component.spec.ts b/frontend/src/app/_elements/navbar/navbar.component.spec.ts new file mode 100644 index 00000000..f8ccd6f4 --- /dev/null +++ b/frontend/src/app/_elements/navbar/navbar.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NavbarComponent } from './navbar.component'; + +describe('NavbarComponent', () => { + let component: NavbarComponent; + let fixture: ComponentFixture<NavbarComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ NavbarComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NavbarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_elements/navbar/navbar.component.ts b/frontend/src/app/_elements/navbar/navbar.component.ts new file mode 100644 index 00000000..c16e3e9d --- /dev/null +++ b/frontend/src/app/_elements/navbar/navbar.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit } from '@angular/core'; +import { Location } from '@angular/common'; +import { AuthService } from '../../_services/auth.service'; +import shared from 'src/app/Shared'; + +@Component({ + selector: 'app-navbar', + templateUrl: './navbar.component.html', + styleUrls: ['./navbar.component.css'] +}) +export class NavbarComponent implements OnInit { + + currentUrl: string; + shared = shared; + + constructor(public location: Location, private auth: AuthService) { + this.currentUrl = this.location.path(); + this.location.onUrlChange(() => { + this.currentUrl = this.location.path(); + }) + } + + ngOnInit(): void { + this.auth.updateUser(); + } + + logOut() { + this.auth.logOut(); + } +} 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 22bd9a28..87686f10 100644 --- a/frontend/src/app/_modals/login-modal/login-modal.component.ts +++ b/frontend/src/app/_modals/login-modal/login-modal.component.ts @@ -27,9 +27,8 @@ export class LoginModalComponent implements OnInit { doLogin() { this.authService.login(this.username, this.password).subscribe((response) => { //ako nisu ok podaci, ne ide hide nego mora opet da ukucava!!!!podesi console.log(response); - this.cookie.set('token', response); + this.authService.authenticate(response); (<HTMLSelectElement>document.getElementById('closeButton')).click(); - this.router.navigate(['add-model']); }, error => { console.warn(error); //NETACNI PODACI }); 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 7ed2bbac..7098c040 100644 --- a/frontend/src/app/_modals/register-modal/register-modal.component.html +++ b/frontend/src/app/_modals/register-modal/register-modal.component.html @@ -1,70 +1,88 @@ <!-- 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 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 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 type="button" class="btn-close" data-bs-dismiss="modal" style="background-color: white;" + aria-label="Close" (click)="resetData()"></button> </div> - <div class="row"> - <!--Korisnicko ime--> - <div class="col-12 px-3 py-3"> - <label class="form-label" for="username">Korisničko ime</label> - <input type="text" id="username" class="form-control" [(ngModel)]="username" name="username" placeholder="Unesite korisničko ime..."/> - <small *ngIf="wrongUsernameBool" class="form-text text-danger">Unesite ispravno korisničko ime.</small> + <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> + <br> </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 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> + </p> </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> - <br> - </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> - </p> - </div> </div> -</div> </div>
\ No newline at end of file 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 688fc806..c02a4e1a 100644 --- a/frontend/src/app/_modals/register-modal/register-modal.component.ts +++ b/frontend/src/app/_modals/register-modal/register-modal.component.ts @@ -48,7 +48,7 @@ export class RegisterModalComponent implements OnInit { return true; return false; } - isCorrectUsername(element: string) : boolean { + isCorrectUsername(element: string): boolean { if (this.pattUsername.test(element) && !(this.pattTwoSpaces.test(element)) && (element.length >= 1 && element.length <= 30)) return true; return false; @@ -85,7 +85,7 @@ export class RegisterModalComponent implements OnInit { this.wrongUsernameBool = false; return; } - (<HTMLSelectElement>document.getElementById('username')).focus(); + (<HTMLSelectElement>document.getElementById('username-register')).focus(); this.wrongUsernameBool = true; } emailValidation() { @@ -146,7 +146,7 @@ export class RegisterModalComponent implements OnInit { } else if (response === 'Username Already Exists') { alert('Nalog sa unetim korisničkim imenom već postoji!'); - (<HTMLSelectElement>document.getElementById('username')).focus(); + (<HTMLSelectElement>document.getElementById('username-register')).focus(); } } ); diff --git a/frontend/src/app/_pages/add-model/add-model.component.html b/frontend/src/app/_pages/add-model/add-model.component.html index bc292bb9..08e27dd7 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.html +++ b/frontend/src/app/_pages/add-model/add-model.component.html @@ -42,15 +42,16 @@ <div class="form-group row my-2"> <div class="col-sm-2 col-form-label"> - <label for="type" class="form-check-label">Podela test skupa: + <label for="type" class="form-check-label">Automatska podela test skupa: <input class="mx-3 form-check-input" type="checkbox" [checked]="newModel.randomTestSet" (change)="newModel.randomTestSet = !newModel.randomTestSet"> </label> </div> <div> - <input type="range" min="0.1" max="0.9" step="0.1" class="form-control" name="randomTestSetDistribution" - [disabled]="!newModel.randomTestSet" [(ngModel)]="newModel.randomTestSetDistribution"> + <mat-slider min="0.1" max="0.9" step="0.1" value="0.2" name="randomTestSetDistribution" thumbLabel + class="w-50" [disabled]="!newModel.randomTestSet" [(ngModel)]="newModel.randomTestSetDistribution"> + </mat-slider> </div> </div> diff --git a/frontend/src/app/_pages/home/home.component.css b/frontend/src/app/_pages/home/home.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_pages/home/home.component.css diff --git a/frontend/src/app/_pages/home/home.component.html b/frontend/src/app/_pages/home/home.component.html new file mode 100644 index 00000000..6713cd59 --- /dev/null +++ b/frontend/src/app/_pages/home/home.component.html @@ -0,0 +1,51 @@ +<div> + <div class="d-flex flex-column align-items-center"> + <div *ngIf="shared.loggedIn"> + <h2 class="my-4">Započnite sa treniranjem!</h2> + <div id="cards" class="d-flex flex-row justify-content-center align-items-start"> + <div class="card" 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 mx-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 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" 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> + <h2 class="my-4">Pogledajte javne projekte!</h2> + <app-carousel [items]="publicDatasets"> + </app-carousel> + </div> +</div>
\ No newline at end of file diff --git a/frontend/src/app/_pages/home/home.component.spec.ts b/frontend/src/app/_pages/home/home.component.spec.ts new file mode 100644 index 00000000..2c5a1726 --- /dev/null +++ b/frontend/src/app/_pages/home/home.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HomeComponent } from './home.component'; + +describe('HomeComponent', () => { + let component: HomeComponent; + let fixture: ComponentFixture<HomeComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ HomeComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_pages/home/home.component.ts b/frontend/src/app/_pages/home/home.component.ts new file mode 100644 index 00000000..eb9adf27 --- /dev/null +++ b/frontend/src/app/_pages/home/home.component.ts @@ -0,0 +1,29 @@ +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'; + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.css'] +}) +export class HomeComponent implements OnInit { + + publicDatasets: Dataset[]; + + shared = shared; + + constructor() { + this.publicDatasets = [ + new Dataset('Dataset1', 'Lorem ipsum dolor sir amet', ['kolona1', 'kolona2', 'kolona3']), + new Dataset('Drugi Dataset', 'Lorem ipsum dolor sir amet', ['jabuka', 'kruska', 'jagoda']), + new Dataset('Dataset III', 'Kratak opis izvora podataka', ['c1', 'c2', 'c3', 'c4', 'c5']), + ] + } + + ngOnInit(): void { + } + +} diff --git a/frontend/src/app/_pages/login-page/login-page.component.html b/frontend/src/app/_pages/login-page/login-page.component.html index 3a4244fc..766268d9 100644 --- a/frontend/src/app/_pages/login-page/login-page.component.html +++ b/frontend/src/app/_pages/login-page/login-page.component.html @@ -6,8 +6,4 @@ <!-- Button trigger modal, OVO JE U STVARI DUGME U NAVBARU --> <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalForRegister"> Otvori register modal -</button> - - -<app-login-modal></app-login-modal> -<app-register-modal></app-register-modal> +</button>
\ No newline at end of file diff --git a/frontend/src/app/_pages/login-page/login-page.component.ts b/frontend/src/app/_pages/login-page/login-page.component.ts index 23ce4df0..58cd75a0 100644 --- a/frontend/src/app/_pages/login-page/login-page.component.ts +++ b/frontend/src/app/_pages/login-page/login-page.component.ts @@ -8,8 +8,8 @@ declare var window: any; selector: 'app-login-page', templateUrl: './login-page.component.html', styleUrls: ['./login-page.component.css'], - + }) -export class LoginPageComponent{ +export class LoginPageComponent { } diff --git a/frontend/src/app/_services/auth.service.ts b/frontend/src/app/_services/auth.service.ts index c96c2dae..e6611880 100644 --- a/frontend/src/app/_services/auth.service.ts +++ b/frontend/src/app/_services/auth.service.ts @@ -3,6 +3,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { JwtHelperService } from '@auth0/angular-jwt'; import { CookieService } from 'ngx-cookie-service'; import { API_SETTINGS } from 'src/config'; +import shared from '../Shared'; const jwtHelper = new JwtHelperService(); @@ -11,6 +12,8 @@ const jwtHelper = new JwtHelperService(); }) export class AuthService { + shared = shared; + constructor(private http: HttpClient, private cookie: CookieService) { } login(username: string, password: string) { @@ -28,4 +31,47 @@ export class AuthService { } return false; } + + lastToken?: string; + refresher: any; + + enableAutoRefresh() { + this.lastToken = this.cookie.get('token'); + let exp = jwtHelper.getTokenExpirationDate(this.lastToken); + if (!exp) { + exp = new Date(); + } + console.log(exp, exp?.getTime()); + this.refresher = setTimeout(() => { + console.log('refreshing token!'); + this.http.post(`${API_SETTINGS.apiURL}/auth/renewJwt`, {}, { headers: this.authHeader(), responseType: 'text' }).subscribe((response) => { + this.authenticate(response); + }); + }, exp.getTime() - new Date().getTime()); + } + + authenticate(token: string) { + const user = jwtHelper.decodeToken(token); + this.cookie.set('token', token, user.exp); + this.updateUser(); + } + + updateUser() { + if (this.cookie.check('token')) { + const token = this.cookie.get('token'); + this.shared.loggedIn = this.isAuthenticated(); + this.enableAutoRefresh(); + } + } + + logOut() { + this.cookie.delete('token'); + if (this.refresher) + clearTimeout(this.refresher); + this.shared.loggedIn = false; + } + + authHeader() { + return new HttpHeaders().set("Authorization", "Bearer " + this.cookie.get('token')); + } } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index d053a9a5..9ce08a8f 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -7,10 +7,11 @@ import { OnlyAuthorizedComponent } from './_pages/only-authorized/only-authorize import { RegisterPageComponent } from './_pages/register-page/register-page.component'; import { AddModelComponent } from './_pages/add-model/add-model.component'; import { LoginModalComponent } from './_modals/login-modal/login-modal.component'; +import { HomeComponent } from './_pages/home/home.component'; import { RegisterModalComponent } from './_modals/register-modal/register-modal.component'; const routes: Routes = [ - { path: '', redirectTo: '/login', pathMatch: 'full' }, + { path: '', component: HomeComponent }, { path: 'login', component: LoginPageComponent }, { path: 'register', component: RegisterPageComponent }, { path: 'only-authorized', component: OnlyAuthorizedComponent, canActivate: [AuthGuardService] }, diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index 90c6b646..7f2d4225 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1 +1,4 @@ -<router-outlet></router-outlet>
\ No newline at end of file +<app-navbar></app-navbar> +<div class="mat-app-background container h-100"> + <router-outlet></router-outlet> +</div>
\ No newline at end of file diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 553ff513..c0f6130e 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -3,9 +3,10 @@ import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; +import { MatSliderModule } from '@angular/material/slider'; +import { MatIconModule } from '@angular/material/icon'; import { AppComponent } from './app.component'; -import { LoginPageComponent } from './_pages/login-page/login-page.component'; import { RegisterPageComponent } from './_pages/register-page/register-page.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { OnlyAuthorizedComponent } from './_pages/only-authorized/only-authorized.component'; @@ -13,21 +14,30 @@ import { DatasetLoadComponent } from './_elements/dataset-load/dataset-load.comp import { AddModelComponent } from './_pages/add-model/add-model.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 { MaterialModule } from './material.module'; -import { ReactiveFormsModule } from '@angular/forms'; +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'; @NgModule({ declarations: [ AppComponent, - LoginPageComponent, RegisterPageComponent, OnlyAuthorizedComponent, DatasetLoadComponent, AddModelComponent, LoginModalComponent, - RegisterModalComponent + RegisterModalComponent, + HomeComponent, + NavbarComponent, + ItemPredictorComponent, + ItemDatasetComponent, + CarouselComponent ], imports: [ BrowserModule, @@ -37,7 +47,9 @@ import { ReactiveFormsModule } from '@angular/forms'; NgbModule, BrowserAnimationsModule, MaterialModule, - ReactiveFormsModule + ReactiveFormsModule, + MatSliderModule, + MatIconModule ], providers: [], bootstrap: [AppComponent] |