diff options
Diffstat (limited to 'frontend/src')
23 files changed, 703 insertions, 43 deletions
diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts new file mode 100644 index 00000000..216e1c36 --- /dev/null +++ b/frontend/src/app/_data/Model.ts @@ -0,0 +1,53 @@ +export default class Model { + constructor( + public name: string = 'Novi model', + public description: string = '', + public dateCreated: Date = new Date(), + public datasetId?: number, + + //Test set settings + public inputColumns: number[] = [0], + public columnToPredict: number = 1, + public randomTestSet: boolean = true, + public randomTestSetDistribution: number = 0.10, //0.1-0.9 (10% - 90%) + + // Neural net training settings + public type: ANNType = ANNType.FullyConnected, + public encoding: Encoding = Encoding.Label, + 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 inputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid, + public hiddenLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid, + public outputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid + ) { } +} + +export enum ANNType { + FullyConnected = 'potpuno povezana', + Convolutional = 'konvoluciona' +} + +export enum Encoding { + Label = 'label', + OneHot = 'one hot' +} + +export enum ActivationFunction { + Relu = 'relu', + Sigmoid = 'sigmoid', + Tanh = 'tanh', + Linear = 'linear' +} + +export enum LossFunction { + BinaryCrossEntropy = 'binary_crossentropy', + MeanSquaredError = 'mean_squared_error' +} + +export enum Optimizer { + Adam = 'adam' +}
\ No newline at end of file diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.css b/frontend/src/app/_elements/dataset-load/dataset-load.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.css diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.html b/frontend/src/app/_elements/dataset-load/dataset-load.component.html new file mode 100644 index 00000000..c89add43 --- /dev/null +++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.html @@ -0,0 +1,42 @@ +<div> + + <input style="display: inline-block; width:350px;" list=delimiterOptions + placeholder="Izaberite ili ukucajte delimiter za .csv fajl" class="form-control" [(ngModel)]="delimiter" + (input)="update()"> + <datalist id=delimiterOptions> + <option *ngFor="let option of delimiterOptions">{{option}}</option> + </datalist> + + <label for="checkboxHeader">Da li .csv ima header?</label> + <input (input)="update()" [(ngModel)]="hasHeader" type="checkbox" value="" id="checkboxHeader" checked> + <br><br> + + <input id="fileInput" class="form-control mb-5" type="file" class="upload" (change)="changeListener($event)" accept=".csv"> + + <table *ngIf="csvRecords.length > 0 && hasHeader" class="table table-bordered table-light mt-5"> + <thead> + <tr> + <th *ngFor="let item of csvRecords[0]; let i = index">{{item}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let row of csvRecords | slice:1:11"> + <td *ngFor="let col of row">{{col}}</td> + </tr> + </tbody> + </table> + + <table *ngIf="csvRecords.length > 0 && !hasHeader" class="table table-bordered table-light mt-5"> + <tbody> + <tr *ngFor="let row of csvRecords | slice:0:10"> + <td *ngFor="let col of row">{{col}}</td> + </tr> + </tbody> + </table> + + <div *ngIf="csvRecords.length > 0" id="info"> + . . . <br> + {{rowsNumber}} x {{colsNumber}} + </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/dataset-load/dataset-load.component.spec.ts new file mode 100644 index 00000000..5601b57b --- /dev/null +++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DatasetLoadComponent } from './dataset-load.component'; + +describe('DatasetLoadComponent', () => { + let component: DatasetLoadComponent; + let fixture: ComponentFixture<DatasetLoadComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ DatasetLoadComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DatasetLoadComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.ts b/frontend/src/app/_elements/dataset-load/dataset-load.component.ts new file mode 100644 index 00000000..843a5709 --- /dev/null +++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.ts @@ -0,0 +1,54 @@ +import { Component, ViewChild } from '@angular/core'; +import { NgxCsvParser, NgxCSVParserError } from 'ngx-csv-parser'; + +@Component({ + selector: 'app-dataset-load', + templateUrl: './dataset-load.component.html', + styleUrls: ['./dataset-load.component.css'] +}) +export class DatasetLoadComponent { + + delimiter: string = ""; + delimiterOptions: Array<string> = [",", ";", "\t", "razmak", "|"]; //podrazumevano "," + + hasHeader: boolean = true; + + slice: string = ""; + + csvRecords: any[] = []; + files: any[] = []; + rowsNumber: number = 0; + colsNumber: number = 0; + + constructor(private ngxCsvParser: NgxCsvParser) { + } + + @ViewChild('fileImportInput', { static: false }) fileImportInput: any; + + changeListener($event: any): void { + this.files = $event.srcElement.files; + this.update(); + } + + update() { + + if (this.files.length < 1) + return; + + this.ngxCsvParser.parse(this.files[0], { header: false, delimiter: (this.delimiter == "razmak") ? " " : (this.delimiter == "") ? "," : this.delimiter}) + .pipe().subscribe((result) => { + + //console.log('Result', result); + if (result.constructor === Array) { + this.csvRecords = result; + if (this.hasHeader) + this.rowsNumber = this.csvRecords.length - 1; + else + this.rowsNumber = this.csvRecords.length; + this.colsNumber = this.csvRecords[0].length; + } + }, (error: NgxCSVParserError) => { + console.log('Error', error); + }); + } +} diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.css b/frontend/src/app/_modals/login-modal/login-modal.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_modals/login-modal/login-modal.component.css diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.html b/frontend/src/app/_modals/login-modal/login-modal.component.html new file mode 100644 index 00000000..22f50de2 --- /dev/null +++ b/frontend/src/app/_modals/login-modal/login-modal.component.html @@ -0,0 +1,49 @@ +<!-- Button trigger modal, OVO JE U STVARI DUGME U NAVBARU --> +<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalForLogin" (click)="openModal()"> + Otvori login modal +</button> + +<!-- 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 bg-info"> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></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> + + <div class="text-center text-lg-start mt-5 pt-2"> + <p *ngIf="wrongCreds" class="small fw-bold mt-2 pt-1 mb-0 text-danger">Lozinka ili e-mail su pogrešni + </p> + </div> + </form> + <div class="col-md-12 d-flex justify-content-center"> + <button type="button" class="btn btn-lg btn-info" style="color:white; border-color: #00a8e8; margin-right: 10px;" (click)="doLogin()">Prijavite se</button> + <button type="button" class="btn btn-lg btn-outline-secondary" data-bs-dismiss="modal">Odustanite</button> + </div> + <br> + </div> + <div class="modal-footer justify-content-center"> + <p class="small fw-bold">Još uvek nemate nalog? + <a routerLink="/register" class="link-danger">Registrujte se</a> + </p> + </div> + </div> + </div> +</div> + + diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.spec.ts b/frontend/src/app/_modals/login-modal/login-modal.component.spec.ts new file mode 100644 index 00000000..7d0d526a --- /dev/null +++ b/frontend/src/app/_modals/login-modal/login-modal.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginModalComponent } from './login-modal.component'; + +describe('LoginModalComponent', () => { + let component: LoginModalComponent; + let fixture: ComponentFixture<LoginModalComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LoginModalComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.ts b/frontend/src/app/_modals/login-modal/login-modal.component.ts new file mode 100644 index 00000000..3a6fd8f1 --- /dev/null +++ b/frontend/src/app/_modals/login-modal/login-modal.component.ts @@ -0,0 +1,51 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { Router } from '@angular/router'; +import { CookieService } from 'ngx-cookie-service'; +import { AuthService } from 'src/app/_services/auth.service'; +import { ElementRef } from '@angular/core'; + +declare var window: any; + +@Component({ + selector: 'app-login-modal', + templateUrl: './login-modal.component.html', + styleUrls: ['./login-modal.component.css'] +}) +export class LoginModalComponent implements OnInit { + + loginModal: any; + username: string = ''; + password: string = ''; + + public wrongCreds: boolean = false; //RAZMOTRITI + + constructor( + private authService: AuthService, + private cookie: CookieService, + private router: Router + ) { } + + ngOnInit(): void { + this.loginModal = new window.bootstrap.Modal( + document.getElementById("modalForLogin") + ); + } + + openModal() { + this.loginModal.show(); + //console.log("ok"); + //(<HTMLInputElement>document.getElementById("exampleModal")).style.display = "block"; + } + 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.loginModal.hide(); //dodato + this.router.navigate(['add-model']); + }); + } + sendToRegister() { + + } +} diff --git a/frontend/src/app/_pages/add-model/add-model.component.css b/frontend/src/app/_pages/add-model/add-model.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_pages/add-model/add-model.component.css diff --git a/frontend/src/app/_pages/add-model/add-model.component.html b/frontend/src/app/_pages/add-model/add-model.component.html new file mode 100644 index 00000000..bc292bb9 --- /dev/null +++ b/frontend/src/app/_pages/add-model/add-model.component.html @@ -0,0 +1,189 @@ +<div class="container p-3" style="background-color: rgb(249, 251, 253); min-height: 100%;"> + + <h2 class="my-4 text-primary"> Nov model: </h2> + <div class="form-group row align-items-center"> + <label for="name" class="col-sm-2 col-form-label col-form-label-lg">Naziv</label> + <div class="col-sm-7"> + <input type="text" class="form-control form-control-lg" name="name" placeholder="Naziv..." + [(ngModel)]="newModel.name"> + </div> + + <div class="col-sm-3"> + <input type="text" class="form-control-plaintext text-center" id="dateCreated" placeholder="--/--/--" + value="{{newModel.dateCreated | date: 'dd/MM/yyyy'}}" readonly> + </div> + </div> + + <div class="form-group row my-2"> + <label for="desc" class="col-sm-2 col-form-label">Opis</label> + <div class="col-sm-10"> + <textarea class="form-control" name="desc" rows="3" [(ngModel)]="newModel.description"></textarea> + </div> + </div> + + <!--<div class="form-group row"> + <label for="value" class="col-4">Vrednost</label> + <div class="input-group"> + <input type="number" min="0" class="form-control" name="value" placeholder="Vrednost..." + [(ngModel)]="newModel.value"> + <div class="input-group-prepend"> + <span class="input-group-text">#</span> + </div> + <input type="number" min="1" class="form-control" name="count" placeholder="Br." [(ngModel)]="newModel.count"> + <input type="text" class="form-control" name="sum" placeholder="Suma" + value="=({{newModel.value * newModel.count}})" readonly> + </div> + </div>--> + + <div class="my-4"> + <label for="dataset">Izvor podataka:</label> + <app-dataset-load id="dataset"></app-dataset-load> + </div> + + <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: + <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"> + </div> + </div> + + <h3> Parametri treniranja </h3> + + <div class="form-group row my-2"> + <label for="type" class="col-sm-2 col-form-label">Tip mreže: </label> + <div class="col-sm-10"> + <select id=typeOptions class="form-control" name="type" [(ngModel)]="newModel.type"> + <option *ngFor="let option of Object.keys(ANNType); let optionName of Object.values(ANNType)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> + </div> + + <div class="form-group row my-2"> + <label for="encoding" class="col-sm-2 col-form-label">Enkoding: </label> + <div class="col-sm-10"> + <select id=encodingOptions class="form-control" name="encoding" [(ngModel)]="newModel.encoding"> + <option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> + </div> + + <div class="form-group row my-2"> + <label for="optimizer" class="col-sm-2 col-form-label">Optimizacija: </label> + <div class="col-sm-10"> + <select id=optimizerOptions class="form-control" name="optimizer" [(ngModel)]="newModel.optimizer"> + <option *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> + </div> + + <div class="form-group row my-2"> + <label for="lossFunction" class="col-sm-2 col-form-label">Funkcija obrade gubitka: </label> + <div class="col-sm-10"> + <select id=lossFunctionOptions class="form-control" name="lossFunction" [(ngModel)]="newModel.lossFunction"> + <option *ngFor="let option of Object.keys(LossFunction); let optionName of Object.values(LossFunction)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> + </div> + + <div class="form-group row my-2"> + <label for="inputNeurons" class="col-sm-2 col-form-label">Broj ulaznih neurona: </label> + <div class="col-sm-10"> + <input type="number" min="1" class="form-control" name="inputNeurons" [(ngModel)]="newModel.inputNeurons"> + </div> + </div> + + <div class="form-group row my-2"> + <label for="inputLayerActivationFunction" class="col-sm-2 col-form-label">Funkcija aktivacije ulaznog sloja: + </label> + <div class="col-sm-10"> + <select id=inputLayerActivationFunctionOptions class="form-control" name="inputLayerActivationFunction" + [(ngModel)]="newModel.inputLayerActivationFunction"> + <option + *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> + </div> + + <div class="form-group row my-2"> + <label for="hiddenLayerNeurons" class="col-sm-2 col-form-label">Broj neurona skrivenih slojeva: </label> + <div class="col-sm-10"> + <input type="number" min="1" class="form-control" name="hiddenLayerNeurons" + [(ngModel)]="newModel.hiddenLayerNeurons"> + </div> + </div> + + <div class="form-group row my-2"> + <label for="hiddenLayerActivationFunction" class="col-sm-2 col-form-label">Funkcija aktivacije skrivenih + slojeva: + </label> + <div class="col-sm-10"> + <select id=hiddenLayerActivationFunctionOptions class="form-control" name="hiddenLayerActivationFunction" + [(ngModel)]="newModel.hiddenLayerActivationFunction"> + <option + *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> + </div> + + <div class="form-group row my-2"> + <label for="hiddenLayers" class="col-sm-2 col-form-label">Broj skrivenih slojeva: </label> + <div class="col-sm-10"> + <input type="number" min="1" class="form-control" name="hiddenLayers" [(ngModel)]="newModel.hiddenLayers"> + </div> + </div> + + <div class="form-group row my-2"> + <label for="outputLayerActivationFunction" class="col-sm-2 col-form-label">Funkcija aktivacije izlaznog + sloja: + </label> + <div class="col-sm-10"> + <select id=outputLayerActivationFunctionOptions class="form-control" name="outputLayerActivationFunction" + [(ngModel)]="newModel.outputLayerActivationFunction"> + <option + *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> + </div> + + <div class="form-group row my-2"> + <label for="batchSize" class="col-sm-2 col-form-label">Broj uzorka po iteraciji: </label> + <div class="col-sm-10"> + <input type="number" min="1" class="form-control" name="batchSize" [(ngModel)]="newModel.batchSize"> + </div> + </div> + + <div class=" form-group row my-4"> + <div class="col-4"></div> + <button class="btn btn-lg btn-primary col-4" (click)="addModel();">Dodaj</button> + <div class="col-4"></div> + </div> + +</div>
\ No newline at end of file diff --git a/frontend/src/app/_pages/add-model/add-model.component.spec.ts b/frontend/src/app/_pages/add-model/add-model.component.spec.ts new file mode 100644 index 00000000..2926e1c4 --- /dev/null +++ b/frontend/src/app/_pages/add-model/add-model.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddModelComponent } from './add-model.component'; + +describe('AddModelComponent', () => { + let component: AddModelComponent; + let fixture: ComponentFixture<AddModelComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AddModelComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AddModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_pages/add-model/add-model.component.ts b/frontend/src/app/_pages/add-model/add-model.component.ts new file mode 100644 index 00000000..3cb47d61 --- /dev/null +++ b/frontend/src/app/_pages/add-model/add-model.component.ts @@ -0,0 +1,32 @@ +import { Component, OnInit } from '@angular/core'; +import Model from 'src/app/_data/Model'; +import { ANNType, Encoding, ActivationFunction, LossFunction, Optimizer } from 'src/app/_data/Model'; + +@Component({ + selector: 'app-add-model', + templateUrl: './add-model.component.html', + styleUrls: ['./add-model.component.css'] +}) +export class AddModelComponent implements OnInit { + + newModel: Model + + ANNType = ANNType; + Encoding = Encoding; + ActivationFunction = ActivationFunction; + LossFunction = LossFunction; + Optimizer = Optimizer; + Object = Object; + + constructor() { + this.newModel = new Model(); + } + + ngOnInit(): void { + } + + addModel() { + //TODO + } + +} 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 906eaba6..8deb5290 100644 --- a/frontend/src/app/_pages/login-page/login-page.component.html +++ b/frontend/src/app/_pages/login-page/login-page.component.html @@ -1,18 +1,33 @@ +<!--<script> + $(document).ready(function(){ + $(".btn").click(function(){ + $("#exampleModal").modal('show'); + }); + + $('#exampleModal').modal({ + backdrop: 'static', + keyboard: false + }); + }); +</script>--> + +<!-- Button trigger modal --> +<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalForLogin" (click)="openModal()"> + Open Modal + </button> + +<!-- <div style="min-height: 100vh; position: relative;"> - <!-- TODO : <app-navbar [activeNav]="'login'"></app-navbar>--> - <div class="container p-5 rounded-3 shadow-sm border" style="max-width: 50em; margin-top: 50px;"> <h3 class="text-center pb-5">Prijavite se</h3> <form> - <!-- Email input --> <div class="form-outline mb-4"> - <label class="form-label" for="email">Email adresa</label> - <input [(ngModel)]="email" name="email" type="email" id="email" class="form-control form-control-lg" - placeholder="Unesite email adresu..." /> + <label class="form-label" for="username">Korisničko ime</label> + <input [(ngModel)]="username" name="username" type="text" id="username" + class="form-control form-control-lg" placeholder="Unesite korisničko ime..." /> </div> - <!-- Password input --> <div class="form-outline mb-3"> <label class="form-label" for="password">Lozinka</label> <input [(ngModel)]="password" name="password" type="password" id="password" @@ -20,17 +35,15 @@ </div> <div class="text-center text-lg-start mt-4 pt-2"> - <!-- Pogresna lozinka --> <p *ngIf="wrongCreds" class="small fw-bold mt-2 pt-1 mb-0 text-danger">Lozinka ili e-mail su pogrešni </p> - <!-- Nepotvrdjena registracija - <p *ngIf="notApproved" class="small fw-bold mt-2 pt-1 mb-0 text-danger">Vaša registracija još uvek nije potvrđena</p>--> <br> <button type="button" class="btn btn-primary btn-lg" style="padding-left: 2.5rem; padding-right: 2.5rem;" (click)="onSubmit()">Prijava </button> + <br> <p class="small fw-bold mt-2 pt-1 mb-0">Još uvek nemate nalog? <a routerLink="/register" class="link-danger">Registrujte se</a> </p> @@ -38,6 +51,5 @@ </form> </div> - <!-- TODO: <app-footer></app-footer>--> - -</div>
\ No newline at end of file +</div> +-->
\ 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 f8b429e3..e5366283 100644 --- a/frontend/src/app/_pages/login-page/login-page.component.ts +++ b/frontend/src/app/_pages/login-page/login-page.component.ts @@ -1,40 +1,63 @@ import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; import { CookieService } from 'ngx-cookie-service'; import { AuthService } from 'src/app/_services/auth.service'; +import { LoginModalComponent } from 'src/app/_modals/login-modal/login-modal.component'; +import { MDBModalRef, MDBModalService } from 'ng-uikit-pro-standard'; + + +declare var window: any; + @Component({ selector: 'app-login-page', templateUrl: './login-page.component.html', - styleUrls: ['./login-page.component.css'] + styleUrls: ['./login-page.component.css'], + }) -export class LoginPageComponent implements OnInit { - email: string = ''; +export class LoginPageComponent{ + + modalRef?: MDBModalRef; + + //email: string = ''; + username: string = ''; password: string = ''; public wrongCreds: boolean = false; //RAZMOTRITI //public notApproved: boolean = false; //RAZMOTRITI - pattEmail: RegExp = /^[a-zA-Z0-9]+([\.\-\+][a-zA-Z0-9]+)*\@([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}$/; + formModal: any; constructor( private authService: AuthService, - private cookie: CookieService + private cookie: CookieService, + private router: Router, + private modalService: MDBModalService ) { } + openModal() { + //this.modalRef = this.modalService.show(LoginModalComponent); + } + /* ngOnInit(): void { + this.formModal = new window.bootstrap.Modal( + document.getElementById("exampleModal") + ); } - onSubmit() { - if (!this.pattEmail.test(this.email)) { - console.warn('Bad email!'); - return; - } - else { - this.authService.login(this.email, this.password).subscribe((response) => { - console.log(response); - this.cookie.set('token', response); - }) - } + openModal() { + this.formModal.show(); + //console.log("ok"); + //(<HTMLInputElement>document.getElementById("exampleModal")).style.display = "block"; } + onSubmit() { + + this.authService.login(this.username, this.password).subscribe((response) => { + console.log(response); + this.cookie.set('token', response); + this.router.navigate(['add-model']); + }); + } +*/ } diff --git a/frontend/src/app/_pages/register-page/register-page.component.ts b/frontend/src/app/_pages/register-page/register-page.component.ts index e8d4c036..712fc55e 100644 --- a/frontend/src/app/_pages/register-page/register-page.component.ts +++ b/frontend/src/app/_pages/register-page/register-page.component.ts @@ -104,7 +104,7 @@ export class RegisterPageComponent implements OnInit { this.firstNameValidation(); this.lastNameValidation(); - this.nickNameValidation(); + //this.nickNameValidation(); this.emailValidation(); this.passwordValidation(); @@ -114,19 +114,21 @@ export class RegisterPageComponent implements OnInit { let user = { firstName: this.firstName, lastName: this.lastName, - nickName: this.nickName, - email: this.email, - password: this.pass1 + username: this.nickName, + password: this.pass1, + email: this.email } this.authService.register(user) .subscribe( (response) => { console.log(response); - /*if () + if (response === 'User added') this.router.navigate(['/login']); //registracija uspesna, idi na login - else if () - alert('Nalog sa unetim email-om već postoji!');*/ + else if (response === 'Email Already Exists') + alert('Nalog sa unetim email-om već postoji!'); + else if (response === 'Username Already Exists') + alert('Nalog sa unetim korisnićkim imenom već postoji!'); } ); } diff --git a/frontend/src/app/_services/auth.service.ts b/frontend/src/app/_services/auth.service.ts index 7129b95b..c96c2dae 100644 --- a/frontend/src/app/_services/auth.service.ts +++ b/frontend/src/app/_services/auth.service.ts @@ -18,7 +18,7 @@ export class AuthService { } register(user: any) { - return this.http.post(`${API_SETTINGS.apiURL}/auth/register`, user); + return this.http.post(`${API_SETTINGS.apiURL}/auth/register`, { ...user }, { responseType: 'text' }); } isAuthenticated(): boolean { diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 1868e56c..cd86ef5c 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -1,15 +1,20 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; +import { AuthGuardService } from './_services/auth-guard.service'; import { LoginPageComponent } from './_pages/login-page/login-page.component'; import { OnlyAuthorizedComponent } from './_pages/only-authorized/only-authorized.component'; import { RegisterPageComponent } from './_pages/register-page/register-page.component'; -import { AuthGuardService } from './_services/auth-guard.service'; +import { AddModelComponent } from './_pages/add-model/add-model.component'; +import { LoginModalComponent } from './_modals/login-modal/login-modal.component'; const routes: Routes = [ + { path: '', redirectTo: '/login', pathMatch: 'full' }, { path: 'login', component: LoginPageComponent }, { path: 'register', component: RegisterPageComponent }, - { path: 'only-authorized', component: OnlyAuthorizedComponent, canActivate: [AuthGuardService] } + { path: 'only-authorized', component: OnlyAuthorizedComponent, canActivate: [AuthGuardService] }, + { path: 'add-model', component: AddModelComponent }, + { path: 'login-modal-test', component: LoginModalComponent } ]; @NgModule({ diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 9ccd7ddb..d95252ad 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -9,20 +9,33 @@ 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'; +import { DatasetLoadComponent } from './_elements/dataset-load/dataset-load.component'; +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 { MaterialModule } from './material.module'; +import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ declarations: [ AppComponent, LoginPageComponent, RegisterPageComponent, - OnlyAuthorizedComponent + OnlyAuthorizedComponent, + DatasetLoadComponent, + AddModelComponent, + LoginModalComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule, HttpClientModule, - NgbModule + NgbModule, + BrowserAnimationsModule, + MaterialModule, + ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] diff --git a/frontend/src/app/material.module.ts b/frontend/src/app/material.module.ts new file mode 100644 index 00000000..e85419ee --- /dev/null +++ b/frontend/src/app/material.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; + +import { MatDialogModule } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatCheckboxModule } from '@angular/material/checkbox'; + +@NgModule({ + exports: [ + MatDialogModule, + MatButtonModule, + MatFormFieldModule, + MatInputModule, + MatCheckboxModule + ] +}) +export class MaterialModule {}
\ No newline at end of file diff --git a/frontend/src/custom-theme.scss b/frontend/src/custom-theme.scss new file mode 100644 index 00000000..a6538c37 --- /dev/null +++ b/frontend/src/custom-theme.scss @@ -0,0 +1,35 @@ + +// 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(); + +// 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); + +// The warn palette is optional (defaults to red). +$frontend-warn: mat.define-palette(mat.$red-palette); + +// 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, + ) +)); + +// 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); + diff --git a/frontend/src/index.html b/frontend/src/index.html index 3af61ec9..b3b6eb54 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -6,8 +6,11 @@ <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> + <link rel="preconnect" href="https://fonts.gstatic.com"> + <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> +<body class="mat-typography"> <app-root></app-root> </body> </html> diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 90d4ee00..8997c10e 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1 +1,5 @@ -/* You can add global styles to this file, and also import other style files */ +/* You can add global styles to this file, and also import other style files + +html, body { height: 100%; } +body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } +*/
\ No newline at end of file |