fix
This commit is contained in:
@@ -15,6 +15,8 @@ export class ApiRoutes {
|
||||
|
||||
static SettingsAccounts = '/api/settings/accounts';
|
||||
static SettingsAccount = '/api/settings/accounts/:id';
|
||||
static SettingsAccountAccesses = '/api/settings/accounts/:id/access';
|
||||
static SettingsAccountAccess = '/api/settings/accounts/:id/access/:access';
|
||||
static SettingsAccountAccountCategory = '/api/settings/accounts/:id/category/:categoryId';
|
||||
|
||||
static SettingsItemCategories = '/api/settings/item-categories';
|
||||
|
||||
@@ -5,4 +5,6 @@ export interface AccountAccessRightModel {
|
||||
isAllowRead: boolean;
|
||||
isAllowWrite: boolean;
|
||||
isAllowManage: boolean;
|
||||
isAllowDelete: boolean;
|
||||
isOwner: boolean;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface AccountModel {
|
||||
currencyName?: string,
|
||||
type?: string,
|
||||
allowDelete: boolean,
|
||||
allowManage: boolean,
|
||||
categories?: AccountCategoryModel[],
|
||||
accessRights?: AccountAccessRightModel[],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
account-motion:nth-child(even) {
|
||||
filter: brightness(1)
|
||||
}
|
||||
|
||||
account-motion:nth-child(odd) {
|
||||
filter: brightness(1.75)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import { SettingsAccountCategoryComponent } from './settings/account/account.cat
|
||||
import { SettingsAccountComponent } from './settings/account/account.component';
|
||||
import { SettingsAccountAddComponent } from './settings/account/add.account.component';
|
||||
import { SettingsAccountEditComponent } from './settings/account/edit.account.component';
|
||||
import { SettingsAccountAccessComponent } from './settings/account/access.account.component';
|
||||
import { CurrencyService } from '../services/currency.service';
|
||||
import { ItemService } from '../services/item.service';
|
||||
import { SettingsItemCategoryComponent } from './settings/item/item.category.component';
|
||||
@@ -55,6 +56,7 @@ import { SettingsItemCategoryEditComponent } from './settings/item/edit.item.cat
|
||||
SettingsAccountComponent,
|
||||
SettingsAccountAddComponent,
|
||||
SettingsAccountEditComponent,
|
||||
SettingsAccountAccessComponent,
|
||||
|
||||
SettingsItemCategoryComponent,
|
||||
SettingsItemComponent,
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<div>
|
||||
<h2 mat-dialog-title>
|
||||
Account access rights
|
||||
</h2>
|
||||
<div mat-dialog-content>
|
||||
<form [formGroup]="editForm!" (ngSubmit)="onSubmitClick()">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label>Invite users</label>
|
||||
<div class="text-inside">
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Email</mat-label>
|
||||
<input matInput formControlName="email">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6>User rights</h6>
|
||||
<section>
|
||||
<mat-checkbox formControlName="allowWrite">
|
||||
Allow write
|
||||
</mat-checkbox>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div formArrayName="accesses">
|
||||
<div class="row" *ngFor="let access of accessRightsSorted; let i = index" [formGroupName]="i">
|
||||
<div class="col-md-6">
|
||||
<input type="hidden" formControlName="userId" />
|
||||
{{access.user.email}}
|
||||
<span *ngIf="access.isOwner" class="color-gray">(owner)</span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<mat-checkbox formControlName="allowWrite">
|
||||
Allow write
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button type="button" [disabled]="!access.isAllowDelete" class="btn-space" mat-raised-button color="primary" (click)="removeAccessRight(access)">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-dialog-actions class="mat-dialog-actions">
|
||||
<div class="mat-dialog-left">
|
||||
<div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage">
|
||||
{{errorMessage}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mat-dialog-right">
|
||||
<div class="button-bottom">
|
||||
<button type="button" mat-button (click)="closeDialog()">Cancel</button>
|
||||
<button class="btn-space" mat-raised-button color="primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-dialog-actions>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,131 @@
|
||||
// angular
|
||||
import { Component } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Inject } from '@angular/core';
|
||||
import { UntypedFormBuilder } from '@angular/forms';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { FormArray } from '@angular/forms';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { Validators } from '@angular/forms';
|
||||
|
||||
// libs
|
||||
import Swal from 'sweetalert2';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import * as ld from 'lodash';
|
||||
|
||||
// app
|
||||
import { ApiRoutes } from '../../../api-routes';
|
||||
import { AccountModel } from '../../../model/account.model';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { CurrencyService } from '../../../services/currency.service';
|
||||
import { CurrencyModel } from '../../../model/currency.model';
|
||||
import { AccountCategoryService } from '../../../services/account.category.service';
|
||||
import { AccountCategoryModel } from '../../../model/account.category.model';
|
||||
import { AccountAccessRightModel } from '../../../model/account.accessRight.model';
|
||||
import { AccountService } from '../../../services/account.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './access.account.component.html',
|
||||
styleUrls: ['./access.account.component.scss'],
|
||||
})
|
||||
export class SettingsAccountAccessComponent {
|
||||
public editForm!: UntypedFormGroup;
|
||||
public errorMessage?: string;
|
||||
public currencies?: CurrencyModel[];
|
||||
public categories?: AccountCategoryModel[];
|
||||
public types = new Map<string, string>();
|
||||
|
||||
public accessRightsSorted: AccountAccessRightModel[];
|
||||
|
||||
constructor(
|
||||
private fb: UntypedFormBuilder,
|
||||
private httpClient: HttpClient,
|
||||
private dialogRef: MatDialogRef<SettingsAccountAccessComponent>,
|
||||
private accountService: AccountService,
|
||||
@Inject(MAT_DIALOG_DATA) public account: AccountModel
|
||||
) {
|
||||
this.types = this.accountService.getTypes();
|
||||
|
||||
this.accessRightsSorted = ld.orderBy(account.accessRights!, ['isOwner', 'user.email'], ['desc', 'asc']);
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
var accesses = this.fb.array([]);
|
||||
|
||||
this.editForm = this.fb.group({
|
||||
email: [
|
||||
'',
|
||||
],
|
||||
allowWrite: [
|
||||
false,
|
||||
],
|
||||
accesses: accesses,
|
||||
});
|
||||
|
||||
this.accessRightsSorted.forEach((x, i) => {
|
||||
var g = this.fb.group({
|
||||
userId: [
|
||||
x.user.id
|
||||
],
|
||||
allowWrite: [{
|
||||
value: x.isAllowWrite,
|
||||
disabled: !x.isAllowDelete,
|
||||
}],
|
||||
});
|
||||
accesses.push(g);
|
||||
});
|
||||
}
|
||||
|
||||
removeAccessRight(accessRight: AccountAccessRightModel) {
|
||||
Swal.fire({
|
||||
title: 'Delete access ' + accessRight.user.email,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Delete',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (name) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
var url = ApiRoutes.SettingsAccountAccess
|
||||
.replace(':id', this.account.id!)
|
||||
.replace(':access', accessRight.user.id);
|
||||
|
||||
this.errorMessage = undefined;
|
||||
this.httpClient
|
||||
.delete(url, this.editForm.value)
|
||||
.subscribe(response => {
|
||||
resolve(response);
|
||||
}, error => {
|
||||
Swal.showValidationMessage(error.detail);
|
||||
reject();
|
||||
});
|
||||
|
||||
}).catch(x => {
|
||||
return false;
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading(),
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
this.dialogRef.close({ refresh: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closeDialog(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
onSubmitClick() {
|
||||
if (this.editForm.valid) {
|
||||
this.errorMessage = undefined;
|
||||
this.httpClient
|
||||
.post<AccountModel>(ApiRoutes.SettingsAccountAccesses.replace(':id', this.account.id!), this.editForm.value)
|
||||
.subscribe(response => {
|
||||
this.dialogRef.close({ refresh: true });
|
||||
}, error => {
|
||||
this.errorMessage = error.detail;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,10 @@
|
||||
<button class="btn-space" (click)="edit(account)" mat-raised-button color="primary">
|
||||
Edit
|
||||
</button>
|
||||
<button class="btn-space" *ngIf="account.allowDelete" (click)="remove(account)" mat-raised-button color="primary">
|
||||
<button class="btn-space" *ngIf="account.allowManage" (click)="access(account)" mat-raised-button color="primary">
|
||||
Access
|
||||
</button>
|
||||
<button class="btn-space" *ngIf="account.allowDelete" (click)="remove(account)" mat-raised-button color="primary">
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { AccountModel } from '../../../model/account.model';
|
||||
import { AccountCategoryModel } from '../../../model/account.category.model';
|
||||
import { SettingsAccountAddComponent } from './add.account.component';
|
||||
import { SettingsAccountEditComponent } from './edit.account.component';
|
||||
import { SettingsAccountAccessComponent } from './access.account.component';
|
||||
import { AccountCategoryService } from '../../../services/account.category.service';
|
||||
|
||||
@Component({
|
||||
@@ -106,4 +107,17 @@ export class SettingsAccountComponent {
|
||||
this.loadAccounts();
|
||||
});
|
||||
}
|
||||
|
||||
public access(account: AccountModel) {
|
||||
this.dialogModel.open(SettingsAccountAccessComponent, {
|
||||
width: '640px',
|
||||
disableClose: true,
|
||||
data: account,
|
||||
}).afterClosed().subscribe(x => {
|
||||
if (x && x.refresh) {
|
||||
this.loadAccounts();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-12">
|
||||
<div class="text-inside">
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Category</mat-label>
|
||||
@@ -55,14 +55,6 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-inside">
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>User</mat-label>
|
||||
<input matInput value={{username}} readonly>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<mat-dialog-actions class="mat-dialog-actions">
|
||||
<div class="mat-dialog-left">
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-12">
|
||||
<label>Categories</label>
|
||||
<div class="col-md-12">
|
||||
<div class="text-inside">
|
||||
@@ -62,7 +62,7 @@
|
||||
<div class="col-md-12">
|
||||
<table class="table" style="table-layout: fixed;">
|
||||
<tbody>
|
||||
<tr *ngFor="let category of account.categories">
|
||||
<tr *ngFor="let category of categoriesSorted">
|
||||
<td style="width: 100%;">{{category.name}}</td>
|
||||
<td style="width: 100px;">
|
||||
<button class="btn-space" (click)="removeCategory(category)" mat-raised-button color="primary">
|
||||
@@ -74,37 +74,6 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label>Users</label>
|
||||
<div class="col-md-12">
|
||||
<div class="text-inside">
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Category</mat-label>
|
||||
<mat-select formControlName="categoryId">
|
||||
<mat-option *ngFor="let category of categories" [value]="category.id">
|
||||
{{category.name}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<table class="table" style="table-layout: fixed;">
|
||||
<tbody>
|
||||
<tr *ngFor="let accessRight of account.accessRights">
|
||||
<td style="width: 100%;">{{accessRight.user.email}}</td>
|
||||
<td style="width: 100px;">
|
||||
<button class="btn-space" [disabled]="account.accessRights!.length <= 1" click="removeAccessRight(accessRight)" mat-raised-button color="primary">
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-dialog-actions class="mat-dialog-actions">
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Validators } from '@angular/forms';
|
||||
// libs
|
||||
import Swal from 'sweetalert2';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import * as ld from 'lodash';
|
||||
|
||||
// app
|
||||
import { ApiRoutes } from '../../../api-routes';
|
||||
@@ -32,6 +33,9 @@ export class SettingsAccountEditComponent {
|
||||
public categories?: AccountCategoryModel[];
|
||||
public types = new Map<string, string>();
|
||||
|
||||
public categoriesSorted: AccountCategoryModel[];
|
||||
public accessRightsSorted: AccountAccessRightModel[];
|
||||
|
||||
constructor(
|
||||
private fb: UntypedFormBuilder,
|
||||
private httpClient: HttpClient,
|
||||
@@ -42,6 +46,9 @@ export class SettingsAccountEditComponent {
|
||||
@Inject(MAT_DIALOG_DATA) public account: AccountModel
|
||||
) {
|
||||
this.types = this.accountService.getTypes();
|
||||
|
||||
this.categoriesSorted = ld.orderBy(account.categories!, ['name'], ['asc']);
|
||||
this.accessRightsSorted = ld.orderBy(account.accessRights!, ['isOwner', 'user.email'], ['desc', 'asc']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -63,6 +70,9 @@ export class SettingsAccountEditComponent {
|
||||
type: [
|
||||
this.account.type,
|
||||
],
|
||||
userEmail: [
|
||||
'',
|
||||
],
|
||||
});
|
||||
|
||||
this.currencyService
|
||||
|
||||
Reference in New Issue
Block a user