profile improvements, aliases feature
This commit is contained in:
@@ -4,8 +4,9 @@
|
||||
<nav mat-tab-nav-bar>
|
||||
<a mat-tab-link routerLink="info" routerLinkActive="active">{{'info' | i18n}}</a>
|
||||
<a mat-tab-link routerLink="profile" routerLinkActive="active">{{'profile' | i18n}}</a>
|
||||
<a mat-tab-link routerLink="voucher" routerLinkActive="active">{{'vouchers' | i18n}}</a>
|
||||
<a mat-tab-link routerLink="security" routerLinkActive="active">{{'security' | i18n}}</a>
|
||||
<a mat-tab-link routerLink="voucher" routerLinkActive="active">{{'vouchers' | i18n}}</a>
|
||||
<a mat-tab-link routerLink="aliases" routerLinkActive="active">{{'user.aliases' | i18n}}</a>
|
||||
</nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
@@ -0,0 +1,77 @@
|
||||
<h3>{{'user.aliases' | i18n}}</h3>
|
||||
|
||||
<table mat-table matSort [dataSource]="aliases" (matSortChange)="sortData($event)">
|
||||
|
||||
<ng-container matColumnDef="alias">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="alias"> {{'user.aliases.alias' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let alias"> {{ alias.alias}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="visibility">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="visibility"> {{'visibility' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let alias">
|
||||
<mat-select [(ngModel)]="alias.visibility" (selectionChange)="updateAlias(alias)"
|
||||
placeholder="{{'visibility' | i18n}}">
|
||||
<mat-option *ngFor="let visibility of visibilities" [value]="visibility">
|
||||
<mat-icon inline="true">{{'visibility.' + visibility + '.icon' | i18n}}</mat-icon> {{'visibility.' +
|
||||
visibility | i18n}}
|
||||
</mat-option>
|
||||
|
||||
<mat-select-trigger>
|
||||
<mat-icon inline="true">{{'visibility.' + alias.visibility + '.icon' | i18n}}</mat-icon> {{'visibility.' +
|
||||
alias.visibility | i18n}}
|
||||
</mat-select-trigger>
|
||||
</mat-select>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="delete">
|
||||
<th mat-header-cell *matHeaderCellDef class="align-right"> {{'user.aliases.delete' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let alias" class="text-right">
|
||||
<a mat-icon-button>
|
||||
<mat-icon (click)="confirmDelete(alias)">delete</mat-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="aliasesColumns"></tr>
|
||||
<tr mat-row *matRowDef="let myRowData; columns: aliasesColumns"></tr>
|
||||
</table>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="create()" #formDirective="ngForm">
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<p>{{'user.aliases.info' | i18n}}</p>
|
||||
<p *ngIf="!aliasCreation">{{'user.aliases.noQuota' | i18n}}</p>
|
||||
<div *ngIf="aliasCreation">
|
||||
<p>{{'user.aliases.left' | i18n:aliasCreation}}</p>
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'user.aliases.alias' | i18n}}" formControlName="alias"
|
||||
[(ngModel)]="alias.alias" required>
|
||||
<mat-error>
|
||||
{{'user.aliases.error' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-select [(ngModel)]="alias.visibility" formControlName="visibility" placeholder="{{'visibility' | i18n}}">
|
||||
<mat-option *ngFor="let visibility of visibilities" [value]="visibility">
|
||||
<mat-icon inline="true">{{'visibility.' + visibility + '.icon' | i18n}}</mat-icon> {{'visibility.' +
|
||||
visibility | i18n}}
|
||||
</mat-option>
|
||||
|
||||
<mat-select-trigger>
|
||||
<mat-icon inline="true">{{'visibility.' + alias.visibility + '.icon' | i18n}}</mat-icon> {{'visibility.' +
|
||||
alias.visibility | i18n}}
|
||||
</mat-select-trigger>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button *ngIf="aliasCreation && !working" mat-raised-button color="primary" [disabled]="form.invalid">
|
||||
{{'user.aliases.create' | i18n}}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,16 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mat-header-cell,
|
||||
.mat-cell {
|
||||
&.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.align-right{
|
||||
display: flex;
|
||||
padding: 21px 0;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AliasesComponent } from './aliases.component';
|
||||
|
||||
describe('AliasesComponent', () => {
|
||||
let component: AliasesComponent;
|
||||
let fixture: ComponentFixture<AliasesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ AliasesComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AliasesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,130 @@
|
||||
import {Component, OnInit, ViewChild} from '@angular/core';
|
||||
import {QuotaService} from '../../../services/quota.service';
|
||||
import {I18nService} from '../../../services/i18n.service';
|
||||
import {Sort} from '@angular/material/sort';
|
||||
import {UserAliasService} from '../../../services/useralias.service';
|
||||
import {FormBuilder, FormGroup, Validators, NgForm} from '@angular/forms';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {ConfirmDialog} from '../../../ui/confirm/confirm.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-account-aliases',
|
||||
templateUrl: './aliases.component.html',
|
||||
styleUrls: ['./aliases.component.scss']
|
||||
})
|
||||
export class AliasesComponent implements OnInit {
|
||||
|
||||
form: FormGroup;
|
||||
@ViewChild('formDirective') private formDirective: NgForm;
|
||||
aliasCreation: number = 0;
|
||||
aliases: any[] = [];
|
||||
alias: any = {
|
||||
visibility: "PROTECTED"
|
||||
};
|
||||
success: boolean;
|
||||
working: boolean;
|
||||
|
||||
aliasesColumns = ["alias", "visibility", "delete"];
|
||||
visibilities = ["PRIVATE", "PROTECTED", "PUBLIC"];
|
||||
|
||||
constructor(
|
||||
private quotaService: QuotaService,
|
||||
private formBuilder: FormBuilder,
|
||||
private userAliasService: UserAliasService,
|
||||
private i18n : I18nService,
|
||||
public dialog: MatDialog) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
alias: ['', Validators.required],
|
||||
visibility: ['', Validators.required],
|
||||
});
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
create(): void {
|
||||
this.working = true;
|
||||
this.userAliasService.create(this.alias).subscribe(response => {
|
||||
this.update();
|
||||
this.formDirective.resetForm();
|
||||
this.alias = {
|
||||
visibility: "PROTECTED"
|
||||
};
|
||||
this.working = false;
|
||||
}, (error) => {
|
||||
this.working = false;
|
||||
if(error.status == 409) {
|
||||
let errors = {};
|
||||
for(let code of error.error) {
|
||||
errors[code.field] = errors[code.field] || {};
|
||||
errors[code.field][code.code] = true;
|
||||
}
|
||||
|
||||
for(let code in errors) {
|
||||
this.form.get(code).setErrors(errors[code]);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
updateAlias(alias) {
|
||||
this.userAliasService.update(alias).subscribe((response: any) => {
|
||||
alias = response;
|
||||
})
|
||||
}
|
||||
|
||||
update() {
|
||||
this.aliasCreation = 0;
|
||||
this.quotaService.quotas().subscribe((data: any) => {
|
||||
for(let quota of data) {
|
||||
if(quota.name == "alias_creation") {
|
||||
this.aliasCreation = quota.value;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.userAliasService.get().subscribe((data: any) => {
|
||||
this.aliases = data;
|
||||
})
|
||||
}
|
||||
|
||||
confirmDelete(alias) {
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'user.aliases.confirmDelete',
|
||||
'args': [alias.alias]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if(result) {
|
||||
this.userAliasService.delete(alias.id).subscribe((result: any) => {
|
||||
this.update();
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sortData(sort: Sort) {
|
||||
const data = this.aliases.slice();
|
||||
if(!sort.active || sort.direction === '') {
|
||||
this.aliases = data;
|
||||
return;
|
||||
}
|
||||
|
||||
this.aliases = data.sort((a, b) => {
|
||||
const isAsc = sort.direction === 'asc';
|
||||
switch(sort.active) {
|
||||
case 'alias': return this.compare(a.alias, b.alias, isAsc);
|
||||
case 'visibility': return this.compare(this.i18n.get('visibility.' + a.visibility, []), this.i18n.get('visibility.' + b.visibility, []), isAsc);
|
||||
default: return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
compare(a: number | string | String, b: number | string | String, isAsc: boolean) {
|
||||
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,4 @@
|
||||
<h3>{{'quotas' | i18n}}</h3>
|
||||
<app-quotas [quotas]="quotas"></app-quotas>
|
||||
<h3>{{'profile' | i18n}}</h3>
|
||||
<app-profilefields [profileFields]="profileFields"></app-profilefields>
|
||||
<app-profilefields></app-profilefields>
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { PermissionService } from './../../../services/permission.service';
|
||||
import { QuotaService } from './../../../services/quota.service';
|
||||
import { ProfileService } from './../../../services/profile.service';
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {PermissionService} from './../../../services/permission.service';
|
||||
import {QuotaService} from './../../../services/quota.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-account-info',
|
||||
@@ -12,9 +11,8 @@ export class InfoComponent implements OnInit {
|
||||
|
||||
permissions = [];
|
||||
quotas = [];
|
||||
profileFields = [];
|
||||
|
||||
constructor(private permissionService: PermissionService, private quotaService: QuotaService, private profileService : ProfileService) { }
|
||||
constructor(private permissionService: PermissionService, private quotaService: QuotaService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.permissionService.permissions().subscribe((data: any) => {
|
||||
@@ -25,9 +23,6 @@ export class InfoComponent implements OnInit {
|
||||
this.quotas = data;
|
||||
})
|
||||
|
||||
this.profileService.getAll().subscribe((data: any) => {
|
||||
this.profileFields = data;
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<app-profilefields [profileFields]="profileFields" [edit]="true"></app-profilefields>
|
||||
<app-profilefields [edit]="true"></app-profilefields>
|
||||
@@ -1,6 +1,4 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ProfileService} from '../../../services/profile.service';
|
||||
import {I18nService} from '../../../services/i18n.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-account-profile',
|
||||
@@ -9,16 +7,11 @@ import {I18nService} from '../../../services/i18n.service';
|
||||
})
|
||||
export class ProfileComponent implements OnInit {
|
||||
|
||||
profileFields = [];
|
||||
types = ["TEXT", "NUMBER", "DATE", "URL", "EMAIL", "BOOL"];
|
||||
visibilities = ["PRIVATE", "PROTECTED", "PUBLIC"];
|
||||
|
||||
constructor(private profileService: ProfileService, private i18n: I18nService) {}
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.profileService.getAll().subscribe((data: any) => {
|
||||
this.profileFields = data;
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ export class SecurityComponent implements OnInit {
|
||||
passwordForm: FormGroup;
|
||||
statusForm: FormGroup;
|
||||
@ViewChild('passwordFormDirective') private passwordFormDirective: NgForm;
|
||||
@ViewChild('statusFormDirective') private statusFormDirective: NgForm;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
|
||||
<mat-slide-toggle formControlName="primaryEmail" [(ngModel)]="model.primaryEmail"
|
||||
(change)="onPrimaryChange()">
|
||||
{{'email.primary' | i18n}} <mat-icon inline=true
|
||||
matTooltip="{{'email.primary.hint' | i18n:model.username}}">info</mat-icon>
|
||||
{{'email.primary' | i18n}}
|
||||
</mat-slide-toggle>
|
||||
<mat-icon #primaryHint="matTooltip" (click)="primaryHint.toggle()" inline="true"
|
||||
matTooltip="{{'email.primary.hint' | i18n:model.username}}">info</mat-icon>
|
||||
|
||||
<mat-form-field *ngIf="model.primaryEmail">
|
||||
<input matInput type="email" placeholder="{{'email' | i18n}}" formControlName="email"
|
||||
|
||||
@@ -8,8 +8,8 @@ import {UserService} from './../../services/user.service';
|
||||
import {ItemService} from './../../services/item.service';
|
||||
import {I18nService} from './../../services/i18n.service';
|
||||
import {MatchingValidator} from './../../utils/matching.validator';
|
||||
import { PermissionService } from './../../services/permission.service';
|
||||
import { QuotaService } from './../../services/quota.service';
|
||||
import {PermissionService} from './../../services/permission.service';
|
||||
import {QuotaService} from './../../services/quota.service';
|
||||
|
||||
import {uniqueNamesGenerator, Config, adjectives, colors, animals} from 'unique-names-generator';
|
||||
|
||||
@@ -23,9 +23,9 @@ var openpgp = require('openpgp');
|
||||
export class RegisterComponent implements OnInit {
|
||||
|
||||
form: FormGroup;
|
||||
public missingToken: boolean;
|
||||
public success: boolean;
|
||||
public working: boolean;
|
||||
missingToken: boolean;
|
||||
success: boolean;
|
||||
working: boolean;
|
||||
items = [];
|
||||
permissions = [];
|
||||
quotas = [];
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
i18n}}</a>
|
||||
<a mat-raised-button (click)="copyKey(privkey)">{{'pgp.privateKey.copyKey' |
|
||||
i18n}}</a>
|
||||
<button mat-icon-button [matTooltip]="'pgp.privateKey.help' | i18n" matTooltipPosition="after">
|
||||
<button mat-icon-button #privateKeyHelp="matTooltip" (click)="privateKeyHelp.toggle()" [matTooltip]="'pgp.privateKey.help' | i18n" matTooltipPosition="after">
|
||||
<mat-icon>help</mat-icon>
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<h3>{{'services' | i18n}}</h3>
|
||||
|
||||
<p *ngIf="!services || services.length == 0">{{'services.empty' | i18n}}</p>
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="16px grid">
|
||||
<div fxFlex="33.33%" fxFlex.sm="50%" fxFlex.xs="100%" *ngFor="let service of services">
|
||||
<mat-card>
|
||||
|
||||
@@ -2,8 +2,14 @@
|
||||
<mat-progress-bar *ngIf="!success && !error" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<div *ngIf="success">
|
||||
<h3>{{username}}</h3>
|
||||
<app-profilefields [profileFields]="profileFields"></app-profilefields>
|
||||
<h3>{{model.username}}</h3>
|
||||
<app-profilefields [username]="model.username"></app-profilefields>
|
||||
<div *ngIf="model.aliases && model.aliases.length > 0">
|
||||
<h4>{{'user.aliases' | i18n}}</h4>
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let alias of model.aliases">{{alias}}</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-card class="warn" *ngIf="error">
|
||||
|
||||
@@ -11,20 +11,19 @@ import {ProfileService} from '../../services/profile.service';
|
||||
export class UserComponent implements OnInit {
|
||||
|
||||
username;
|
||||
profileFields = [];
|
||||
model: any;
|
||||
error = false;
|
||||
success = false;
|
||||
|
||||
constructor(
|
||||
private profileService: ProfileService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.username = this.route.snapshot.paramMap.get('username');
|
||||
this.profileService.getAllForUser(this.username).subscribe((data: any) => {
|
||||
this.profileFields = data;
|
||||
this.success = true;
|
||||
this.model = data;
|
||||
}, error => {
|
||||
this.error = error;
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user