Per-Arne
5 years ago
163 changed files with 1599 additions and 3476 deletions
@ -0,0 +1,39 @@ |
|||
import json |
|||
import multiprocessing |
|||
import os |
|||
|
|||
workers_per_core_str = os.getenv("WORKERS_PER_CORE", "1") |
|||
web_concurrency_str = os.getenv("WEB_CONCURRENCY", None) |
|||
host = os.getenv("HOST", "unix:/tmp/gunicorn.sock") |
|||
port = os.getenv("PORT", "80") |
|||
use_loglevel = os.getenv("LOG_LEVEL", "info") |
|||
use_bind = host if "unix" in host else f"{host}:{port}" |
|||
|
|||
cores = multiprocessing.cpu_count() |
|||
workers_per_core = float(workers_per_core_str) |
|||
default_web_concurrency = workers_per_core * cores |
|||
if web_concurrency_str: |
|||
web_concurrency = int(web_concurrency_str) |
|||
assert web_concurrency > 0 |
|||
else: |
|||
web_concurrency = max(int(default_web_concurrency), 2) |
|||
|
|||
# Gunicorn config variables |
|||
loglevel = use_loglevel |
|||
workers = web_concurrency |
|||
bind = use_bind |
|||
keepalive = 120 |
|||
errorlog = "-" |
|||
|
|||
# For debugging and testing |
|||
log_data = { |
|||
"loglevel": loglevel, |
|||
"workers": workers, |
|||
"bind": bind, |
|||
"worker-tmp-dir": "/dev/shm", |
|||
# Additional, non-gunicorn variables |
|||
"workers_per_core": workers_per_core, |
|||
"host": host, |
|||
"port": port, |
|||
} |
|||
print(json.dumps(log_data)) |
@ -0,0 +1,32 @@ |
|||
import os |
|||
from os.path import isdir |
|||
DEFAULT_MODULE_LOCATIONS = [("app.main", "/app/app/main.py"), ("main", "/app/main.py")] |
|||
DEFAULT_GUNICORN_CONF = [(None, "/app/gunicorn_config.py"), (None, "/app/startup/gunicorn_config.py")] |
|||
|
|||
|
|||
def get_location(pot): |
|||
for i in pot: |
|||
if not isdir(i[1]): |
|||
continue |
|||
# Last record will be "defauilt" |
|||
return i[0] if i[0] else i[1] |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
MODULE_NAME = os.getenv("MODULE_LOCATION", get_location(DEFAULT_MODULE_LOCATIONS)) |
|||
VARIABLE_NAME = os.getenv("VARIABLE_NAME", "app") |
|||
APP_MODULE = os.getenv("APP_MODULE", f"{MODULE_NAME}:{VARIABLE_NAME}") |
|||
GUNICORN_CONF = os.getenv("GUNICORN_CONF", get_location(DEFAULT_GUNICORN_CONF)) |
|||
OPTIONS = [ |
|||
"-k", |
|||
"uvicorn.workers.UvicornWorker", |
|||
"-c", |
|||
f"{GUNICORN_CONF} {APP_MODULE}" |
|||
] |
|||
|
|||
# Set envs |
|||
os.putenv("VARIABLE_NAME", VARIABLE_NAME) |
|||
os.putenv("APP_MODULE", APP_MODULE) |
|||
os.putenv("GUNICORN_CONF", GUNICORN_CONF) |
|||
|
|||
os.system(f"gunicorn -k uvicorn.workers.UvicornWorker -c {GUNICORN_CONF} {APP_MODULE}") |
@ -0,0 +1,31 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
|
|||
import { LayoutComponent } from './layout/layout.component'; |
|||
import {MatSidenavModule} from "@angular/material/sidenav"; |
|||
import {MatToolbarModule} from "@angular/material/toolbar"; |
|||
import {MatListModule} from "@angular/material/list"; |
|||
import {MatIconModule} from "@angular/material/icon"; |
|||
import {MatButtonModule} from "@angular/material/button"; |
|||
import {FlexLayoutModule} from "@angular/flex-layout"; |
|||
import {RouterModule} from "@angular/router"; |
|||
|
|||
|
|||
|
|||
@NgModule({ |
|||
declarations: [LayoutComponent], |
|||
imports: [ |
|||
CommonModule, |
|||
MatSidenavModule, |
|||
MatToolbarModule, |
|||
MatListModule, |
|||
MatIconModule, |
|||
MatButtonModule, |
|||
FlexLayoutModule, |
|||
RouterModule |
|||
], |
|||
exports: [ |
|||
|
|||
] |
|||
}) |
|||
export class LayoutModule { } |
@ -0,0 +1,56 @@ |
|||
<div style="height: 100vh;"> |
|||
|
|||
|
|||
<mat-toolbar color="primary"> |
|||
<mat-toolbar-row> |
|||
<button mat-icon-button (click)="sidenav.toggle()" fxShow="true" fxHide.gt-sm> |
|||
<mat-icon>menu</mat-icon> |
|||
</button> |
|||
<span>{{config.applicationName}}</span> |
|||
<span class="example-spacer"></span> |
|||
<div fxShow="true" fxHide.lt-md="true"> |
|||
|
|||
<!-- The following menu items will be hidden on both SM and XS screen sizes --> |
|||
|
|||
<a *ngFor="let item of menu" [routerLink]="item.link" mat-button> |
|||
<mat-icon>{{item.icon}}</mat-icon> |
|||
{{item.text}} |
|||
</a> |
|||
|
|||
</div> |
|||
</mat-toolbar-row> |
|||
|
|||
</mat-toolbar> |
|||
|
|||
<mat-sidenav-container fxFlexFill> |
|||
<mat-sidenav #sidenav> |
|||
<mat-nav-list> |
|||
<a href="#" mat-list-item> |
|||
<mat-icon>notifications</mat-icon> |
|||
Notifications |
|||
</a> |
|||
<a href="#" mat-list-item> |
|||
<mat-icon>message</mat-icon> |
|||
Messages</a> |
|||
<a href="#" mat-list-item> |
|||
<mat-icon>account_box</mat-icon> |
|||
My Account |
|||
</a> |
|||
<a href="#" mat-list-item> |
|||
<mat-icon>lock</mat-icon> |
|||
My Account |
|||
</a> |
|||
<a (click)="sidenav.toggle()" mat-list-item> |
|||
<mat-icon>close</mat-icon> Close |
|||
</a> |
|||
</mat-nav-list> |
|||
</mat-sidenav> |
|||
<mat-sidenav-content fxFlexFill> |
|||
<router-outlet></router-outlet> |
|||
</mat-sidenav-content> |
|||
</mat-sidenav-container> |
|||
|
|||
|
|||
|
|||
|
|||
</div> |
@ -0,0 +1,19 @@ |
|||
.sidenav-container { |
|||
height: 100%; |
|||
} |
|||
|
|||
.sidenav { |
|||
width: 200px; |
|||
} |
|||
|
|||
.sidenav .mat-toolbar { |
|||
background: inherit; |
|||
} |
|||
|
|||
.mat-toolbar.mat-primary { |
|||
position: sticky; |
|||
top: 0; |
|||
z-index: 1; |
|||
} |
|||
|
|||
|
@ -0,0 +1,25 @@ |
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { LayoutComponent } from './layout.component'; |
|||
|
|||
describe('LayoutComponent', () => { |
|||
let component: LayoutComponent; |
|||
let fixture: ComponentFixture<LayoutComponent>; |
|||
|
|||
beforeEach(async(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [ LayoutComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
})); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(LayoutComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
@ -0,0 +1,29 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import {Observable} from "rxjs"; |
|||
import {BreakpointObserver, Breakpoints} from "@angular/cdk/layout"; |
|||
import {map, shareReplay} from "rxjs/operators"; |
|||
import {ConfigService} from "../../services/config.service"; |
|||
|
|||
@Component({ |
|||
selector: 'app-layout', |
|||
templateUrl: './layout.component.html', |
|||
styleUrls: ['./layout.component.scss'] |
|||
}) |
|||
export class LayoutComponent implements OnInit { |
|||
|
|||
isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset) |
|||
.pipe( |
|||
map(result => result.matches), |
|||
shareReplay() |
|||
); |
|||
|
|||
menu: Array<{link: Array<string>, icon: string, text: string}> = [ |
|||
{ link: ["/page/dashboard"], icon: "home", text: "Dashboard"} |
|||
]; |
|||
|
|||
constructor(private breakpointObserver: BreakpointObserver, public config: ConfigService) {} |
|||
ngOnInit(): void { |
|||
console.log("Layout") |
|||
} |
|||
|
|||
} |
@ -1,5 +0,0 @@ |
|||
<div class="mdl-layout mdl-js-layout"> |
|||
<main class="mdl-layout__content"> |
|||
<router-outlet></router-outlet> |
|||
</main> |
|||
</div> |
@ -1,11 +0,0 @@ |
|||
@import '~theme/helpers'; |
|||
|
|||
app-blank-layout .mdl-layout .mdl-layout__content { |
|||
padding: 16px; |
|||
display: flex; |
|||
} |
|||
|
|||
// FIXME: responsibility leak |
|||
.not-found .mdl-layout__content { |
|||
background-image: url('#{$image-path}/404.svg'); |
|||
} |
@ -1,18 +0,0 @@ |
|||
import { Component, HostBinding } from '@angular/core'; |
|||
import { Router } from '@angular/router'; |
|||
|
|||
@Component({ |
|||
selector: 'app-blank-layout', |
|||
styleUrls: ['./blank-layout.component.scss'], |
|||
templateUrl: './blank-layout.component.html', |
|||
}) |
|||
export class BlankLayoutComponent { |
|||
// FIXME: responsibility leak
|
|||
@HostBinding('class.not-found') private get notFound() { |
|||
return this.router.url === '/pages/404'; |
|||
} |
|||
|
|||
constructor( |
|||
private router: Router, |
|||
) { } |
|||
} |
@ -1 +0,0 @@ |
|||
export { BlankLayoutComponent } from './blank-layout.component'; |
@ -1,89 +0,0 @@ |
|||
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header has-drawer"> |
|||
<div class="mdl-layout__header"> |
|||
<base-page-top> |
|||
|
|||
<span class="mdl-layout__title">{{title}}</span> |
|||
<nav class="mdl-navigation"> |
|||
<base-menu-item *ngFor="let item of menu" [data]="item"></base-menu-item> |
|||
|
|||
<div class="mdl-layout-spacer"></div> |
|||
</nav> |
|||
|
|||
<div class="mdl-layout-spacer"></div> |
|||
|
|||
|
|||
<!-- |
|||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--expandable search"> |
|||
<label class="mdl-button mdl-js-button mdl-button--icon" for="search"> |
|||
<i class="material-icons">search</i> |
|||
</label> |
|||
|
|||
<div class="mdl-textfield__expandable-holder"> |
|||
<input class="mdl-textfield__input" type="text" id="search"/> |
|||
<label class="mdl-textfield__label" for="search">Enter your query...</label> |
|||
</div> |
|||
</div>--> |
|||
|
|||
|
|||
|
|||
<div class="avatar-dropdown" id="icon" *ngIf="auth.user"> |
|||
<span>Logged in as {{auth.user?.username}}</span> |
|||
<!--<img src="assets/images/Icon_header.png">--> |
|||
</div> |
|||
<ul |
|||
class="mdl-menu mdl-list mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect mdl-shadow--2dp account-dropdown" |
|||
for="icon"> |
|||
<li class="mdl-list__item mdl-list__item--two-line"> |
|||
<span class="mdl-list__item-primary-content"> |
|||
<span class="material-icons mdl-list__item-avatar"></span> |
|||
<span>{{ auth.user?.username }}</span> |
|||
<span class="mdl-list__item-sub-title">{{ auth.user?.email }}</span> |
|||
</span> |
|||
</li> |
|||
<li class="list__item--border-top"></li> |
|||
<li class="mdl-menu__item mdl-list__item"> |
|||
<span class="mdl-list__item-primary-content" (click)="router.navigate(['/user/edit'])"> |
|||
<i class="material-icons mdl-list__item-icon">account_circle</i> |
|||
My account |
|||
</span> |
|||
</li> |
|||
<!--<li class="mdl-menu__item mdl-list__item"> |
|||
<span class="mdl-list__item-primary-content"> |
|||
<i class="material-icons mdl-list__item-icon">check_box</i> |
|||
My tasks |
|||
</span> |
|||
<span class="mdl-list__item-secondary-content"> |
|||
<span class="label background-color--primary">3 new</span> |
|||
</span> |
|||
</li> |
|||
<li class="mdl-menu__item mdl-list__item"> |
|||
<span class="mdl-list__item-primary-content"> |
|||
<i class="material-icons mdl-list__item-icon">perm_contact_calendar</i> |
|||
My events |
|||
</span> |
|||
</li>--> |
|||
<!--<li class="list__item--border-top"></li> |
|||
<li class="mdl-menu__item mdl-list__item"> |
|||
<span class="mdl-list__item-primary-content"> |
|||
<i class="material-icons mdl-list__item-icon">settings</i> |
|||
Settings |
|||
</span> |
|||
</li>--> |
|||
<li class="mdl-menu__item mdl-list__item"> |
|||
<span class="mdl-list__item-primary-content" (click)="logout()"> |
|||
<i class="material-icons mdl-list__item-icon text-color--secondary">exit_to_app</i> |
|||
Log out |
|||
</span> |
|||
</li> |
|||
</ul> |
|||
|
|||
</base-page-top> |
|||
</div> |
|||
|
|||
<!--<div class="mdl-layout__drawer"> |
|||
<app-sidebar></app-sidebar> |
|||
</div>--> |
|||
<main class="mdl-layout__content"> |
|||
<router-outlet></router-outlet> |
|||
</main> |
|||
</div> |
@ -1,28 +0,0 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { Router } from '@angular/router'; |
|||
|
|||
import { AuthService } from '@services/*'; |
|||
|
|||
@Component({ |
|||
selector: 'app-common-layout', |
|||
templateUrl: './common-layout.component.html', |
|||
}) |
|||
export class CommonLayoutComponent implements OnInit { |
|||
public title = 'Wireguard Manager'; |
|||
public menu = [ |
|||
{ name: 'Dashboard', link: '/app/dashboard', icon: 'dashboard' }, |
|||
]; |
|||
|
|||
|
|||
constructor(public auth: AuthService, |
|||
public router: Router) {} |
|||
|
|||
public ngOnInit() { |
|||
|
|||
} |
|||
|
|||
public logout() { |
|||
this.auth.logout() |
|||
.subscribe(res => this.router.navigate(['/user/login'])); |
|||
} |
|||
} |
@ -1 +0,0 @@ |
|||
export { CommonLayoutComponent } from './common-layout.component'; |
@ -1 +0,0 @@ |
|||
export { LayoutsModule } from './layouts.module'; |
@ -1,32 +0,0 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule } from '@angular/router'; |
|||
|
|||
import { BlankLayoutCardComponent } from 'app/components/blank-layout-card'; |
|||
import { MessageMenuComponent } from 'app/components/message-menu'; |
|||
import { NotificationMenuComponent } from 'app/components/notification-menu'; |
|||
import { SidebarComponent } from 'app/components/sidebar'; |
|||
import { ThemeModule } from 'theme'; |
|||
import { BlankLayoutComponent } from './blank-layout'; |
|||
import { CommonLayoutComponent } from './common-layout'; |
|||
|
|||
@NgModule({ |
|||
imports: [ |
|||
CommonModule, |
|||
ThemeModule, |
|||
RouterModule, |
|||
], |
|||
declarations: [ |
|||
CommonLayoutComponent, |
|||
BlankLayoutComponent, |
|||
BlankLayoutCardComponent, |
|||
SidebarComponent, |
|||
MessageMenuComponent, |
|||
NotificationMenuComponent, |
|||
], |
|||
exports: [ |
|||
CommonLayoutComponent, |
|||
BlankLayoutComponent, |
|||
], |
|||
}) |
|||
export class LayoutsModule { } |
@ -1,13 +1,12 @@ |
|||
import { Component, HostBinding } from '@angular/core'; |
|||
|
|||
import { UpgradableComponent } from 'theme/components/upgradable'; |
|||
|
|||
@Component({ |
|||
selector: 'app-components', |
|||
templateUrl: './components.component.html', |
|||
styleUrls: ['./components.component.scss'], |
|||
}) |
|||
export class ComponentsComponent extends UpgradableComponent { |
|||
export class ComponentsComponent { |
|||
@HostBinding('class.mdl-grid') private readonly mdlGrid = true; |
|||
@HostBinding('class.ui-components') private readonly uiComponents = true; |
|||
|
@ -0,0 +1,104 @@ |
|||
<mat-card class="dashboard-card"> |
|||
<mat-card-content class="dashboard-card-content"> |
|||
|
|||
<form [formGroup]="serverForm" (ngSubmit)="serverForm.valid && add(serverForm.value)" class="add-server-form"> |
|||
|
|||
<p>Essentials</p> |
|||
<table class="add-server-full-width" cellspacing="0"><tr> |
|||
<td> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Interface</mat-label> |
|||
<input formControlName="interface" matInput placeholder="wg0"> |
|||
</mat-form-field> |
|||
</td> |
|||
<td> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Address Scope</mat-label> |
|||
<input formControlName="address" matInput placeholder="10.0.200.1/24"> |
|||
</mat-form-field> |
|||
</td> |
|||
</tr></table> |
|||
|
|||
<table class="add-server-full-width" cellspacing="0"><tr> |
|||
<td> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Endpoint</mat-label> |
|||
<input formControlName="endpoint" matInput placeholder="my-address.com"> |
|||
</mat-form-field> |
|||
</td> |
|||
<td> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Port</mat-label> |
|||
<input formControlName="listen_port" matInput placeholder="51820"> |
|||
</mat-form-field> |
|||
</td> |
|||
</tr></table> |
|||
|
|||
<p>Keys</p> |
|||
<p> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Private-Key</mat-label> |
|||
<input formControlName="private_key" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
<p> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Public-Key</mat-label> |
|||
<input formControlName="public_key" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
<p> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Shared-Key</mat-label> |
|||
<input formControlName="shared_key" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
<div class="add-server-button-group"> |
|||
<button type="button" [hidden]="!isEdit" (click)="getKeyPair()" mat-raised-button color="primary" disabled> |
|||
<i class="material-icons">vpn_key</i> |
|||
Generate KeyPair |
|||
</button> |
|||
<button type="button" [hidden]="!isEdit" (click)="getPSK()" mat-raised-button color="primary"> |
|||
<i class="material-icons">share</i> |
|||
Generate PSK |
|||
</button> |
|||
</div> |
|||
|
|||
<p>Scripts</p> |
|||
<p> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Post-Up</mat-label> |
|||
<input formControlName="post_up" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
<p> |
|||
<mat-form-field class="add-server-full-width"> |
|||
<mat-label>Post-Down</mat-label> |
|||
<input formControlName="post_down" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
|
|||
<div class="add-server-button-group"> |
|||
<button mat-raised-button color="primary" [disabled]="!serverForm.valid" type="submit"> |
|||
<ng-container *ngIf="!isEdit">Add Server</ng-container> |
|||
<ng-container *ngIf="isEdit">Edit Server</ng-container> |
|||
</button> |
|||
|
|||
<button mat-raised-button color="warn" (click)="isEdit = false; serverForm.reset()"> |
|||
Reset |
|||
</button> |
|||
|
|||
</div> |
|||
</form> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</mat-card-content> |
|||
</mat-card> |
@ -0,0 +1,18 @@ |
|||
.add-server-form { |
|||
min-width: 150px; |
|||
//max-width: 500px; |
|||
width: 100%; |
|||
} |
|||
|
|||
.add-server-full-width { |
|||
width: 100%; |
|||
} |
|||
|
|||
td { |
|||
padding-right: 8px; |
|||
} |
|||
|
|||
.add-server-button-group{ |
|||
margin-right: 8px; |
|||
} |
|||
|
@ -0,0 +1,85 @@ |
|||
import {Component, Input, OnInit, ViewEncapsulation} from '@angular/core'; |
|||
import {FormControl, FormGroup, Validators} from "@angular/forms"; |
|||
import {IPValidator} from "../../../validators/ip-address.validator"; |
|||
import {NumberValidator} from "../../../validators/number.validator"; |
|||
import {Server} from "../../../interfaces/server"; |
|||
import {ServerService} from "../../../services/server.service"; |
|||
import {DataService} from "../../../services/data.service"; |
|||
|
|||
@Component({ |
|||
selector: 'app-add-server', |
|||
templateUrl: './add-server.component.html', |
|||
encapsulation: ViewEncapsulation.None, |
|||
styleUrls: ['./add-server.component.scss', '../dashboard2.component.css'] |
|||
}) |
|||
export class AddServerComponent implements OnInit { |
|||
|
|||
@Input() servers: Array<Server>; |
|||
|
|||
serverForm = new FormGroup({ |
|||
address: new FormControl('', [IPValidator.isIPAddress]), |
|||
interface: new FormControl('', [Validators.required, Validators.minLength(3)]), |
|||
listen_port: new FormControl('', [Validators.required, NumberValidator.stringIsNumber]), |
|||
endpoint: new FormControl('', Validators.required), |
|||
private_key: new FormControl('', [Validators.minLength(44), Validators.maxLength(44)]), |
|||
public_key: new FormControl('', [Validators.minLength(44), Validators.maxLength(44)]), |
|||
shared_key: new FormControl('', [Validators.minLength(44), Validators.maxLength(44)]), |
|||
post_up: new FormControl(''), |
|||
post_down: new FormControl(''), |
|||
|
|||
// Unused on backend
|
|||
is_running: new FormControl(false), |
|||
peers: new FormControl([]), |
|||
}); |
|||
isEdit: boolean = false; |
|||
editServer: Server = null; |
|||
|
|||
constructor(private serverAPI: ServerService, private comm: DataService) { } |
|||
|
|||
ngOnInit(): void { |
|||
|
|||
this.comm.on("server-edit").subscribe( (data: Server) => { |
|||
this.isEdit = true; |
|||
this.serverForm.setValue(data); |
|||
this.editServer = data; |
|||
}) |
|||
|
|||
} |
|||
|
|||
add(form: Server) { |
|||
|
|||
if(this.isEdit){ |
|||
const idx = this.servers.indexOf(this.editServer); |
|||
this.serverAPI.editServer(this.editServer, form).subscribe((server: Server) => { |
|||
this.servers[idx] = server; |
|||
}); |
|||
|
|||
} else { |
|||
|
|||
this.serverAPI.addServer(form).subscribe((server: Server) => { |
|||
this.servers.push(server); |
|||
}); |
|||
} |
|||
|
|||
this.isEdit = false; |
|||
this.serverForm.reset(); |
|||
this.editServer = null; |
|||
} |
|||
|
|||
getKeyPair() { |
|||
this.serverAPI.getKeyPair().subscribe((kp: any) => { |
|||
this.serverForm.patchValue({ |
|||
private_key: kp.private_key, |
|||
public_key: kp.public_key |
|||
}) |
|||
}); |
|||
} |
|||
|
|||
getPSK() { |
|||
this.serverAPI.getPSK().subscribe((psk: any) => { |
|||
this.serverForm.patchValue({ |
|||
shared_key: psk.psk |
|||
}) |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,18 @@ |
|||
.grid-container { |
|||
margin: 20px; |
|||
} |
|||
|
|||
.dashboard-card { |
|||
position: absolute; |
|||
top: 15px; |
|||
left: 15px; |
|||
right: 15px; |
|||
bottom: 15px; |
|||
} |
|||
|
|||
.more-button { |
|||
position: absolute; |
|||
top: 5px; |
|||
right: 10px; |
|||
} |
|||
|
@ -0,0 +1,11 @@ |
|||
<div flex fxFill fxLayout="row" fxLayoutAlign="space-between" > |
|||
<div fxFlex="65"> |
|||
<app-server [(server)]="servers[idx]" [(servers)]="servers" *ngFor="let server of servers; let idx = index"></app-server> |
|||
</div> |
|||
|
|||
<div fxFlex="34"> |
|||
<app-add-server [(servers)]="servers"></app-add-server> |
|||
</div> |
|||
|
|||
|
|||
</div> |
@ -0,0 +1,40 @@ |
|||
import { LayoutModule } from '@angular/cdk/layout'; |
|||
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; |
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
import { MatButtonModule } from '@angular/material/button'; |
|||
import { MatCardModule } from '@angular/material/card'; |
|||
import { MatGridListModule } from '@angular/material/grid-list'; |
|||
import { MatIconModule } from '@angular/material/icon'; |
|||
import { MatMenuModule } from '@angular/material/menu'; |
|||
|
|||
import { Dashboard2Component } from './dashboard2.component'; |
|||
|
|||
describe('Dashboard2Component', () => { |
|||
let component: Dashboard2Component; |
|||
let fixture: ComponentFixture<Dashboard2Component>; |
|||
|
|||
beforeEach(async(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [Dashboard2Component], |
|||
imports: [ |
|||
NoopAnimationsModule, |
|||
LayoutModule, |
|||
MatButtonModule, |
|||
MatCardModule, |
|||
MatGridListModule, |
|||
MatIconModule, |
|||
MatMenuModule, |
|||
] |
|||
}).compileComponents(); |
|||
})); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(Dashboard2Component); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should compile', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
@ -0,0 +1,44 @@ |
|||
import {Component, OnInit} from '@angular/core'; |
|||
import { map } from 'rxjs/operators'; |
|||
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout'; |
|||
import {Server} from "../../interfaces/server"; |
|||
import {ServerService} from "../../services/server.service"; |
|||
import {Peer} from "../../interfaces/peer"; |
|||
|
|||
@Component({ |
|||
selector: 'dashboard2', |
|||
templateUrl: './dashboard2.component.html', |
|||
styleUrls: ['./dashboard2.component.css'] |
|||
}) |
|||
export class Dashboard2Component implements OnInit |
|||
{ |
|||
servers: Array<Server> = []; |
|||
|
|||
constructor(private breakpointObserver: BreakpointObserver, private serverAPI: ServerService) { |
|||
|
|||
} |
|||
|
|||
|
|||
ngOnInit(): void { |
|||
this.serverAPI.getServers() |
|||
.subscribe( (servers: Array<Server>) => { |
|||
this.servers.push(...servers); |
|||
servers.forEach((server) => { |
|||
|
|||
this.serverAPI.serverStats(server).subscribe((stats: Peer[]) => { |
|||
stats.forEach( item => { |
|||
const peer = server.peers.find(x => x.public_key == item.public_key); |
|||
peer._stats = item |
|||
}); |
|||
|
|||
|
|||
}); |
|||
|
|||
|
|||
}); |
|||
|
|||
|
|||
}) |
|||
} |
|||
|
|||
} |
@ -0,0 +1,49 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import {Dashboard2Component} from "./dashboard2.component"; |
|||
import {MatGridListModule} from "@angular/material/grid-list"; |
|||
import {MatCardModule} from "@angular/material/card"; |
|||
import {MatMenuModule} from "@angular/material/menu"; |
|||
import {MatIconModule} from "@angular/material/icon"; |
|||
import {MatButtonModule} from "@angular/material/button"; |
|||
import {ServerComponent} from "./server/server.component"; |
|||
import {MatExpansionModule} from "@angular/material/expansion"; |
|||
import {AddServerComponent} from "./add-server/add-server.component"; |
|||
import {MatFormFieldModule} from "@angular/material/form-field"; |
|||
import {MatInputModule} from "@angular/material/input"; |
|||
import {FormsModule, ReactiveFormsModule} from "@angular/forms"; |
|||
import {ComponentsModule} from "../components"; |
|||
import {FlexModule} from "@angular/flex-layout"; |
|||
import {MatTableModule} from "@angular/material/table"; |
|||
import {PeerComponent} from "./peer/peer.component"; |
|||
import {QRCodeModule} from "angularx-qrcode"; |
|||
|
|||
|
|||
|
|||
@NgModule({ |
|||
declarations: [ |
|||
Dashboard2Component, |
|||
ServerComponent, |
|||
AddServerComponent, |
|||
PeerComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
MatGridListModule, |
|||
MatCardModule, |
|||
MatMenuModule, |
|||
MatIconModule, |
|||
MatButtonModule, |
|||
MatExpansionModule, |
|||
MatFormFieldModule, |
|||
MatInputModule, |
|||
ReactiveFormsModule, |
|||
ComponentsModule, |
|||
FlexModule, |
|||
MatTableModule, |
|||
FormsModule, |
|||
QRCodeModule, |
|||
|
|||
] |
|||
}) |
|||
export class Dashboard2Module { } |
@ -0,0 +1,76 @@ |
|||
<div flex fxLayout="row" fxLayoutAlign="space-between"> |
|||
<div fxFlex="50"> |
|||
|
|||
|
|||
<form #peerForm="ngForm" class="peer-edit-form" (ngSubmit)="peerForm.valid && edit()" > |
|||
|
|||
<b>Essentials</b> |
|||
<table class="full-width" cellspacing="0"><tr> |
|||
<td> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>Name</mat-label> |
|||
<input [disabled]="!peer._edit" name="name" matInput [(ngModel)]="peer.name"> |
|||
</mat-form-field> |
|||
</td> |
|||
<td> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>Address</mat-label> |
|||
<input [disabled]="!peer._edit" name="address" matInput [(ngModel)]="peer.address"> |
|||
</mat-form-field> |
|||
</td> |
|||
</tr></table> |
|||
|
|||
<p> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>DNS</mat-label> |
|||
<input [disabled]="!peer._edit" name="dns" [(ngModel)]="peer.dns" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
|
|||
<p> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>Allowed IPs</mat-label> |
|||
<input [disabled]="!peer._edit" name="allowed_ips" [(ngModel)]="peer.allowed_ips" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
|
|||
<p>Keys</p> |
|||
<p> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>Private-Key</mat-label> |
|||
<input [disabled]="!peer._edit" name="private_key" [(ngModel)]="peer.private_key" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
<p> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>Public-Key</mat-label> |
|||
<input [disabled]="!peer._edit" name="public_key" [(ngModel)]="peer.public_key" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
<button |
|||
[hidden]="!peer._edit" |
|||
[disabled]="!peerForm.valid" |
|||
type="submit" |
|||
mat-raised-button color="primary"> |
|||
Submit changes |
|||
</button> |
|||
|
|||
</form> |
|||
|
|||
|
|||
|
|||
</div> |
|||
|
|||
<div fxFlex="33"> |
|||
<textarea readonly class="mdl-textfield--full-width" style="min-height: 250px; height: 100%; background-color: #202020; color: #00bcd4;">{{config}}</textarea> |
|||
|
|||
</div> |
|||
<div fxFlex="33"> |
|||
<qrcode [qrdata]="config" [width]="256" [errorCorrectionLevel]="'M'"></qrcode> |
|||
</div> |
|||
|
|||
</div> |
@ -0,0 +1,17 @@ |
|||
.peer-edit-form { |
|||
min-width: 150px; |
|||
//max-width: 500px; |
|||
width: 100%; |
|||
text-align: left; |
|||
} |
|||
|
|||
.full-width { |
|||
width: 100%; |
|||
} |
|||
|
|||
|
|||
td { |
|||
padding-left: 0 !important; |
|||
padding-right: 8px; |
|||
text-align: left !important; |
|||
} |
@ -0,0 +1,84 @@ |
|||
import {Component, EventEmitter, Input, OnInit, ViewEncapsulation} from '@angular/core'; |
|||
import {ServerService} from "../../../services/server.service"; |
|||
import {Peer} from "../../../interfaces/peer"; |
|||
import {Server} from "../../../interfaces/server"; |
|||
import {FormControl, FormGroup} from "@angular/forms"; |
|||
|
|||
@Component({ |
|||
selector: 'app-peer', |
|||
templateUrl: './peer.component.html', |
|||
encapsulation: ViewEncapsulation.None, |
|||
styleUrls: ['./peer.component.scss'], |
|||
}) |
|||
export class PeerComponent implements OnInit { |
|||
|
|||
@Input("peer") peer: Peer; |
|||
@Input("server") server: Server; |
|||
@Input("selectedPeer") selectedPeer: Peer; |
|||
@Input("onEvent") editPeerEmitter: EventEmitter<any> = new EventEmitter<any>(); |
|||
|
|||
|
|||
|
|||
config: string = "Loading..."; |
|||
|
|||
|
|||
constructor(public serverAPI: ServerService) { } |
|||
|
|||
ngOnInit(): void { |
|||
|
|||
this.editPeerEmitter.subscribe( (msg) => { |
|||
if(msg.peer !== this.peer){ |
|||
return; |
|||
} |
|||
if(msg.type === "edit"){ |
|||
this.edit(); |
|||
|
|||
}else if(msg.type == "delete"){ |
|||
this.delete(); |
|||
}else if(msg.type == "open"){ |
|||
this.fetchConfig(); |
|||
} |
|||
}) |
|||
|
|||
} |
|||
|
|||
edit(){ |
|||
if(this.peer._edit) { |
|||
|
|||
// Submit the edit (True -> False)
|
|||
const idx = this.server.peers.indexOf(this.peer); |
|||
this.serverAPI.editPeer(this.peer).subscribe((newPeer) => { |
|||
Object.keys(newPeer).forEach(k => { |
|||
this.server.peers[idx][k] = newPeer[k]; |
|||
}); |
|||
}); |
|||
|
|||
} else if(!this.peer._edit) { |
|||
this.peer._expand = true; |
|||
|
|||
// Open for edit. aka do nothing (False -> True
|
|||
|
|||
} |
|||
|
|||
this.peer._edit = !this.peer._edit; |
|||
|
|||
|
|||
} |
|||
|
|||
delete(){ |
|||
const idx = this.server.peers.indexOf(this.peer); |
|||
this.serverAPI.deletePeer(this.peer).subscribe((apiServer) => { |
|||
this.server.peers.splice(idx, 1); |
|||
}) |
|||
} |
|||
|
|||
fetchConfig() { |
|||
this.serverAPI.peerConfig(this.peer).subscribe((config: any) => { |
|||
this.config = config.config |
|||
}) |
|||
} |
|||
|
|||
pInt(string: string) { |
|||
return parseInt(string) |
|||
} |
|||
} |
@ -0,0 +1,248 @@ |
|||
|
|||
<mat-card class="dashboard-card"> |
|||
<mat-card-header class="server-card-header"> |
|||
<mat-card-title> |
|||
<span>{{server.interface}}</span> |
|||
|
|||
<!-- This fills the remaining space of the current row --> |
|||
<span class="fill-remaining-space"></span> |
|||
|
|||
<i class="material-icons" [ngClass]="{'text-success': server.is_running, 'text-danger': !server.is_running}">check_circle</i> |
|||
|
|||
<app-modal-confirm |
|||
[qrCode]="true" |
|||
[noConfirm]="false" |
|||
area="true" |
|||
icon="settings" |
|||
title="Configuration" |
|||
[text]="serverConfig" |
|||
hover="Show config for {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<span> |
|||
|
|||
<app-modal-confirm |
|||
[noConfirm]="true" |
|||
(onConfirm)="addPeer()" |
|||
icon="person_add" |
|||
hover="Add peer to {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
*ngIf="!server.is_running" |
|||
[noConfirm]="true" |
|||
(onConfirm)="start()" |
|||
icon="play_arrow" |
|||
hover="Start {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
*ngIf="server.is_running" |
|||
[noConfirm]="false" |
|||
(onConfirm)="stop()" |
|||
title="Stop server {{server.interface}}?" |
|||
text="Are you sure you want to stop this server? This may cause you or your clients to lose connection to the server." |
|||
icon="stop" |
|||
hover="Stop {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
[noConfirm]="false" |
|||
(onConfirm)="restart()" |
|||
title="Restart server {{server.interface}}?" |
|||
text="Are you sure you want to restart this server? This may cause you or your clients to lose connection to the server." |
|||
icon="autorenew" |
|||
hover="Restart {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
[noConfirm]="true" |
|||
(onConfirm)="edit()" |
|||
icon="edit" |
|||
hover="Edit {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
(onConfirm)="delete()" |
|||
title="Delete {{server.interface}}" |
|||
text="Are you sure you want to delete {{server.interface}}" |
|||
icon="delete" |
|||
hover="Delete {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
</span> |
|||
|
|||
|
|||
|
|||
</mat-card-title> |
|||
<mat-card-subtitle>{{server.address}} @ {{server.endpoint}}</mat-card-subtitle> |
|||
</mat-card-header> |
|||
|
|||
<mat-card-content class="dashboard-card-content"> |
|||
|
|||
|
|||
<table class="table"> |
|||
<thead> |
|||
<tr> |
|||
<th>Name</th> |
|||
<th>Address</th> |
|||
<th>Public-Key</th> |
|||
<th>Total tx/rx</th> |
|||
<th>Handshake</th> |
|||
<th>Manage</th> |
|||
</tr> |
|||
</thead> |
|||
|
|||
|
|||
<tbody> |
|||
<ng-container *ngFor="let peer of server.peers; let idx = index;" (click)="selectedPeer = (selectedPeer != peer)? peer : null"> |
|||
|
|||
<tr (click)="openPeer(peer)"> |
|||
<td>{{peer.name}}</td> |
|||
<td>{{peer.address}}</td> |
|||
<td>{{peer.public_key}}</td> |
|||
<td>{{peer._stats?.tx || '0'}}/{{peer._stats?.rx || '0'}}</td> |
|||
<td>{{peer._stats?.handshake || 'N/A'}}</td> |
|||
<td> |
|||
|
|||
<!-- Edit buttons --> |
|||
<app-modal-confirm |
|||
[noConfirm]="true" |
|||
(onConfirm)="this.editPeerEmitter.emit({type: 'edit', peer: peer})" |
|||
icon="edit" |
|||
hover="Edit {{peer.name}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
[noConfirm]="false" |
|||
(onConfirm)="this.editPeerEmitter.emit({type: 'delete', peer: peer});" |
|||
text="Are you sure you want to delete {{peer.name}} ({{peer.public_key}})?" |
|||
title="Delete {{peer.name}}" |
|||
icon="delete" |
|||
hover="Delete {{peer.name}} ({{peer.public_key}})"> |
|||
</app-modal-confirm> |
|||
|
|||
|
|||
|
|||
</td> |
|||
</tr> |
|||
<tr [hidden]="peer !== selectedPeer"> |
|||
<td colspan="6"> |
|||
<app-peer [onEvent]="this.editPeerEmitter" [(peer)]="server.peers[idx]" [(server)]="server"></app-peer> |
|||
</td> |
|||
</tr> |
|||
|
|||
|
|||
</ng-container> |
|||
</tbody> |
|||
</table> |
|||
|
|||
|
|||
|
|||
|
|||
</mat-card-content> |
|||
<mat-card-actions> |
|||
</mat-card-actions> |
|||
</mat-card> |
|||
|
|||
|
|||
|
|||
<!-- |
|||
<mat-card class="dashboard-card"> |
|||
<mat-card-content class="dashboard-card-content"> |
|||
*Server* |
|||
<ng-container > |
|||
|
|||
|
|||
</ng-container> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
|
|||
|
|||
--> |
|||
|
|||
<!-- |
|||
<div class=" mdl-card mdl-shadow--2dp"> |
|||
<div class="mdl-card__title mdl-card--border"> |
|||
<h2 class="mdl-card__title-text">{{server.interface}}</h2> |
|||
<span style="width:20px;"></span> |
|||
|
|||
|
|||
|
|||
</div> |
|||
|
|||
<div class="mdl-card__actions"> |
|||
|
|||
<div class="mdl-grid peer-item-header"> |
|||
<div class="mdl-cell--2-col mdl-cell--12-col-phone">Name</div> |
|||
<div class="mdl-cell--2-col mdl-cell--12-col-phone">Address</div> |
|||
<div class="mdl-cell--3-col mdl-cell--12-col-phone">Public-Key</div> |
|||
<div class="mdl-cell--2-col mdl-cell--12-col-phone">Total tx/rx</div> |
|||
<div class="mdl-cell--2-col mdl-cell--12-col-phone">Handshake</div> |
|||
<div class="mdl-cell--2-col mdl-cell--12-col-phone">Manage</div> |
|||
</div> |
|||
|
|||
|
|||
<div style="cursor: pointer;" *ngFor="let peer of server.peers; let idx = index;" > |
|||
<app-peer [(peer)]="server.peers[idx]" [(server)]="server"></app-peer> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<div class="mdl-card__supporting-text"> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
<div class="mdl-card__menu"> |
|||
|
|||
<app-modal-confirm |
|||
[noConfirm]="true" |
|||
(onConfirm)="addPeer()" |
|||
icon="person_add" |
|||
hover="Add peer to {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
*ngIf="!server.is_running" |
|||
[noConfirm]="true" |
|||
(onConfirm)="start()" |
|||
icon="play_arrow" |
|||
hover="Start {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
*ngIf="server.is_running" |
|||
[noConfirm]="false" |
|||
(onConfirm)="stop()" |
|||
title="Stop server {{server.interface}}?" |
|||
text="Are you sure you want to stop this server? This may cause you or your clients to lose connection to the server." |
|||
icon="stop" |
|||
hover="Stop {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
[noConfirm]="false" |
|||
(onConfirm)="restart()" |
|||
title="Restart server {{server.interface}}?" |
|||
text="Are you sure you want to restart this server? This may cause you or your clients to lose connection to the server." |
|||
icon="autorenew" |
|||
hover="Restart {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
[noConfirm]="true" |
|||
(onConfirm)="edit()" |
|||
icon="edit" |
|||
hover="Edit {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
|
|||
<app-modal-confirm |
|||
(onConfirm)="delete()" |
|||
title="Delete {{server.interface}}" |
|||
text="Are you sure you want to delete {{server.interface}}" |
|||
icon="delete" |
|||
hover="Delete {{server.interface}}"> |
|||
</app-modal-confirm> |
|||
</div> |
|||
</div>--> |
@ -0,0 +1,28 @@ |
|||
|
|||
table { |
|||
width: 100%; |
|||
} |
|||
|
|||
tr.example-detail-row { |
|||
height: 0 !important; |
|||
} |
|||
|
|||
tr.example-element-row:not(.example-expanded-row):hover { |
|||
background: whitesmoke; |
|||
} |
|||
|
|||
tr.example-element-row:not(.example-expanded-row):active { |
|||
background: #efefef; |
|||
} |
|||
|
|||
.example-element-row td { |
|||
border-bottom-width: 0; |
|||
} |
|||
|
|||
.example-element-detail { |
|||
overflow: hidden; |
|||
display: flex; |
|||
} |
|||
|
|||
|
|||
|
@ -0,0 +1,77 @@ |
|||
import {Component, EventEmitter, Input, OnInit, ViewEncapsulation} from '@angular/core'; |
|||
import {Server} from "../../../interfaces/server"; |
|||
import {ServerService} from "../../../services/server.service"; |
|||
import {DataService} from "../../../services/data.service"; |
|||
import {Peer} from "../../../interfaces/peer"; |
|||
|
|||
|
|||
@Component({ |
|||
selector: 'app-server', |
|||
templateUrl: './server.component.html', |
|||
encapsulation: ViewEncapsulation.None, |
|||
styleUrls: ['./server.component.scss', '../dashboard2.component.css'], |
|||
}) |
|||
export class ServerComponent implements OnInit { |
|||
@Input() server: Server; |
|||
@Input() servers: Array<Server>; |
|||
public editPeerEmitter: EventEmitter<any> = new EventEmitter<any>(); |
|||
|
|||
serverConfig: string; |
|||
|
|||
selectedPeer: Peer | null; |
|||
|
|||
constructor(private serverAPI: ServerService, private comm: DataService) { } |
|||
|
|||
ngOnInit(): void { |
|||
console.log("Server"); |
|||
|
|||
this.serverAPI.serverConfig(this.server).subscribe((x: any) => this.serverConfig = x.config) |
|||
|
|||
} |
|||
|
|||
edit(){ |
|||
|
|||
this.comm.emit('server-edit', this.server); |
|||
} |
|||
|
|||
stop() { |
|||
this.serverAPI.stopServer(this.server).subscribe((apiServer) => { |
|||
this.server.is_running = apiServer.is_running |
|||
}) |
|||
} |
|||
|
|||
start() { |
|||
this.serverAPI.startServer(this.server).subscribe((apiServer) => { |
|||
this.server.is_running = apiServer.is_running |
|||
}) |
|||
} |
|||
|
|||
addPeer() { |
|||
this.serverAPI.addPeer(this.server).subscribe((peer) => { |
|||
this.server.peers.push(peer) |
|||
}) |
|||
} |
|||
|
|||
restart() { |
|||
this.serverAPI.restartServer(this.server).subscribe((apiServer) => { |
|||
this.server.is_running = apiServer.is_running |
|||
}) |
|||
} |
|||
|
|||
|
|||
delete() { |
|||
const index = this.servers.indexOf(this.server); |
|||
this.serverAPI.deleteServer(this.server).subscribe((apiServer) => { |
|||
this.servers.splice(index, 1); |
|||
}) |
|||
} |
|||
|
|||
openPeer(peer: Peer) { |
|||
if(this.selectedPeer == peer){ |
|||
this.selectedPeer = null; |
|||
return |
|||
} |
|||
this.selectedPeer = peer; |
|||
this.editPeerEmitter.emit({type: 'open', peer: peer}); |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
*{-webkit-box-sizing:border-box;box-sizing:border-box}body{padding:0;margin:0}#notfound{position:relative;height:100vh}#notfound .notfound{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.notfound{max-width:520px;width:100%;line-height:1.4;text-align:center}.notfound .notfound-404{position:relative;height:240px}.notfound .notfound-404 h1{font-family:montserrat,sans-serif;position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);font-size:252px;font-weight:900;margin:0;color:#262626;text-transform:uppercase;letter-spacing:-40px;margin-left:-20px}.notfound .notfound-404 h1>span{text-shadow:-8px 0 0 #fff}.notfound .notfound-404 h3{font-family:cabin,sans-serif;position:relative;font-size:16px;font-weight:700;text-transform:uppercase;color:#262626;margin:0;letter-spacing:3px;padding-left:6px}.notfound h2{font-family:cabin,sans-serif;font-size:20px;font-weight:400;text-transform:uppercase;color:#000;margin-top:0;margin-bottom:25px}@media only screen and (max-width:767px){.notfound .notfound-404{height:200px}.notfound .notfound-404 h1{font-size:200px}}@media only screen and (max-width:480px){.notfound .notfound-404{height:162px}.notfound .notfound-404 h1{font-size:162px;height:150px;line-height:162px}.notfound h2{font-size:16px}} |
@ -0,0 +1,9 @@ |
|||
<div id="notfound"> |
|||
<div class="notfound"> |
|||
<div class="notfound-404"> |
|||
<h3>Oops! Page not found</h3> |
|||
<h1><span>4</span><span>0</span><span>4</span></h1> |
|||
</div> |
|||
<h2>we are sorry, but the page you requested was not found</h2> |
|||
</div> |
|||
</div> |
@ -0,0 +1,8 @@ |
|||
import { Component, HostBinding } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'app-error', |
|||
styleUrls: ['error.component.css'], |
|||
templateUrl: './error.component.html', |
|||
}) |
|||
export class ErrorComponent { } |
@ -0,0 +1,32 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { Routes, RouterModule } from '@angular/router'; |
|||
import {Dashboard2Component} from "./dashboard2/dashboard2.component"; |
|||
import {LayoutComponent} from "../layout/layout/layout.component"; |
|||
import {ErrorComponent} from "./error"; |
|||
import {LoginComponent} from "./user/login/login.component"; |
|||
import {AuthGuard} from "@services/*"; |
|||
|
|||
|
|||
|
|||
|
|||
const routes: Routes = [ |
|||
{ path: '', component: LayoutComponent, children: |
|||
[ |
|||
//{ path: 'dashboard', component: DashboardComponent, pathMatch: 'full', canActivate: [AuthGuard]},
|
|||
{ path: 'dashboard', component: Dashboard2Component, pathMatch: 'full', canActivate: [AuthGuard]}, |
|||
{ path: '404', component: ErrorComponent, pathMatch: 'full' }, |
|||
] |
|||
}, |
|||
{ path: 'user', component: LayoutComponent, children: |
|||
[ |
|||
//{ path: 'dashboard', component: DashboardComponent, pathMatch: 'full', canActivate: [AuthGuard]},
|
|||
{ path: 'login', component: LoginComponent, pathMatch: 'full'}, |
|||
] |
|||
}, |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule] |
|||
}) |
|||
export class PageRoutingModule { } |
@ -0,0 +1,24 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import {PageRoutingModule} from "./page-routing.module"; |
|||
import {Dashboard2Module} from "./dashboard2/dashboard2.module"; |
|||
import {LoginComponent} from "./user/login/login.component"; |
|||
import {MatCardModule} from "@angular/material/card"; |
|||
import {FormsModule, ReactiveFormsModule} from "@angular/forms"; |
|||
import {MatInputModule} from "@angular/material/input"; |
|||
|
|||
|
|||
@NgModule({ |
|||
declarations: [LoginComponent], |
|||
imports: [ |
|||
CommonModule, |
|||
PageRoutingModule, |
|||
FormsModule, |
|||
Dashboard2Module, |
|||
MatCardModule, |
|||
ReactiveFormsModule, |
|||
MatInputModule, |
|||
], |
|||
|
|||
}) |
|||
export class PageModule { } |
@ -0,0 +1,48 @@ |
|||
<div class="container"> |
|||
|
|||
<base-card> |
|||
<base-card-title> |
|||
<h2 class="mdl-card__title-text">Edit User</h2> |
|||
</base-card-title> |
|||
<base-card-body> |
|||
|
|||
<form [formGroup]="editForm" (ngSubmit)="editForm.valid && edit()" class="form"> |
|||
|
|||
<div class="mdl-grid"> |
|||
<div class="mdl-cell mdl-cell--6-col mdl-textfield mdl-js-textfield mdl-textfield--floating-label"> |
|||
<input formControlName="full_name" class="mdl-textfield__input" type="text" id="full_name" value=""/> |
|||
<label class="mdl-textfield__label" for="full_name">Full Name</label> |
|||
</div> |
|||
|
|||
|
|||
<div class="mdl-cell mdl-cell--6-col mdl-textfield mdl-js-textfield mdl-textfield--floating-label"> |
|||
<input formControlName="username" class="mdl-textfield__input" type="text" id="username" /> |
|||
<label class="mdl-textfield__label" for="username">Username</label> |
|||
</div> |
|||
|
|||
<div class="mdl-cell mdl-cell--6-col mdl-textfield mdl-js-textfield mdl-textfield--floating-label"> |
|||
<input formControlName="password" class="mdl-textfield__input" type="text" id="password"/> |
|||
<label class="mdl-textfield__label" for="password">Password</label> |
|||
</div> |
|||
|
|||
<div class="mdl-cell mdl-cell--6-col mdl-textfield mdl-js-textfield mdl-textfield--floating-label"> |
|||
<input formControlName="email" class="mdl-textfield__input" type="text" id="email"/> |
|||
<label class="mdl-textfield__label" for="email">Email</label> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
|
|||
<button [disabled]="!editForm.valid" type="submit" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect button--colored-light-blue"> |
|||
Edit User |
|||
</button> |
|||
|
|||
|
|||
|
|||
</form> |
|||
|
|||
|
|||
</base-card-body> |
|||
</base-card> |
|||
|
|||
</div> |
@ -0,0 +1,51 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import {FormControl, FormGroup, Validators} from "@angular/forms"; |
|||
import {AuthService} from "@services/*"; |
|||
import {Router} from "@angular/router"; |
|||
|
|||
@Component({ |
|||
selector: 'app-edit', |
|||
templateUrl: './edit.component.html', |
|||
styleUrls: ['./edit.component.scss'] |
|||
}) |
|||
export class EditComponent implements OnInit { |
|||
|
|||
public editForm: FormGroup = new FormGroup({ |
|||
full_name: new FormControl(''), |
|||
password: new FormControl('', Validators.required), |
|||
email: new FormControl('', [ |
|||
Validators.required, |
|||
Validators.pattern('^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$'), |
|||
Validators.maxLength(20), |
|||
]), |
|||
username: new FormControl('', [Validators.required, Validators.maxLength(20)]), |
|||
}); |
|||
public user: any; |
|||
public error: string; |
|||
|
|||
constructor(private authService: AuthService, |
|||
private router: Router) { |
|||
|
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.user = this.authService.user; |
|||
|
|||
|
|||
this.editForm.setValue({ |
|||
full_name: this.user.full_name, |
|||
password: "", |
|||
email: this.user.email, |
|||
username: this.user.username |
|||
}) |
|||
} |
|||
|
|||
public edit() { |
|||
if (this.editForm.valid) { |
|||
this.authService.edit(this.editForm.getRawValue()) |
|||
.subscribe(res => this.router.navigate(['/app/dashboard']), |
|||
error => this.error = error.message); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,40 @@ |
|||
|
|||
|
|||
<mat-card> |
|||
<mat-card-title> |
|||
Authenticate to Wireguard Management |
|||
</mat-card-title> |
|||
|
|||
<mat-card-content> |
|||
<form [formGroup]="loginForm" (ngSubmit)="loginForm.valid && login()" class="form"> |
|||
|
|||
<p> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>Username</mat-label> |
|||
<input type="text" id="username" formControlName="username" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
<p> |
|||
<mat-form-field class="full-width"> |
|||
<mat-label>Password</mat-label> |
|||
<input type="text" id="password" formControlName="password" matInput> |
|||
</mat-form-field> |
|||
</p> |
|||
|
|||
|
|||
<button [disabled]="!loginForm.valid" type="submit" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect button--colored-light-blue"> |
|||
SIGN IN |
|||
</button> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</form> |
|||
</mat-card-content> |
|||
|
|||
|
|||
</mat-card> |
|||
|
|||
|
@ -0,0 +1,25 @@ |
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { LoginComponent } from './login.component'; |
|||
|
|||
describe('LoginComponent', () => { |
|||
let component: LoginComponent; |
|||
let fixture: ComponentFixture<LoginComponent>; |
|||
|
|||
beforeEach(async(() => { |
|||
TestBed.configureTestingModule({ |
|||
declarations: [ LoginComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
})); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(LoginComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
@ -0,0 +1,53 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms"; |
|||
import {AuthService} from "@services/*"; |
|||
import {Router} from "@angular/router"; |
|||
|
|||
@Component({ |
|||
selector: 'app-login', |
|||
templateUrl: './login.component.html', |
|||
styleUrls: ['./login.component.scss'] |
|||
}) |
|||
export class LoginComponent implements OnInit { |
|||
|
|||
public loginForm: FormGroup; |
|||
public username; |
|||
public password; |
|||
public error: string; |
|||
|
|||
constructor(private authService: AuthService, |
|||
private fb: FormBuilder, |
|||
private router: Router) { |
|||
|
|||
|
|||
this.loginForm = this.fb.group({ |
|||
password: new FormControl('', Validators.required), |
|||
username: new FormControl('', [ |
|||
Validators.required, |
|||
]), |
|||
}); |
|||
this.username = this.loginForm.get('username'); |
|||
this.password = this.loginForm.get('password'); |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.authService.logout(); |
|||
this.loginForm.valueChanges.subscribe(() => { |
|||
this.error = null; |
|||
}); |
|||
} |
|||
|
|||
public login() { |
|||
this.error = null; |
|||
if (this.loginForm.valid) { |
|||
this.authService.login(this.loginForm.getRawValue()) |
|||
.subscribe(res => this.router.navigate(['/page/dashboard']), |
|||
error => this.error = error.message); |
|||
} |
|||
} |
|||
|
|||
public onInputChange(event) { |
|||
event.target.required = true; |
|||
} |
|||
|
|||
} |
@ -1,2 +0,0 @@ |
|||
|
|||
|
@ -1,20 +0,0 @@ |
|||
<div class="mdl-card mdl-card__blank-layout-card mdl-shadow--2dp"> |
|||
<div class="mdl-card__supporting-text color--dark-gray"> |
|||
<div class="mdl-grid"> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<span class="mdl-card__title-text text-color--smooth-gray">DARKBOARD</span> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<span class="text--huge color-text--light-blue">404</span> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<span class="text--sorry text-color--white">Sorry, but there's nothing here</span> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<a routerLink="/" class="mdl-button mdl-js-button color-text--light-blue pull-right"> |
|||
Go Back |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -1,10 +0,0 @@ |
|||
import { Component, HostBinding } from '@angular/core'; |
|||
|
|||
import { BlankLayoutCardComponent } from 'app/components/blank-layout-card'; |
|||
|
|||
@Component({ |
|||
selector: 'app-error', |
|||
styleUrls: ['../../../components/blank-layout-card/blank-layout-card.component.scss'], |
|||
templateUrl: './error.component.html', |
|||
}) |
|||
export class ErrorComponent extends BlankLayoutCardComponent { } |
@ -1,27 +0,0 @@ |
|||
<div class="mdl-card mdl-card__blank-layout-card mdl-shadow--2dp"> |
|||
<div class="mdl-card__supporting-text color--dark-gray"> |
|||
<div class="mdl-grid"> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<span class="mdl-card__title-text text-color--smooth-gray">DARKBOARD</span> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<span class="blank-layout-card-name text-color--white">Forgot password?</span> |
|||
<span class="blank-layout-card-secondary-text text-color--smoke">Enter your email below to recieve your password</span> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label full-size"> |
|||
<input class="mdl-textfield__input" type="text" id="e-mail"> |
|||
<label class="mdl-textfield__label" for="e-mail">Email</label> |
|||
</div> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone submit-cell"> |
|||
<div class="mdl-layout-spacer"></div> |
|||
<a routerLink="/app/dashboard"> |
|||
<button class="mdl-button mdl-js-button mdl-button--raised color--light-blue"> |
|||
SEND PASSWORD |
|||
</button> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -1,10 +0,0 @@ |
|||
import { Component, HostBinding } from '@angular/core'; |
|||
|
|||
import { BlankLayoutCardComponent } from 'app/components/blank-layout-card'; |
|||
|
|||
@Component({ |
|||
selector: 'app-forgot-password', |
|||
styleUrls: ['../../../components/blank-layout-card/blank-layout-card.component.scss'], |
|||
templateUrl: './forgot-password.component.html', |
|||
}) |
|||
export class ForgotPasswordComponent extends BlankLayoutCardComponent { } |
@ -1 +0,0 @@ |
|||
export { ForgotPasswordComponent } from './forgot-password.component'; |
@ -1 +0,0 @@ |
|||
export { PagesModule } from './pages.module'; |
@ -1,30 +0,0 @@ |
|||
import { ModuleWithProviders, NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
|
|||
import { LayoutsModule } from 'app/layouts'; |
|||
import { BlankLayoutComponent } from 'app/layouts/blank-layout'; |
|||
import { ErrorComponent } from './error'; |
|||
import { ForgotPasswordComponent } from './forgot-password'; |
|||
import { LoginComponent } from './login'; |
|||
import { SignUpComponent } from './sign-up'; |
|||
|
|||
@NgModule({ |
|||
imports: [ |
|||
RouterModule.forChild([ |
|||
{ |
|||
path: '', |
|||
component: BlankLayoutComponent, |
|||
children: [ |
|||
{ path: '404', component: ErrorComponent, pathMatch: 'full' }, |
|||
{ path: 'login', component: LoginComponent, pathMatch: 'full' }, |
|||
{ path: 'sign-up', component: SignUpComponent, pathMatch: 'full' }, |
|||
{ path: 'forgot-password', component: ForgotPasswordComponent, pathMatch: 'full' }, |
|||
{ path: '**', redirectTo: '404' }, |
|||
], |
|||
}, |
|||
]), |
|||
LayoutsModule, |
|||
], |
|||
exports: [RouterModule], |
|||
}) |
|||
export class PagesRoutingModule { } |
@ -1,30 +0,0 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { NgModule } from '@angular/core'; |
|||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; |
|||
|
|||
import { ThemeModule } from 'theme'; |
|||
|
|||
import { TooltipModule } from '../../../theme/directives/tooltip/tooltip.module'; |
|||
import { ErrorComponent } from './error'; |
|||
import { ForgotPasswordComponent } from './forgot-password'; |
|||
|
|||
import { PagesRoutingModule } from './pages-routing.module'; |
|||
import { SignUpComponent } from './sign-up'; |
|||
|
|||
|
|||
@NgModule({ |
|||
imports: [ |
|||
CommonModule, |
|||
ThemeModule, |
|||
PagesRoutingModule, |
|||
FormsModule, |
|||
ReactiveFormsModule, |
|||
TooltipModule, |
|||
], |
|||
declarations: [ |
|||
ErrorComponent, |
|||
SignUpComponent, |
|||
ForgotPasswordComponent, |
|||
], |
|||
}) |
|||
export class PagesModule { } |
@ -1 +0,0 @@ |
|||
export { SignUpComponent } from './sign-up.component'; |
@ -1,73 +0,0 @@ |
|||
<div class="mdl-card mdl-card__blank-layout-card mdl-shadow--2dp"> |
|||
<div class="mdl-card__supporting-text color--dark-gray"> |
|||
<div class="mdl-grid"> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<span class="mdl-card__title-text text-color--smooth-gray">DARKBOARD</span> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<span class="blank-layout-card-name text-color--white">Sign up</span> |
|||
</div> |
|||
<form class="login-form" [formGroup]="signupForm" (submit)="login()" novalidate autocomplete="off"> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone"> |
|||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label full-size" |
|||
[class.is-invalid]="username.invalid && (username.dirty || username.touched)" |
|||
[class.is-valid]="username.valid && (username.dirty || username.touched)"> |
|||
<input formControlName="username" |
|||
(change)="onInputChange($event)" |
|||
class="mdl-textfield__input" type="text" id="username"> |
|||
<label class="mdl-textfield__label" for="username">Name</label> |
|||
|
|||
<div *ngIf="username.invalid && (username.dirty || username.touched)"> |
|||
<span *ngIf="username.errors.required" class="mdl-textfield__error"> |
|||
Name is required. <span class="color-text--orange"> Please, write any name.</span> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label full-size" |
|||
[class.is-invalid]="password.invalid && (password.dirty || password.touched)" |
|||
[class.is-valid]="password.valid && (password.dirty || password.touched)" id="forRass"> |
|||
<input formControlName="password" |
|||
(change)="onInputChange($event)" |
|||
class="mdl-textfield__input" type="password" id="password"> |
|||
<label class="mdl-textfield__label" for="password">Password</label> |
|||
<div *ngIf="password.invalid && (password.dirty || password.touched)"> |
|||
<span *ngIf="password.errors.required" class="mdl-textfield__error"> |
|||
Password is required. <span class="color-text--orange"> Please, write any password.</span> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label full-size" |
|||
[class.is-invalid]="email.invalid && (email.dirty || email.touched)" |
|||
[class.is-valid]="email.valid && (email.dirty || email.touched)"> |
|||
<input formControlName="email" |
|||
pattern="{{emailPattern}}" |
|||
(change)="onInputChange($event)" |
|||
class="mdl-textfield__input" type="text" id="email"> |
|||
<label class="mdl-textfield__label" for="email">Email</label> |
|||
|
|||
<div *ngIf="email.invalid && (email.dirty || email.touched)"> |
|||
<span *ngIf="email.errors.required" class="mdl-textfield__error"> |
|||
Email is required. <span class="color-text--orange"> Please, write any valid email.</span> |
|||
</span> |
|||
<span *ngIf="email.errors.pattern" class="mdl-textfield__error"> |
|||
Email is invalid. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<label baseCheckbox color="light-blue" class="checkbox--inline" inline></label> |
|||
<span class="blank-layout-card-link">I agree all statements in <a href="#" |
|||
class="underlined">terms of service</a></span> |
|||
</div> |
|||
<div class="mdl-cell mdl-cell--12-col mdl-cell--4-col-phone submit-cell"> |
|||
<a routerLink="/pages/login" class="blank-layout-card-link">I have already signed up</a> |
|||
<div class="mdl-layout-spacer"></div> |
|||
<button class="mdl-button mdl-js-button mdl-button--raised color--light-blue" |
|||
type="submit" [disabled]="signupForm.invalid"> |
|||
SIGN UP |
|||
</button> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -1,61 +0,0 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; |
|||
import { Router } from '@angular/router'; |
|||
|
|||
import { AuthService } from '@services/*'; |
|||
|
|||
import { BlankLayoutCardComponent } from 'app/components/blank-layout-card'; |
|||
|
|||
@Component({ |
|||
selector: 'app-sign-up', |
|||
styleUrls: ['../../../components/blank-layout-card/blank-layout-card.component.scss'], |
|||
templateUrl: './sign-up.component.html', |
|||
}) |
|||
export class SignUpComponent extends BlankLayoutCardComponent implements OnInit { |
|||
|
|||
public signupForm: FormGroup; |
|||
public email; |
|||
public password; |
|||
public username; |
|||
public emailPattern = '^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$'; |
|||
public error: string; |
|||
|
|||
constructor(private authService: AuthService, |
|||
private fb: FormBuilder, |
|||
private router: Router) { |
|||
super(); |
|||
|
|||
this.signupForm = this.fb.group({ |
|||
password: new FormControl('', Validators.required), |
|||
email: new FormControl('', [ |
|||
Validators.required, |
|||
Validators.pattern(this.emailPattern), |
|||
Validators.maxLength(20), |
|||
]), |
|||
username: new FormControl('', [Validators.required, Validators.maxLength(10)]), |
|||
}); |
|||
this.email = this.signupForm.get('email'); |
|||
this.password = this.signupForm.get('password'); |
|||
this.username = this.signupForm.get('username'); |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.authService.logout(); |
|||
this.signupForm.valueChanges.subscribe(() => { |
|||
this.error = null; |
|||
}); |
|||
} |
|||
|
|||
public login() { |
|||
this.error = null; |
|||
if (this.signupForm.valid) { |
|||
this.authService.signup(this.signupForm.getRawValue()) |
|||
.subscribe(res => this.router.navigate(['/app/dashboard']), |
|||
error => this.error = error.message); |
|||
} |
|||
} |
|||
|
|||
public onInputChange(event) { |
|||
event.target.required = true; |
|||
} |
|||
} |
@ -1,6 +0,0 @@ |
|||
@import '~material-design-lite/src/functions'; |
|||
@import '~material-design-lite/src/variables'; |
|||
@import '~material-design-lite/src/mixins'; |
|||
@import '~material-design-lite/src/color-definitions'; |
|||
@import './scss/variables'; |
|||
@import './scss/mixins'; |
@ -1,14 +0,0 @@ |
|||
import { Component, HostBinding, Input, ViewChild, ViewContainerRef } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'base-card base-card-actions', |
|||
styleUrls: ['./card.component.scss'], |
|||
template: `<ng-content></ng-content>`, |
|||
}) |
|||
export class CardActionsComponent { |
|||
@HostBinding('class.mdl-card__actions') private readonly mdlCardActions = true; |
|||
|
|||
constructor( |
|||
private viewContainerRef: ViewContainerRef, |
|||
) { } |
|||
} |
@ -1,18 +0,0 @@ |
|||
import { Component, HostBinding, Input, ViewChild } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'base-card base-card-body', |
|||
styleUrls: ['./card.component.scss'], |
|||
template: `<ng-content></ng-content>`, |
|||
}) |
|||
export class CardBodyComponent { |
|||
@HostBinding('class.mdl-card__supporting-text') private readonly mdlCardSupportingText = true; |
|||
|
|||
@HostBinding('class.mdl-card--expand') private isExpanded = false; |
|||
|
|||
@Input() set expanded(value) { |
|||
if (value || value === '') { |
|||
this.isExpanded = true; |
|||
} |
|||
} |
|||
} |
@ -1,10 +0,0 @@ |
|||
import { Component, HostBinding, Input, ViewChild, ViewContainerRef } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'base-card base-card-menu', |
|||
styleUrls: ['./card.component.scss'], |
|||
template: `<ng-content></ng-content>`, |
|||
}) |
|||
export class CardMenuComponent { |
|||
@HostBinding('class.mdl-card__menu') private readonly mdlCardMenu = true; |
|||
} |
@ -1,21 +0,0 @@ |
|||
import { Component, HostBinding, Input, ViewChild } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'base-card base-card-title', |
|||
styleUrls: ['./card.component.scss'], |
|||
template: `<ng-content></ng-content>`, |
|||
}) |
|||
export class CardTitleComponent { |
|||
@HostBinding('class.mdl-card__title') private readonly mdlCardTitle = true; |
|||
@HostBinding('class.mdl-card--border') private readonly mdlCardBorder = true; |
|||
|
|||
|
|||
|
|||
@HostBinding('class.mdl-card--expand') private isExpanded = false; |
|||
|
|||
@Input() set expanded(value) { |
|||
if (value || value === '') { |
|||
this.isExpanded = true; |
|||
} |
|||
} |
|||
} |
@ -1,20 +0,0 @@ |
|||
@import '~theme/helpers'; |
|||
|
|||
.mdl-card__title { |
|||
background-color: $card-title-background-color; |
|||
} |
|||
|
|||
.mdl-card__supporting-text { |
|||
line-height: 22px; |
|||
width: calc(100% - #{$card-horizontal-padding*2}); |
|||
overflow: visible; |
|||
} |
|||
|
|||
.mdl-card__actions { |
|||
padding: 8px 16px; |
|||
} |
|||
|
|||
.mdl-card { |
|||
height: 100%; |
|||
overflow: visible; |
|||
} |
@ -1,15 +0,0 @@ |
|||
import { Component, HostBinding, Input, ViewChild, ViewContainerRef } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'base-card', |
|||
styleUrls: ['./card.component.scss'], |
|||
template: `<ng-content></ng-content>`, |
|||
}) |
|||
export class CardComponent { |
|||
@HostBinding('class.mdl-card') private readonly mdlCard = true; |
|||
@HostBinding('class.mdl-shadow--2dp') private readonly mdlShadow2DP = true; |
|||
|
|||
constructor( |
|||
private viewContainerRef: ViewContainerRef, |
|||
) { } |
|||
} |
@ -1,29 +0,0 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { NgModule } from '@angular/core'; |
|||
|
|||
import { CardActionsComponent } from './card-actions.component'; |
|||
import { CardBodyComponent } from './card-body.component'; |
|||
import { CardMenuComponent } from './card-menu.component'; |
|||
import { CardTitleComponent } from './card-title.component'; |
|||
import { CardComponent } from './card.component'; |
|||
|
|||
@NgModule({ |
|||
imports: [ |
|||
CommonModule, |
|||
], |
|||
declarations: [ |
|||
CardComponent, |
|||
CardTitleComponent, |
|||
CardMenuComponent, |
|||
CardBodyComponent, |
|||
CardActionsComponent, |
|||
], |
|||
exports: [ |
|||
CardComponent, |
|||
CardTitleComponent, |
|||
CardMenuComponent, |
|||
CardBodyComponent, |
|||
CardActionsComponent, |
|||
], |
|||
}) |
|||
export class CardModule { } |
@ -1,6 +0,0 @@ |
|||
export { CardActionsComponent } from './card-actions.component'; |
|||
export { CardBodyComponent } from './card-body.component'; |
|||
export { CardMenuComponent } from './card-menu.component'; |
|||
export { CardTitleComponent } from './card-title.component'; |
|||
export { CardComponent } from './card.component'; |
|||
export { CardModule } from './card.module'; |
@ -1,23 +0,0 @@ |
|||
import { Component, HostBinding, Input } from '@angular/core'; |
|||
|
|||
import { ToggleComponent } from 'theme/components/toggle/toggle.component'; |
|||
|
|||
@Component({ |
|||
selector: 'label[baseCheckbox]', |
|||
styleUrls: ['../toggle/toggle.component.scss'], |
|||
template: ` |
|||
<input type="checkbox" [id]="innerID" class="mdl-checkbox__input" [checked]="isChecked" (change)="isChecked = !isChecked"> |
|||
<span class="mdl-checkbox__label"><ng-content></ng-content></span> |
|||
`,
|
|||
}) |
|||
export class CheckboxComponent extends ToggleComponent { |
|||
private isInline = false; |
|||
@Input() private set inline(value) { |
|||
if (value || value === '') { |
|||
this.isInline = true; |
|||
} |
|||
} |
|||
@HostBinding('class') private get className() { |
|||
return `mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect checkbox--colored-${this.color} ${this.isInline && 'checkbox--inline'}`; |
|||
} |
|||
} |
@ -1 +0,0 @@ |
|||
export { CheckboxComponent } from './checkbox.component'; |
@ -1,17 +0,0 @@ |
|||
import { Component, HostBinding, Input } from '@angular/core'; |
|||
|
|||
import { ToggleComponent } from 'theme/components/toggle/toggle.component'; |
|||
|
|||
@Component({ |
|||
selector: 'label[baseIconToggle]', |
|||
styleUrls: ['../toggle/toggle.component.scss'], |
|||
template: ` |
|||
<input type="checkbox" [id]="innerID" class="mdl-icon-toggle__input" [checked]="isChecked" (change)="isChecked = !isChecked"> |
|||
<i class="mdl-icon-toggle__label material-icons"><ng-content></ng-content></i> |
|||
`,
|
|||
}) |
|||
export class IconToggleComponent extends ToggleComponent { |
|||
@HostBinding('class') private get className() { |
|||
return `mdl-icon-toggle mdl-js-icon-toggle mdl-js-ripple-effect icon-toggle--colored-${this.color}`; |
|||
} |
|||
} |
@ -1 +0,0 @@ |
|||
export { IconToggleComponent } from './icon-toggle.component'; |
@ -1 +0,0 @@ |
|||
export { PageTopComponent } from './page-top.component'; |
@ -1,62 +0,0 @@ |
|||
@import '~theme/helpers'; |
|||
|
|||
@media screen and (max-width: $layout-screen-size-threshold) { |
|||
.mdl-layout__header { |
|||
display: flex !important; |
|||
} |
|||
} |
|||
|
|||
.account-dropdown { |
|||
&.mdl-menu { |
|||
width: 310px; |
|||
} |
|||
|
|||
.mdl-list__item { |
|||
font-size: 1rem; |
|||
|
|||
&:first-child { |
|||
font-size: 16px; |
|||
padding-top: $list-min-padding/2; |
|||
padding-bottom: $list-min-padding/2; |
|||
height: $account-dropdown-avatar-size + $list-min-padding; |
|||
|
|||
.mdl-list__item-primary-content { |
|||
height: $account-dropdown-avatar-size; |
|||
line-height: 28px; |
|||
|
|||
.mdl-list__item-avatar { |
|||
height: $account-dropdown-avatar-size; |
|||
width: $account-dropdown-avatar-size; |
|||
background: url("#{$image-path}/Icon.png"); |
|||
background-size: cover; |
|||
} |
|||
|
|||
.mdl-list__item-sub-title { |
|||
font-weight: 300; |
|||
} |
|||
} |
|||
} |
|||
|
|||
&:hover .mdl-list__item-icon { |
|||
color: $list-icon-hover-color; |
|||
} |
|||
} |
|||
|
|||
.list__item--border-top { |
|||
margin-top: 8px; |
|||
padding-top: 8px; |
|||
} |
|||
} |
|||
|
|||
.settings-dropdown { |
|||
width: $settings_dropdown_width; |
|||
|
|||
.mdl-menu__item, |
|||
a { |
|||
@include typo-dropdown-menu-li; |
|||
} |
|||
} |
|||
|
|||
.search { |
|||
padding: 18px 0 !important; |
|||
} |
@ -1,10 +0,0 @@ |
|||
import { Component, HostBinding } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'base-page-top', |
|||
styleUrls: ['./page-top.component.scss'], |
|||
template: `<ng-content></ng-content>`, |
|||
}) |
|||
export class PageTopComponent { |
|||
@HostBinding('class.mdl-layout__header-row') protected readonly mdlLayoutHeaderRow = true; |
|||
} |
@ -1 +0,0 @@ |
|||
export { PaginationComponent } from './pagination.component'; |
@ -1,13 +0,0 @@ |
|||
<span (click)="onChangePage(-1)"><i class="material-icons">chevron_left</i></span> |
|||
<span> {{ currentPage }} of {{ numPage }} </span> |
|||
<span (click)="onChangePage(1)"><i class="material-icons">chevron_right</i></span> |
|||
<div class="goto"> |
|||
<span> Go to </span> |
|||
<form (submit)="goToPage($event)"> |
|||
<input [(ngModel)]="inputNumPage" name="inputPage" |
|||
class="mdl-textfield__input" |
|||
type="number" |
|||
min="1" |
|||
[max]="numPage"> |
|||
</form> |
|||
</div> |
@ -1,36 +0,0 @@ |
|||
@import '~theme/helpers'; |
|||
|
|||
.pagination { |
|||
font-family: Roboto, Helvetica, sans-serif; |
|||
color: $color-smooth-gray; |
|||
font-size: 14px; |
|||
position: relative; |
|||
line-height: 16px; |
|||
user-select: none; |
|||
|
|||
.material-icons { |
|||
cursor: pointer; |
|||
position: relative; |
|||
top: 0.5rem; |
|||
margin: 0 0.5rem; |
|||
} |
|||
|
|||
.goto { |
|||
display: inline-block; |
|||
margin: 0 1rem 0 2rem; |
|||
|
|||
form { |
|||
width: 30px; |
|||
display: inline-block; |
|||
|
|||
input { |
|||
text-align: center; |
|||
font-family: Roboto, Helvetica, sans-serif; |
|||
|
|||
&:focus { |
|||
outline: none; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue