Added domains page

This commit is contained in:
Lukas Metzger 2018-04-09 11:16:06 +02:00
parent d1a32ec860
commit 43b911eb60
19 changed files with 351 additions and 27 deletions

View file

@ -0,0 +1,16 @@
export class DomainApitype {
public id = 0;
public name = '';
public type = '';
public master: string = null;
public records = 0;
constructor(init: Object) {
Object.assign(this, init);
}
}

View file

@ -0,0 +1,12 @@
import { PagingApitype } from './Paging.apitype';
export class ListApitype<T> {
public paging: PagingApitype;
public results: T[] = [];
constructor(init: Object) {
Object.assign(this, init);
}
}

View file

@ -0,0 +1,12 @@
export class PagingApitype {
public page = 1;
public total = 1;
public pagesize: number = null;
constructor(init: Object) {
Object.assign(this, init);
}
}

View file

@ -1,3 +1,6 @@
import { PagesizeComponent } from './partials/pagesize/pagesize.component';
import { PagingComponent } from './partials/paging/paging.component';
import { DomainsOperation } from './operations/domains.operations';
import { PasswordOperation } from './operations/password.operations';
import { AuthGuard } from './services/auth-guard.service';
import { FocusDirective } from './utils/Focus.directive';
@ -21,6 +24,7 @@ import { HttpService } from './services/http.service';
import { SessionOperation } from './operations/session.operation';
import { DomainsComponent } from './pages/domains/domains.component';
import { PasswordComponent } from './pages/password/password.component';
import { EditSlaveComponent } from './pages/edit-slave/edit-slave.component';
@NgModule({
declarations: [
@ -35,7 +39,10 @@ import { PasswordComponent } from './pages/password/password.component';
LoginComponent,
DomainsComponent,
FocusDirective,
PasswordComponent
PasswordComponent,
PagingComponent,
PagesizeComponent,
EditSlaveComponent
],
imports: [
BrowserModule,
@ -48,6 +55,7 @@ import { PasswordComponent } from './pages/password/password.component';
HttpService,
SessionOperation,
PasswordOperation,
DomainsOperation,
AuthGuard
],
bootstrap: [AppComponent]

View file

@ -11,7 +11,13 @@ export class ModalOptionsDatatype {
public acceptClass: 'primary';
constructor(init: Object) {
constructor(init: {
heading: string
body: string
acceptText: string
dismisText: string,
acceptClass?: string
}) {
Object.assign(this, init);
}
}

View file

@ -0,0 +1,35 @@
import { DomainApitype } from './../apitypes/Domain.apitype';
import { ListApitype } from './../apitypes/List.apitype';
import { Injectable } from '@angular/core';
import { HttpService } from '../services/http.service';
import { StateService } from '../services/state.service';
import { SessionApitype } from '../apitypes/Session.apitype';
@Injectable()
export class DomainsOperation {
constructor(private http: HttpService, private gs: StateService) { }
public async getList(page?: number, pageSize?: number, query?: string, sort?: Array<String>): Promise<ListApitype<DomainApitype>> {
try {
return new ListApitype<DomainApitype>(await this.http.get('/domains', {
page: page,
pagesize: pageSize,
query: query
}));
} catch (e) {
console.error(e);
return new ListApitype<DomainApitype>({ paging: {}, results: [] });
}
}
public async delete(domainId: number): Promise<boolean> {
try {
await this.http.delete(['/domains', domainId.toString()]);
return true;
} catch (e) {
console.error(e);
return false;
}
}
}

View file

@ -1,3 +1,30 @@
<p>
domains works!
</p>
<app-pagesize [pagesizes]="gs.pageSizes" [currentPagesize]="gs.pageSize" (pagesizeChange)="onPagesizeChange($event)"></app-pagesize>
<div class="row">
<div class="col-12">
<div class="table-responsive-lg">
<table class="table table-hover">
<thead>
<tr>
<th class="w-5">ID</th>
<th>Name</th>
<th class="w-25">Type</th>
<th class="w-15">Records</th>
<th *ngIf="gs.isAdmin" class="w-5"></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let domain of domainList" class="cursor-pointer" (click)="onDomainClick(domain)">
<td>{{ domain.id }}</td>
<td>{{ domain.name }}</td>
<td>{{ domain.type }}</td>
<td>{{ domain.records }}</td>
<td *ngIf="gs.isAdmin">
<app-fa-icon class="cursor-pointer" icon="trash" (click)="onDeleteDomain(domain)"></app-fa-icon>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<app-paging [pagingInfo]="pagingInfo" [pageWidth]="3" (pageChange)="onPageChange($event)"></app-paging>

View file

@ -1,12 +1,65 @@
import { Component } from '@angular/core';
import { ModalOptionsDatatype } from './../../datatypes/modal-options.datatype';
import { ModalService } from './../../services/modal.service';
import { StateService } from './../../services/state.service';
import { DomainApitype } from './../../apitypes/Domain.apitype';
import { PagingApitype } from './../../apitypes/Paging.apitype';
import { DomainsOperation } from './../../operations/domains.operations';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-domains',
templateUrl: './domains.component.html',
styleUrls: ['./domains.component.scss']
selector: 'app-domains',
templateUrl: './domains.component.html',
styleUrls: ['./domains.component.scss']
})
export class DomainsComponent {
export class DomainsComponent implements OnInit {
constructor() { }
public pagingInfo = new PagingApitype({});
public pageRequested = 1;
public domainList: DomainApitype[] = [];
constructor(private domains: DomainsOperation, public gs: StateService, private modal: ModalService) { }
public ngOnInit() {
this.loadData();
}
public async loadData() {
const res = await this.domains.getList(this.pageRequested, this.gs.pageSize);
this.pagingInfo = res.paging;
this.domainList = res.results;
}
public async onDeleteDomain(domain: DomainApitype) {
try {
await this.modal.showMessage(new ModalOptionsDatatype({
heading: 'Confirm deletion',
body: 'Are you shure you want to delete ' + domain.name + '?',
acceptText: 'Delete',
dismisText: 'Cancel',
acceptClass: 'danger'
}));
await this.domains.delete(domain.id);
await this.loadData();
} catch (e) {
}
}
public async onPageChange(newPage: number) {
this.pageRequested = newPage;
await this.loadData();
}
public async onPagesizeChange(pagesize: number) {
this.gs.pageSize = pagesize;
this.pageRequested = 1;
await this.loadData();
}
public async onDomainClick(domain: DomainApitype) {
alert(domain.id);
}
}

View file

@ -30,7 +30,7 @@
<app-alert-message>Username or password is invalid!</app-alert-message>
</app-alert>
<button type="submit" class="btn btn-success float-right" [disabled]="!loginForm.valid">Login</button>
<button type="submit" class="btn btn-primary float-right" [disabled]="!loginForm.valid">Login</button>
</form>
</div>
</div>

View file

@ -23,7 +23,7 @@
<app-alert-message>Password change sucessfull.</app-alert-message>
</app-alert>
<button type="submit" class="btn btn-success float-right" [disabled]="!passwordForm.valid">Change</button>
<button type="submit" class="btn btn-primary float-right" [disabled]="!passwordForm.valid">Change</button>
</form>
</div>
</div>

View file

@ -0,0 +1,12 @@
<div class="row">
<nav class="mr-3 ml-auto">
<ul class="pagination pagination-sm">
<li class="disabled page-item">
<span class="page-link">Entries per page</span>
</li>
<li *ngFor="let i of pagesizes" class="page-item" [class.active]="i === currentPagesize" (click)="newPagesize(i)">
<span class="page-link">{{ i }}</span>
</li>
</ul>
</nav>
</div>

View file

@ -0,0 +1,23 @@
import { PagingApitype } from './../../apitypes/Paging.apitype';
import { Component, Input, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-pagesize',
templateUrl: './pagesize.component.html',
styleUrls: ['./pagesize.component.scss']
})
export class PagesizeComponent {
@Input() pagesizes: Array<number>;
@Input() currentPagesize: number;
@Output() pagesizeChange = new EventEmitter<number>();
constructor() {
}
public newPagesize(pagesize: number) {
this.pagesizeChange.emit(pagesize);
}
}

View file

@ -0,0 +1,21 @@
<div *ngIf="pagingInfo.total > 1" class="row">
<nav class="mx-auto">
<ul class="pagination">
<li *ngIf="pagingInfo.page > 1" class="page-item" (click)="previous()">
<app-fa-icon class="page-link" icon="angle-left"></app-fa-icon>
</li>
<li *ngIf="truncatesLeft()" class="page-item disabled">
<app-fa-icon class="page-link" icon="ellipsis-h"></app-fa-icon>
</li>
<li *ngFor="let i of createNumbers()" class="page-item" [class.active]="i === pagingInfo.page" (click)="newPage(i)">
<span class="page-link">{{ i }}</span>
</li>
<li *ngIf="truncatesRight()" class="page-item disabled">
<app-fa-icon class="page-link" icon="ellipsis-h"></app-fa-icon>
</li>
<li *ngIf="pagingInfo.page < pagingInfo.total" class="page-item " (click)="next()">
<app-fa-icon class="page-link " icon="angle-right "></app-fa-icon>
</li>
</ul>
</nav>
</div>

View file

@ -0,0 +1,49 @@
import { PagingApitype } from './../../apitypes/Paging.apitype';
import { Component, Input, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-paging',
templateUrl: './paging.component.html',
styleUrls: ['./paging.component.scss']
})
export class PagingComponent {
@Input() pagingInfo: PagingApitype;
@Input() pageWidth = 2;
@Output() pageChange = new EventEmitter<number>();
constructor() { }
public createNumbers(): Array<number> {
const min = Math.max(1, this.pagingInfo.page - this.pageWidth);
const max = Math.min(this.pagingInfo.total, this.pagingInfo.page + this.pageWidth);
const pages = [];
for (let i = min; i <= max; i++) {
pages.push(i);
}
return pages;
}
public truncatesLeft(): boolean {
return this.pagingInfo.page - this.pageWidth > 1;
}
public truncatesRight(): boolean {
return this.pagingInfo.page + this.pageWidth < this.pagingInfo.total;
}
public previous(): void {
this.pageChange.emit(this.pagingInfo.page - 1);
}
public next(): void {
this.pageChange.emit(this.pagingInfo.page + 1);
}
public newPage(page: number) {
this.pageChange.emit(page);
}
}

View file

@ -18,6 +18,10 @@ export class HttpService {
public async get(url: string, params: Object = {}): Promise<any> {
const parts = [];
for (const [k, v] of Object.entries(params)) {
if (v === undefined || v === null) {
continue;
}
let value;
if (v instanceof Array) {
value = v.join(',');

View file

@ -1,53 +1,68 @@
import { SessionApitype } from './../apitypes/Session.apitype';
import { Injectable } from '@angular/core';
@Injectable()
export class StateService {
public _isLoggedIn = false;
private _isLoggedIn = false;
get isLoggedIn(): boolean {
return this._isLoggedIn;
}
set isLoggedIn(_isLoggedIn: boolean) {
this._isLoggedIn = _isLoggedIn;
this.saveSessionStorage();
this.saveLocalStorage();
}
public _isAdmin = false;
private _isAdmin = false;
get isAdmin(): boolean {
return this._isAdmin;
}
set isAdmin(_isAdmin: boolean) {
this._isAdmin = _isAdmin;
this.saveSessionStorage();
this.saveLocalStorage();
}
public _apiToken: string = null;
private _apiToken: string = null;
get apiToken(): string {
return this._apiToken;
}
set apiToken(_apiToken: string) {
this._apiToken = _apiToken;
this.saveSessionStorage();
this.saveLocalStorage();
}
public _isNative = false;
private _isNative = false;
get isNative(): boolean {
return this._isNative;
}
set isNative(_isNative: boolean) {
this._isNative = _isNative;
this.saveSessionStorage();
this.saveLocalStorage();
}
private _pageSize = 25;
get pageSize(): number {
return this._pageSize;
}
set pageSize(_pageSize: number) {
this._pageSize = _pageSize;
this.saveLocalStorage();
}
private _pageSizes = [5, 10, 25, 50, 100];
get pageSizes(): Array<number> {
return this._pageSizes;
}
constructor() {
this.loadSessiontorage();
this.loadLocalStorage();
}
private saveSessionStorage() {
sessionStorage.setItem('pdnsmanagerstate', JSON.stringify(this));
private saveLocalStorage() {
localStorage.setItem('pdnsmanagerstate', JSON.stringify(this));
}
private loadSessiontorage() {
Object.assign(this, JSON.parse(sessionStorage.getItem('pdnsmanagerstate')));
private loadLocalStorage() {
Object.assign(this, JSON.parse(localStorage.getItem('pdnsmanagerstate')));
}
}

View file

@ -1,4 +1,30 @@
/* Bootstrap and customizations */
$table-cell-padding: .60rem !default;
$sizes: (
0: 0%,
5: 5%,
10: 10%,
15: 15%,
20: 20%,
25: 25%,
30: 30%,
35: 35%,
40: 40%,
45: 45%,
50: 50%,
55: 55%,
60: 60%,
65: 65%,
70: 70%,
75: 75%,
80: 80%,
85: 85%,
90: 90%,
95: 95%,
100: 100%
);
@import '~bootstrap/scss/bootstrap.scss';
/* Add font awesome */
@ -26,4 +52,9 @@ $fa-font-path: "~font-awesome/fonts";
.ng-dirty.ng-valid.auto-validstate {
@extend .is-valid;
}
}
/* Cursor pointer class */
.cursor-pointer {
cursor: pointer;
}