This commit is contained in:
2023-07-28 21:18:18 +03:00
parent 5ecefe5756
commit 90f0386bfe
53 changed files with 3067 additions and 267 deletions
+2
View File
@@ -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