From 43b911eb6031884ecacaffb7bb551533f8066718 Mon Sep 17 00:00:00 2001 From: Lukas Metzger Date: Mon, 9 Apr 2018 11:16:06 +0200 Subject: [PATCH] Added domains page --- frontend/src/app/apitypes/Domain.apitype.ts | 16 +++++ frontend/src/app/apitypes/List.apitype.ts | 12 ++++ frontend/src/app/apitypes/Paging.apitype.ts | 12 ++++ frontend/src/app/app.module.ts | 10 ++- .../app/datatypes/modal-options.datatype.ts | 8 ++- .../src/app/operations/domains.operations.ts | 35 ++++++++++ .../app/pages/domains/domains.component.html | 33 +++++++++- .../app/pages/domains/domains.component.ts | 65 +++++++++++++++++-- .../src/app/pages/login/login.component.html | 2 +- .../pages/password/password.component.html | 2 +- .../partials/pagesize/pagesize.component.html | 12 ++++ .../partials/pagesize/pagesize.component.scss | 0 .../partials/pagesize/pagesize.component.ts | 23 +++++++ .../app/partials/paging/paging.component.html | 21 ++++++ .../app/partials/paging/paging.component.scss | 0 .../app/partials/paging/paging.component.ts | 49 ++++++++++++++ frontend/src/app/services/http.service.ts | 4 ++ frontend/src/app/services/state.service.ts | 41 ++++++++---- frontend/src/styles.scss | 33 +++++++++- 19 files changed, 351 insertions(+), 27 deletions(-) create mode 100644 frontend/src/app/apitypes/Domain.apitype.ts create mode 100644 frontend/src/app/apitypes/List.apitype.ts create mode 100644 frontend/src/app/apitypes/Paging.apitype.ts create mode 100644 frontend/src/app/operations/domains.operations.ts create mode 100644 frontend/src/app/partials/pagesize/pagesize.component.html create mode 100644 frontend/src/app/partials/pagesize/pagesize.component.scss create mode 100644 frontend/src/app/partials/pagesize/pagesize.component.ts create mode 100644 frontend/src/app/partials/paging/paging.component.html create mode 100644 frontend/src/app/partials/paging/paging.component.scss create mode 100644 frontend/src/app/partials/paging/paging.component.ts diff --git a/frontend/src/app/apitypes/Domain.apitype.ts b/frontend/src/app/apitypes/Domain.apitype.ts new file mode 100644 index 0000000..99667b1 --- /dev/null +++ b/frontend/src/app/apitypes/Domain.apitype.ts @@ -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); + } +} diff --git a/frontend/src/app/apitypes/List.apitype.ts b/frontend/src/app/apitypes/List.apitype.ts new file mode 100644 index 0000000..de22031 --- /dev/null +++ b/frontend/src/app/apitypes/List.apitype.ts @@ -0,0 +1,12 @@ +import { PagingApitype } from './Paging.apitype'; + +export class ListApitype { + + public paging: PagingApitype; + + public results: T[] = []; + + constructor(init: Object) { + Object.assign(this, init); + } +} diff --git a/frontend/src/app/apitypes/Paging.apitype.ts b/frontend/src/app/apitypes/Paging.apitype.ts new file mode 100644 index 0000000..09123d6 --- /dev/null +++ b/frontend/src/app/apitypes/Paging.apitype.ts @@ -0,0 +1,12 @@ +export class PagingApitype { + + public page = 1; + + public total = 1; + + public pagesize: number = null; + + constructor(init: Object) { + Object.assign(this, init); + } +} diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index b5f7ce3..b617f9a 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -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] diff --git a/frontend/src/app/datatypes/modal-options.datatype.ts b/frontend/src/app/datatypes/modal-options.datatype.ts index c51e8f5..333147a 100644 --- a/frontend/src/app/datatypes/modal-options.datatype.ts +++ b/frontend/src/app/datatypes/modal-options.datatype.ts @@ -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); } } diff --git a/frontend/src/app/operations/domains.operations.ts b/frontend/src/app/operations/domains.operations.ts new file mode 100644 index 0000000..5765782 --- /dev/null +++ b/frontend/src/app/operations/domains.operations.ts @@ -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): Promise> { + try { + return new ListApitype(await this.http.get('/domains', { + page: page, + pagesize: pageSize, + query: query + })); + } catch (e) { + console.error(e); + return new ListApitype({ paging: {}, results: [] }); + } + } + + public async delete(domainId: number): Promise { + try { + await this.http.delete(['/domains', domainId.toString()]); + return true; + } catch (e) { + console.error(e); + return false; + } + } +} diff --git a/frontend/src/app/pages/domains/domains.component.html b/frontend/src/app/pages/domains/domains.component.html index a72e2fe..583408a 100644 --- a/frontend/src/app/pages/domains/domains.component.html +++ b/frontend/src/app/pages/domains/domains.component.html @@ -1,3 +1,30 @@ -

- domains works! -

+ +
+
+
+ + + + + + + + + + + + + + + + + + + +
IDNameTypeRecords
{{ domain.id }}{{ domain.name }}{{ domain.type }}{{ domain.records }} + +
+
+
+
+ \ No newline at end of file diff --git a/frontend/src/app/pages/domains/domains.component.ts b/frontend/src/app/pages/domains/domains.component.ts index 8904a62..ca0304d 100644 --- a/frontend/src/app/pages/domains/domains.component.ts +++ b/frontend/src/app/pages/domains/domains.component.ts @@ -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); + } } diff --git a/frontend/src/app/pages/login/login.component.html b/frontend/src/app/pages/login/login.component.html index 84d291e..b201063 100644 --- a/frontend/src/app/pages/login/login.component.html +++ b/frontend/src/app/pages/login/login.component.html @@ -30,7 +30,7 @@ Username or password is invalid! - + diff --git a/frontend/src/app/pages/password/password.component.html b/frontend/src/app/pages/password/password.component.html index b0d727a..3422d87 100644 --- a/frontend/src/app/pages/password/password.component.html +++ b/frontend/src/app/pages/password/password.component.html @@ -23,7 +23,7 @@ Password change sucessfull. - + \ No newline at end of file diff --git a/frontend/src/app/partials/pagesize/pagesize.component.html b/frontend/src/app/partials/pagesize/pagesize.component.html new file mode 100644 index 0000000..88747ed --- /dev/null +++ b/frontend/src/app/partials/pagesize/pagesize.component.html @@ -0,0 +1,12 @@ +
+ +
\ No newline at end of file diff --git a/frontend/src/app/partials/pagesize/pagesize.component.scss b/frontend/src/app/partials/pagesize/pagesize.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/partials/pagesize/pagesize.component.ts b/frontend/src/app/partials/pagesize/pagesize.component.ts new file mode 100644 index 0000000..d8a545e --- /dev/null +++ b/frontend/src/app/partials/pagesize/pagesize.component.ts @@ -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; + + @Input() currentPagesize: number; + + @Output() pagesizeChange = new EventEmitter(); + + constructor() { + } + + public newPagesize(pagesize: number) { + this.pagesizeChange.emit(pagesize); + } +} diff --git a/frontend/src/app/partials/paging/paging.component.html b/frontend/src/app/partials/paging/paging.component.html new file mode 100644 index 0000000..97ca01c --- /dev/null +++ b/frontend/src/app/partials/paging/paging.component.html @@ -0,0 +1,21 @@ +
+ +
\ No newline at end of file diff --git a/frontend/src/app/partials/paging/paging.component.scss b/frontend/src/app/partials/paging/paging.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/partials/paging/paging.component.ts b/frontend/src/app/partials/paging/paging.component.ts new file mode 100644 index 0000000..ef6469c --- /dev/null +++ b/frontend/src/app/partials/paging/paging.component.ts @@ -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(); + + constructor() { } + + public createNumbers(): Array { + 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); + } +} diff --git a/frontend/src/app/services/http.service.ts b/frontend/src/app/services/http.service.ts index 9929c0a..401672c 100644 --- a/frontend/src/app/services/http.service.ts +++ b/frontend/src/app/services/http.service.ts @@ -18,6 +18,10 @@ export class HttpService { public async get(url: string, params: Object = {}): Promise { 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(','); diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 223f39e..fe2b84d 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -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 { + 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'))); } } diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 66f08ce..30404c4 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -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; -} \ No newline at end of file +} + +/* Cursor pointer class */ +.cursor-pointer { + cursor: pointer; +}