add search + note

This commit is contained in:
_Bastler 2021-06-06 17:09:09 +02:00
parent a69647ffde
commit 57d2bf97fb
14 changed files with 60 additions and 22 deletions

View File

@ -1,15 +1,18 @@
import { Directive, OnInit } from '@angular/core'; import { Directive, ElementRef, OnInit } from '@angular/core';
import { MatInput } from '@angular/material/input'; import { MatInput } from '@angular/material/input';
@Directive({ @Directive({
selector: '[matInputAutofocus]', selector: '[matAutofocus]',
}) })
export class AutofocusDirective implements OnInit { export class AutofocusDirective implements OnInit {
constructor(private matInput: MatInput) { } constructor(private element: ElementRef) { }
ngOnInit() { ngOnInit() {
setTimeout(() => this.matInput.focus()); setTimeout(() => {
this.element.nativeElement.focus();
this.element.nativeElement.scrollIntoView();
})
} }
} }

View File

@ -8,7 +8,7 @@
{{'security.2fa.totp.invalid' | i18n}} {{'security.2fa.totp.invalid' | i18n}}
</mat-error> </mat-error>
<mat-form-field> <mat-form-field>
<input id="code" name="code" matInput placeholder="{{'security.2fa.totp.code' | i18n}}" required matInputAutofocus> <input id="code" name="code" matInput placeholder="{{'security.2fa.totp.code' | i18n}}" required matAutofocus>
<mat-error> <mat-error>
{{'security.2fa.totp.missing' | i18n}} {{'security.2fa.totp.missing' | i18n}}
</mat-error> </mat-error>

View File

@ -8,7 +8,7 @@
{{'login.invalid' | i18n}} {{'login.invalid' | i18n}}
</mat-error> </mat-error>
<mat-form-field> <mat-form-field>
<input id="username" name="username" matInput placeholder="{{'username' | i18n}}" required matInputAutofocus> <input id="username" name="username" matInput placeholder="{{'username' | i18n}}" required matAutofocus>
<mat-error> <mat-error>
{{'username.missing' | i18n}} {{'username.missing' | i18n}}
</mat-error> </mat-error>

View File

@ -7,7 +7,7 @@
</mat-error> </mat-error>
<mat-form-field> <mat-form-field>
<input id="code" name="code" matInput placeholder="{{'security.2fa.totp.code' | i18n}}" formControlName="code" <input id="code" name="code" matInput placeholder="{{'security.2fa.totp.code' | i18n}}" formControlName="code"
required matInputAutofocus> required matAutofocus>
<mat-error> <mat-error>
{{'security.2fa.totp.missing' | i18n}} {{'security.2fa.totp.missing' | i18n}}
</mat-error> </mat-error>

View File

@ -7,7 +7,7 @@
</mat-error> </mat-error>
<mat-form-field> <mat-form-field>
<input id="username" name="username" matInput placeholder="{{'username' | i18n}}" <input id="username" name="username" matInput placeholder="{{'username' | i18n}}"
formControlName="username" required matInputAutofocus> formControlName="username" required matAutofocus>
<mat-error> <mat-error>
{{'username.missing' | i18n}} {{'username.missing' | i18n}}
</mat-error> </mat-error>

View File

@ -7,7 +7,7 @@
</mat-error> </mat-error>
<mat-form-field> <mat-form-field>
<input matInput placeholder="{{'username' | i18n}}" formControlName="username" <input matInput placeholder="{{'username' | i18n}}" formControlName="username"
[(ngModel)]="model.username" required matInputAutofocus> [(ngModel)]="model.username" required matAutofocus>
<mat-error> <mat-error>
{{'username.error' | i18n}} {{'username.error' | i18n}}
</mat-error> </mat-error>

View File

@ -1,7 +1,8 @@
<h3>{{'services' | i18n}}</h3> <h3>{{'services' | i18n}}</h3>
<p *ngIf="!services || services.length == 0">{{'services.empty' | i18n}}</p> <mat-progress-bar *ngIf="!services" mode="indeterminate"></mat-progress-bar>
<p *ngIf="services && services.length == 0">{{'services.empty' | i18n}}</p>
<table *ngIf="services && services.length > 0" mat-table matSort [dataSource]="services" (matSortChange)="sortData($event)" matSortActive="name" matSortDirection="asc"> <table *ngIf="services && services.length > 0" mat-table matSort [dataSource]="services" (matSortChange)="sortData($event)" matSortActive="name" matSortDirection="asc">

View File

@ -10,7 +10,7 @@ import {I18nService} from '../../services/i18n.service';
}) })
export class ServicesComponent implements OnInit { export class ServicesComponent implements OnInit {
services = []; services;
serviceColumns = ["icon", "name", "text"]; serviceColumns = ["icon", "name", "text"];
constructor(private serviceService: ServiceService, private i18n: I18nService) {} constructor(private serviceService: ServiceService, private i18n: I18nService) {}

View File

@ -9,7 +9,7 @@
{{'tokens.redeemed' | i18n}} {{'tokens.redeemed' | i18n}}
</mat-error> </mat-error>
<mat-form-field> <mat-form-field>
<input matInput placeholder="{{'token' | i18n}}" formControlName="token" matInputAutofocus> <input matInput placeholder="{{'token' | i18n}}" formControlName="token" matAutofocus>
<mat-error> <mat-error>
{{'tokens.provide-valid' | i18n}} {{'tokens.provide-valid' | i18n}}
</mat-error> </mat-error>

View File

@ -1,6 +1,9 @@
<h3>{{'urlshortener' | i18n}}</h3> <h3>{{'urlshortener' | i18n}}</h3>
<div *ngIf="shortenedUrls"> <div *ngIf="shortenedUrls">
<mat-form-field>
<input matInput [formControl]="searchFormControl" placeholder="{{'urlshortener.search' | i18n}}">
</mat-form-field>
<table mat-table matSort [dataSource]="shortenedUrls.content" (matSortChange)="updateSort($event)"> <table mat-table matSort [dataSource]="shortenedUrls.content" (matSortChange)="updateSort($event)">
<ng-container matColumnDef="share"> <ng-container matColumnDef="share">
@ -80,6 +83,14 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field>
<textarea matInput type="note" placeholder="{{'urlshortener.note' | i18n}}" formControlName="note"
[(ngModel)]="shortenedUrl.note"></textarea>
<mat-error>
{{'urlshortener.error.note' | i18n}}
</mat-error>
</mat-form-field>
<mat-expansion-panel> <mat-expansion-panel>
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
@ -95,6 +106,7 @@
</div> </div>
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<input matInput type="password" placeholder="{{'password.confirm' | i18n}}" formControlName="password2" <input matInput type="password" placeholder="{{'password.confirm' | i18n}}" formControlName="password2"
[(ngModel)]="shortenedUrl.password2"> [(ngModel)]="shortenedUrl.password2">

View File

@ -1,7 +1,7 @@
import {Component, OnInit, ViewChild, Inject} from '@angular/core'; import {Component, OnInit, ViewChild, Inject} from '@angular/core';
import {MatSnackBar} from '@angular/material/snack-bar'; import {MatSnackBar} from '@angular/material/snack-bar';
import {Sort} from '@angular/material/sort'; import {Sort} from '@angular/material/sort';
import {FormBuilder, FormGroup, Validators, NgForm} from '@angular/forms'; import {FormBuilder, FormGroup, Validators, NgForm, FormControl} from '@angular/forms';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import {PageEvent} from '@angular/material/paginator'; import {PageEvent} from '@angular/material/paginator';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
@ -12,6 +12,7 @@ import {UrlShortenerService} from '../../services/urlshortener.service';
import {ConfirmDialog} from '../../ui/confirm/confirm.component'; import {ConfirmDialog} from '../../ui/confirm/confirm.component';
import {I18nService} from '../../services/i18n.service'; import {I18nService} from '../../services/i18n.service';
import {environment} from '../../../environments/environment'; import {environment} from '../../../environments/environment';
import {debounceTime} from 'rxjs/operators';
@Component({ @Component({
selector: 'app-urlshortener', selector: 'app-urlshortener',
@ -22,13 +23,14 @@ export class UrlShortenerComponent implements OnInit {
form: FormGroup; form: FormGroup;
@ViewChild('formDirective') private formDirective: NgForm; @ViewChild('formDirective') private formDirective: NgForm;
searchFormControl = new FormControl();
shortenedUrlQuota: number = 0; shortenedUrlQuota: number = 0;
shortenedUrls: any; shortenedUrls: any;
shortenedUrl: any = {}; shortenedUrl: any = {};
success: boolean; success: boolean;
working: boolean; working: boolean;
datetimeformat: String; datetimeformat: String;
page: any = {page: 0, size: 10, sort: "code", desc: false}; page: any = {page: 0, size: 10, sort: "code", desc: false, search: ""};
pageSizeOptions: number[] = [5, 10, 25, 50]; pageSizeOptions: number[] = [5, 10, 25, 50];
shortenedUrlColumns = ["share", "link", "note", "url", "expires", "delete"]; shortenedUrlColumns = ["share", "link", "note", "url", "expires", "delete"];
@ -45,6 +47,7 @@ export class UrlShortenerComponent implements OnInit {
this.form = this.formBuilder.group({ this.form = this.formBuilder.group({
url: ['', Validators.required], url: ['', Validators.required],
note: ['', Validators.nullValidator],
code: ['', Validators.nullValidator], code: ['', Validators.nullValidator],
password: ['', Validators.nullValidator], password: ['', Validators.nullValidator],
password2: ['', Validators.nullValidator], password2: ['', Validators.nullValidator],
@ -53,6 +56,14 @@ export class UrlShortenerComponent implements OnInit {
validator: MatchingValidator('password', 'password2') validator: MatchingValidator('password', 'password2')
}); });
this.searchFormControl.valueChanges.pipe(debounceTime(500)).subscribe(value => {
this.page.search = this.searchFormControl.value ? this.searchFormControl.value : "";
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.page.search).subscribe((data: any) => {
this.shortenedUrls = data;
})
})
this.update(); this.update();
} }
@ -90,15 +101,25 @@ export class UrlShortenerComponent implements OnInit {
} }
}) })
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc).subscribe((data: any) => { this.page.search = this.searchFormControl.value ? this.searchFormControl.value : "";
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.page.search).subscribe((data: any) => {
this.shortenedUrls = data; this.shortenedUrls = data;
}) })
} }
updateSearch() {
this.page.search = this.searchFormControl.value ? this.searchFormControl.value : "";
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.page.search).subscribe((data: any) => {
this.shortenedUrls = data;
}, (error) => {})
}
updatePages(event: PageEvent) { updatePages(event: PageEvent) {
this.page.page = event.pageIndex; this.page.page = event.pageIndex;
this.page.size = event.pageSize; this.page.size = event.pageSize;
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc).subscribe((data: any) => { this.page.search = this.searchFormControl.value ? this.searchFormControl.value : "";
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.page.search).subscribe((data: any) => {
this.shortenedUrls = data; this.shortenedUrls = data;
}, (error) => {}) }, (error) => {})
} }
@ -111,7 +132,8 @@ export class UrlShortenerComponent implements OnInit {
this.page.sort = sort.active; this.page.sort = sort.active;
this.page.desc = sort.direction == "desc"; this.page.desc = sort.direction == "desc";
} }
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc).subscribe((data: any) => { this.page.search = this.searchFormControl.value ? this.searchFormControl.value : "";
this.urlShortenerService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.page.search).subscribe((data: any) => {
this.shortenedUrls = data; this.shortenedUrls = data;
}, (error) => {}) }, (error) => {})
} }
@ -191,7 +213,7 @@ export class UrlShortenerShareDialog {
}) })
export class UrlShortenerPasswordComponent implements OnInit { export class UrlShortenerPasswordComponent implements OnInit {
code : string; code: string;
apiUrl = environment.apiUrl; apiUrl = environment.apiUrl;
invalidPassword: boolean = false; invalidPassword: boolean = false;

View File

@ -4,7 +4,7 @@
<h2>{{'urlshortener.password' | i18n}} <h2>{{'urlshortener.password' | i18n}}
</h2> </h2>
<mat-form-field> <mat-form-field>
<input id="password" name="password" matInput type="password" placeholder="{{'password' | i18n}}" required matInputAutofocus> <input id="password" name="password" matInput type="password" placeholder="{{'password' | i18n}}" required matAutofocus>
</mat-form-field> </mat-form-field>
<mat-error *ngIf="invalidPassword"> <mat-error *ngIf="invalidPassword">
{{'urlshortener.password.invalid' | i18n}} {{'urlshortener.password.invalid' | i18n}}

View File

@ -11,8 +11,8 @@ export class UrlShortenerService {
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
} }
get(page: number, size: number, sort: string, desc: boolean) { get(page: number, size: number, sort: string, desc: boolean, search: string) {
const httpParams = new HttpParams().set("page", "" + page).set("size", "" + size).set("sort", sort).set("desc", "" + desc); const httpParams = new HttpParams().set("page", "" + page).set("size", "" + size).set("sort", sort).set("desc", "" + desc).set("search", search);
return this.http.get(environment.apiUrl + "/url/shortener", {params: httpParams}); return this.http.get(environment.apiUrl + "/url/shortener", {params: httpParams});
} }

View File

@ -2,6 +2,6 @@
{{text}} {{text}}
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<button mat-raised-button [mat-dialog-close]="true" color="accent" matAutofocus>{{'confirm' | i18n}}</button>
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button> <button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
<button mat-raised-button [mat-dialog-close]="true" color="accent">{{'confirm' | i18n}}</button>
</mat-dialog-actions> </mat-dialog-actions>