Ag Grid anpassungen
This commit is contained in:
@@ -34,6 +34,9 @@ export class EmailLog {
|
|||||||
@Column({type: 'boolean'})
|
@Column({type: 'boolean'})
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
|
||||||
|
@Column({type: 'text', default: null})
|
||||||
|
context: boolean;
|
||||||
|
|
||||||
@AfterLoad()
|
@AfterLoad()
|
||||||
setType() {
|
setType() {
|
||||||
this.eventName = EmailEvent[this.type]
|
this.eventName = EmailEvent[this.type]
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export class UserSettings {
|
|||||||
@Column({ name: 'send_system_update_notification', default: true, type: 'boolean'})
|
@Column({ name: 'send_system_update_notification', default: true, type: 'boolean'})
|
||||||
sendSystemUpdateMails: boolean;
|
sendSystemUpdateMails: boolean;
|
||||||
|
|
||||||
|
@Column({ name: 'ui_scale', default: 'm' })
|
||||||
|
uiScale: 's' | 'm' | 'l';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,10 +5,11 @@ import { DatabaseModule } from 'src/shared/database/database.module';
|
|||||||
import { AuthModule } from '../auth/auth.module';
|
import { AuthModule } from '../auth/auth.module';
|
||||||
import { SharedServiceModule } from 'src/shared/service/shared.service.module';
|
import { SharedServiceModule } from 'src/shared/service/shared.service.module';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { MailModule } from '../mail/mail.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [KeyController],
|
controllers: [KeyController],
|
||||||
providers: [KeyService, ConfigService],
|
providers: [KeyService, ConfigService],
|
||||||
imports: [DatabaseModule, AuthModule, SharedServiceModule],
|
imports: [DatabaseModule, AuthModule, SharedServiceModule, MailModule],
|
||||||
})
|
})
|
||||||
export class KeyModule {}
|
export class KeyModule {}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { HelperService } from 'src/shared/service/system.helper.service';
|
|||||||
import { FindOperator, IsNull, Not } from 'typeorm';
|
import { FindOperator, IsNull, Not } from 'typeorm';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { MailService } from '../mail/mail.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class KeyService {
|
export class KeyService {
|
||||||
@@ -20,7 +21,8 @@ export class KeyService {
|
|||||||
private readonly handoverRepo: KeyHandoutRepository,
|
private readonly handoverRepo: KeyHandoutRepository,
|
||||||
private readonly activityService: ActivityHelperService,
|
private readonly activityService: ActivityHelperService,
|
||||||
private readonly helper: HelperService,
|
private readonly helper: HelperService,
|
||||||
private readonly configService: ConfigService
|
private readonly configService: ConfigService,
|
||||||
|
private readonly mailService: MailService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
get isDevelopMode(): boolean {
|
get isDevelopMode(): boolean {
|
||||||
@@ -109,6 +111,21 @@ export class KeyService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.activityService.logKeyHandover(user, key, key.cylinder[0].system, res);
|
this.activityService.logKeyHandover(user, key, key.cylinder[0].system, res);
|
||||||
|
try {
|
||||||
|
if (key && key.cylinder && key.cylinder[0].system) {
|
||||||
|
const managerOb: Key = await this.keyrepository.findOne({
|
||||||
|
where: { id: keyID },
|
||||||
|
relations: [ 'cylinder', 'cylinder.system', 'cylinder.system.managers', 'cylinder.system.managers.settings' ]
|
||||||
|
});
|
||||||
|
console.log(managerOb.cylinder[0].system.managers)
|
||||||
|
managerOb.cylinder[0].system.managers.filter(m => m.settings.sendSystemUpdateMails).forEach(m => {
|
||||||
|
this.mailService.sendKeyHandoutMail({ to: m, key, handoutAction: res })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e){
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ export class LogService {
|
|||||||
|
|
||||||
private async logEmail(data: EmailLogDto) {
|
private async logEmail(data: EmailLogDto) {
|
||||||
const log = this.emailLogRepo.create(data);
|
const log = this.emailLogRepo.create(data);
|
||||||
|
console.log(log)
|
||||||
const logEntry = await this.emailLogRepo.save(log);
|
const logEntry = await this.emailLogRepo.save(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async logAuthEvent(data: User) {
|
private async logAuthEvent(data: User) {
|
||||||
console.error("auth logging not implemented")
|
// console.error("auth logging not implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +35,8 @@ export enum LogType {
|
|||||||
|
|
||||||
export enum EmailEvent {
|
export enum EmailEvent {
|
||||||
GrantSystemAccess,
|
GrantSystemAccess,
|
||||||
RemoveSystemAccess
|
RemoveSystemAccess,
|
||||||
|
KeyHandout
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmailLogDto {
|
export interface EmailLogDto {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Injectable } from "@nestjs/common";
|
|||||||
import { ConfigService } from "@nestjs/config";
|
import { ConfigService } from "@nestjs/config";
|
||||||
import { EmailEvent, LogService, LogType } from "../log/log.service";
|
import { EmailEvent, LogService, LogType } from "../log/log.service";
|
||||||
import { KeySystem } from "src/model/entitites/system.entity";
|
import { KeySystem } from "src/model/entitites/system.entity";
|
||||||
import { User } from "src/model/entitites";
|
import { Key, KeyHandout, User } from "src/model/entitites";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MailService {
|
export class MailService {
|
||||||
@@ -14,6 +14,46 @@ export class MailService {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sendKeyHandoutMail({to, key, handoutAction}: {to: User, key: Key, handoutAction: KeyHandout}) {
|
||||||
|
const keyAction = handoutAction.direction == 'out' ? 'wurde ausgegeben' : 'wurde zurückgegeben';
|
||||||
|
const keyExtendedAction = handoutAction.direction == 'return' ? `wurde von ${handoutAction.customer.name} zurückgegeben` : `wurde an ${handoutAction.customer.name} ausgegeben`;
|
||||||
|
const subject = handoutAction.direction == 'out' ? 'Schlüssel ausgegeben' : 'Schlüssel zurückgegeben';
|
||||||
|
const context = {
|
||||||
|
keyAction,
|
||||||
|
keyExtendedAction,
|
||||||
|
firstName: to.firstName,
|
||||||
|
keyNr: key.nr,
|
||||||
|
keyName: key.name,
|
||||||
|
url: 'https://keyvaultpro.de/keys?nr=' + key.nr
|
||||||
|
}
|
||||||
|
this.mailserService.sendMail({
|
||||||
|
template: './key-handout-changed',
|
||||||
|
to: to.username,
|
||||||
|
from: this.configService.get<string>('MAILER_FROM'),
|
||||||
|
subject: subject,
|
||||||
|
context
|
||||||
|
}).then(v => {
|
||||||
|
|
||||||
|
this.logService.log(LogType.Mail, {
|
||||||
|
to: to.username,
|
||||||
|
success: true,
|
||||||
|
message: v.response,
|
||||||
|
type: EmailEvent.KeyHandout,
|
||||||
|
system: key.cylinder[0].system,
|
||||||
|
context: JSON.stringify(handoutAction)
|
||||||
|
})
|
||||||
|
}).catch(e => {
|
||||||
|
this.logService.log(LogType.Mail, {
|
||||||
|
to,
|
||||||
|
success: false,
|
||||||
|
message: e.response,
|
||||||
|
type: EmailEvent.KeyHandout,
|
||||||
|
system: key.cylinder[0].system,
|
||||||
|
context: JSON.stringify(handoutAction)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async sendAccessGrantedMail({to, system}: {to: User, system: KeySystem}) {
|
async sendAccessGrantedMail({to, system}: {to: User, system: KeySystem}) {
|
||||||
this.mailserService.sendMail({
|
this.mailserService.sendMail({
|
||||||
template: './access',
|
template: './access',
|
||||||
|
|||||||
94
api/src/templates/key-handout-changed.hbs
Normal file
94
api/src/templates/key-handout-changed.hbs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Zugriff gewährt</title>
|
||||||
|
<style>
|
||||||
|
/* General styles */
|
||||||
|
body {
|
||||||
|
font-family: 'Roboto', Arial, sans-serif;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #424242;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 20px auto;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #2196f3; /* Freundliches Blau */
|
||||||
|
color: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 24px 20px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #424242;
|
||||||
|
}
|
||||||
|
.content p {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 24px 0;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #2196f3; /* Gleicher Blauton */
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 24px;
|
||||||
|
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
}
|
||||||
|
.btn:hover {
|
||||||
|
background-color: #1769aa; /* Dunkleres Blau für Hover */
|
||||||
|
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #757575;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #2196f3;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>Schlüssel {{ keyAction }}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>Hallo {{firstName}},</p>
|
||||||
|
<p>der Schlüssel {{ keyName }} ({{ keyNr }}) wurde {{ keyExtendedAction }}</p>
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="{{ url }}" class="btn">Website aufrufen</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -34,7 +34,6 @@
|
|||||||
"styles": [
|
"styles": [
|
||||||
"@angular/material/prebuilt-themes/azure-blue.css",
|
"@angular/material/prebuilt-themes/azure-blue.css",
|
||||||
"src/styles.scss",
|
"src/styles.scss",
|
||||||
"src/styles/ag.css",
|
|
||||||
"node_modules/@ngxpert/hot-toast/src/styles/styles.css"
|
"node_modules/@ngxpert/hot-toast/src/styles/styles.css"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { BehaviorSubject, Observable, tap, of, catchError } from 'rxjs';
|
|||||||
import { IUser } from '../../model/interface/user.interface';
|
import { IUser } from '../../model/interface/user.interface';
|
||||||
import { environment } from '../../../environments/environment';
|
import { environment } from '../../../environments/environment';
|
||||||
import { HotToastService } from '@ngxpert/hot-toast';
|
import { HotToastService } from '@ngxpert/hot-toast';
|
||||||
|
import { ApiService } from '../../shared/api.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -16,6 +17,7 @@ export class AuthService {
|
|||||||
private http: HttpClient = inject(HttpClient);
|
private http: HttpClient = inject(HttpClient);
|
||||||
private router: Router = inject(Router);
|
private router: Router = inject(Router);
|
||||||
private toast: HotToastService = inject(HotToastService);
|
private toast: HotToastService = inject(HotToastService);
|
||||||
|
private api: ApiService = inject(ApiService);
|
||||||
|
|
||||||
private _user: IUser | null = null;
|
private _user: IUser | null = null;
|
||||||
|
|
||||||
@@ -35,21 +37,27 @@ export class AuthService {
|
|||||||
return this.user != null && this.user.role == 'admin';
|
return this.user != null && this.user.role == 'admin';
|
||||||
}
|
}
|
||||||
|
|
||||||
getMe() {
|
async getMe() {
|
||||||
if (!this.getAccessToken()) {
|
if (!this.getAccessToken()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return new Promise(resolve => {
|
const user = await this.api.getMe();
|
||||||
this.http.get<IUser>('/api/auth/me').subscribe({
|
if (user) {
|
||||||
next: user => {
|
|
||||||
this._user = user;
|
this._user = user;
|
||||||
resolve(true)
|
return Promise.resolve(true);
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
resolve(false)
|
|
||||||
}
|
}
|
||||||
})
|
return Promise.resolve(false)
|
||||||
})
|
// return new Promise(resolve => {
|
||||||
|
// this.http.get<IUser>('/api/auth/me').subscribe({
|
||||||
|
// next: user => {
|
||||||
|
// this._user = user;
|
||||||
|
// resolve(true)
|
||||||
|
// },
|
||||||
|
// error: () => {
|
||||||
|
// resolve(false)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
@if (gridOptions || true) {
|
@if (myTheme && gridOptions) {
|
||||||
<ag-grid-angular
|
<ag-grid-angular
|
||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
[gridOptions]="gridOptions!"
|
[gridOptions]="gridOptions!"
|
||||||
|
[theme]="myTheme"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ import { AuthService } from '../../../core/auth/auth.service';
|
|||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { AgGridContainerComponent } from '../../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-all-users',
|
selector: 'app-all-users',
|
||||||
@@ -16,7 +17,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
templateUrl: './all-users.component.html',
|
templateUrl: './all-users.component.html',
|
||||||
styleUrl: './all-users.component.scss'
|
styleUrl: './all-users.component.scss'
|
||||||
})
|
})
|
||||||
export class AllUsersComponent {
|
export class AllUsersComponent extends AgGridContainerComponent {
|
||||||
|
|
||||||
private toast: HotToastService = inject(HotToastService);
|
private toast: HotToastService = inject(HotToastService);
|
||||||
private api: ApiService = inject(ApiService);
|
private api: ApiService = inject(ApiService);
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<ag-grid-angular
|
@if (myTheme) {
|
||||||
|
<ag-grid-angular
|
||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
[gridOptions]="gridOptions!"
|
[gridOptions]="gridOptions!"
|
||||||
|
[theme]="myTheme"
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
<div class="floating-btn-container">
|
<div class="floating-btn-container">
|
||||||
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateCylinder()" >Zylinder anlegen</button>
|
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateCylinder()" >Zylinder anlegen</button>
|
||||||
<button mat-mini-fab disabled><mat-icon>inventory_2</mat-icon></button>
|
<button mat-mini-fab disabled><mat-icon>inventory_2</mat-icon></button>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
|||||||
import { CreateCylinderComponent } from './components/create-cylinder/create-cylinder.component';
|
import { CreateCylinderComponent } from './components/create-cylinder/create-cylinder.component';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { AgGridContainerComponent } from '../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-cylinder',
|
selector: 'app-cylinder',
|
||||||
@@ -17,7 +18,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
templateUrl: './cylinder.component.html',
|
templateUrl: './cylinder.component.html',
|
||||||
styleUrl: './cylinder.component.scss'
|
styleUrl: './cylinder.component.scss'
|
||||||
})
|
})
|
||||||
export class CylinderComponent {
|
export class CylinderComponent extends AgGridContainerComponent {
|
||||||
private api: ApiService = inject(ApiService);
|
private api: ApiService = inject(ApiService);
|
||||||
private datePipe = inject(DatePipe);
|
private datePipe = inject(DatePipe);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
@@ -28,6 +29,7 @@ export class CylinderComponent {
|
|||||||
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
this.gridOptions.columnDefs = [
|
this.gridOptions.columnDefs = [
|
||||||
{ field: 'name', headerName: 'Name', sort: 'asc', flex: 1, filter: true },
|
{ field: 'name', headerName: 'Name', sort: 'asc', flex: 1, filter: true },
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
[gridOptions]="gridOptions"
|
[gridOptions]="gridOptions"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
|
[theme]="myTheme"
|
||||||
>
|
>
|
||||||
</ag-grid-angular>
|
</ag-grid-angular>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { RouterModule } from '@angular/router';
|
|||||||
import { AgLoadingComponent } from '../../shared/ag-grid/components/ag-loading/ag-loading.component';
|
import { AgLoadingComponent } from '../../shared/ag-grid/components/ag-loading/ag-loading.component';
|
||||||
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { AgGridContainerComponent } from '../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
@@ -17,7 +18,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
templateUrl: './dashboard.component.html',
|
templateUrl: './dashboard.component.html',
|
||||||
styleUrl: './dashboard.component.scss'
|
styleUrl: './dashboard.component.scss'
|
||||||
})
|
})
|
||||||
export class DashboardComponent {
|
export class DashboardComponent extends AgGridContainerComponent {
|
||||||
private api = inject(ApiService);
|
private api = inject(ApiService);
|
||||||
private datePipe = inject(DatePipe);
|
private datePipe = inject(DatePipe);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<ag-grid-angular
|
@if (myTheme) {
|
||||||
|
<ag-grid-angular
|
||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
[gridOptions]="gridOptions!"
|
[gridOptions]="gridOptions!"
|
||||||
|
[theme]="myTheme"
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="floating-btn-container">
|
<div class="floating-btn-container">
|
||||||
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateKey()" >Schlüssel anlegen</button>
|
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateKey()" >Schlüssel anlegen</button>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
||||||
import { AgGridAngular } from 'ag-grid-angular';
|
import { AgGridAngular } from 'ag-grid-angular';
|
||||||
import { GridOptions,GridApi, GridReadyEvent, CellEditingStoppedEvent, ICellEditorParams, FilterActionParams, FilterAction } from 'ag-grid-community';
|
import { GridOptions,GridApi, GridReadyEvent, CellEditingStoppedEvent, ICellEditorParams, FilterActionParams, FilterAction, themeQuartz, Theme, ThemeDefaultParams } from 'ag-grid-community';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { ApiService } from '../../shared/api.service';
|
import { ApiService } from '../../shared/api.service';
|
||||||
import { IKey } from '../../model/interface/key.interface';
|
import { IKey } from '../../model/interface/key.interface';
|
||||||
@@ -20,6 +20,8 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
|||||||
import { SelectKeyCylinderComponent } from './create/select-key-cylinder/select-key-cylinder.component';
|
import { SelectKeyCylinderComponent } from './create/select-key-cylinder/select-key-cylinder.component';
|
||||||
import { ActivatedRoute, Route } from '@angular/router';
|
import { ActivatedRoute, Route } from '@angular/router';
|
||||||
import { ModuleRegistry } from 'ag-grid-community';
|
import { ModuleRegistry } from 'ag-grid-community';
|
||||||
|
import { AgGridService } from '../../shared/ag-grid/ag-grid.service';
|
||||||
|
import { AgGridContainerComponent } from '../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-keys',
|
selector: 'app-keys',
|
||||||
@@ -28,12 +30,14 @@ import { ModuleRegistry } from 'ag-grid-community';
|
|||||||
templateUrl: './keys.component.html',
|
templateUrl: './keys.component.html',
|
||||||
styleUrl: './keys.component.scss'
|
styleUrl: './keys.component.scss'
|
||||||
})
|
})
|
||||||
export class KeysComponent {
|
export class KeysComponent extends AgGridContainerComponent {
|
||||||
private api: ApiService = inject(ApiService);
|
private api: ApiService = inject(ApiService);
|
||||||
private datePipe = inject(DatePipe);
|
private datePipe = inject(DatePipe);
|
||||||
private toast: HotToastService = inject(HotToastService);
|
private toast: HotToastService = inject(HotToastService);
|
||||||
private dialog: MatDialog = inject(MatDialog);
|
private dialog: MatDialog = inject(MatDialog);
|
||||||
private route: ActivatedRoute = inject(ActivatedRoute)
|
private route: ActivatedRoute = inject(ActivatedRoute);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// cylinders: any[] = [];
|
// cylinders: any[] = [];
|
||||||
|
|
||||||
@@ -97,7 +101,7 @@ export class KeysComponent {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
loading: true,
|
loading: true,
|
||||||
rowHeight: 54,
|
// rowHeight: 54,
|
||||||
loadingOverlayComponent: AgLoadingComponent,
|
loadingOverlayComponent: AgLoadingComponent,
|
||||||
pagination: true,
|
pagination: true,
|
||||||
}
|
}
|
||||||
@@ -110,6 +114,7 @@ export class KeysComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private setFilterToParams() {
|
private setFilterToParams() {
|
||||||
const params = this.route.snapshot.queryParams;
|
const params = this.route.snapshot.queryParams;
|
||||||
|
|
||||||
@@ -120,6 +125,15 @@ export class KeysComponent {
|
|||||||
type: params['handedOut']
|
type: params['handedOut']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} if (Object.keys(params).includes('nr')) {
|
||||||
|
console.log("SET " + params['nr'] )
|
||||||
|
this.gridApi.setFilterModel({
|
||||||
|
nr: {
|
||||||
|
filterType: 'text',
|
||||||
|
type: 'equals',
|
||||||
|
filter: params['nr']
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,13 +27,13 @@
|
|||||||
<mat-form-field appearance="outline">
|
<mat-form-field appearance="outline">
|
||||||
<mat-label>Email</mat-label>
|
<mat-label>Email</mat-label>
|
||||||
<input type="text" matInput formControlName="userName">
|
<input type="text" matInput formControlName="userName">
|
||||||
<mat-hint>Wird zum Login benötigt</mat-hint>
|
<mat-hint>Wird für den Emailversand benötigt</mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<div class="spacer-y16"></div>
|
<div class="spacer-y16"></div>
|
||||||
<button matButton="elevated" [disabled]="userData.invalid" (click)="saveUser()">Speichern</button>
|
<button matButton="elevated" [disabled]="userData.invalid" (click)="saveUser()">Speichern</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="spacer-y32"></div>
|
<div class="spacer-y32"></div>
|
||||||
<div class="px-4">
|
<div class="px-4">
|
||||||
<div class="text-2xl">Emailbenachrichtigungen</div>
|
<div class="text-2xl">Emailbenachrichtigungen</div>
|
||||||
<div>Sende Emails bei: </div>
|
<div>Sende Emails bei: </div>
|
||||||
@@ -48,6 +48,17 @@
|
|||||||
<mat-slide-toggle formControlName="sendUserDisabledMails" (change)="save()">
|
<mat-slide-toggle formControlName="sendUserDisabledMails" (change)="save()">
|
||||||
Deaktivierung meines Users
|
Deaktivierung meines Users
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
|
<div class="spacer-y16"></div>
|
||||||
|
<div class="text-2xl">Oberfläche</div>
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Skalierung</mat-label>
|
||||||
|
<mat-select formControlName="uiScale" (selectionChange)="save()" >
|
||||||
|
<mat-option [value]="'s'">Klein</mat-option>
|
||||||
|
<mat-option [value]="'m'">Mittel</mat-option>
|
||||||
|
<mat-option [value]="'l'">Groß</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-hint>Ändert die Schriftgröße in der Liste</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,3 +47,7 @@
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
@@ -8,10 +8,11 @@ import { ApiService } from '../../shared/api.service';
|
|||||||
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
|
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
|
||||||
import { HotToastService } from '@ngxpert/hot-toast';
|
import { HotToastService } from '@ngxpert/hot-toast';
|
||||||
import {MatProgressBarModule} from '@angular/material/progress-bar';
|
import {MatProgressBarModule} from '@angular/material/progress-bar';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings',
|
selector: 'app-settings',
|
||||||
imports: [MatProgressBarModule, MatFormFieldModule, MatInputModule, MatButtonModule, ReactiveFormsModule, FormsModule, MatSlideToggleModule],
|
imports: [MatProgressBarModule, MatFormFieldModule, MatInputModule, MatButtonModule, ReactiveFormsModule, FormsModule, MatSlideToggleModule, MatSelectModule],
|
||||||
templateUrl: './settings.component.html',
|
templateUrl: './settings.component.html',
|
||||||
styleUrl: './settings.component.scss'
|
styleUrl: './settings.component.scss'
|
||||||
})
|
})
|
||||||
@@ -36,6 +37,7 @@ export class SettingsComponent {
|
|||||||
sendSystemAccessMails: new FormControl(false),
|
sendSystemAccessMails: new FormControl(false),
|
||||||
sendSystemUpdateMails: new FormControl(false),
|
sendSystemUpdateMails: new FormControl(false),
|
||||||
sendUserDisabledMails: new FormControl(false),
|
sendUserDisabledMails: new FormControl(false),
|
||||||
|
uiScale: new FormControl('s')
|
||||||
})
|
})
|
||||||
|
|
||||||
open() {
|
open() {
|
||||||
@@ -70,25 +72,20 @@ export class SettingsComponent {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSettings() {
|
async loadSettings() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.api.getSettings().subscribe({
|
const settings = await this.api.userSettings;
|
||||||
next: (r: any) => {
|
this.userSettings.patchValue(settings);
|
||||||
this.userSettings.patchValue(r)
|
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
save() {
|
async save() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.api.updateSettings(this.userSettings.value).subscribe({
|
const res = await this.api.updateSettings(this.userSettings.value);
|
||||||
next: () => {
|
|
||||||
this.toast.success('Gespeichert')
|
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
if (res) {
|
||||||
this.userSettings.markAsPristine();
|
this.userSettings.markAsPristine();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
saveUser() {
|
saveUser() {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
@if (myTheme) {
|
||||||
<ag-grid-angular
|
<ag-grid-angular
|
||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
[gridOptions]="gridOptions!"
|
[gridOptions]="gridOptions!"
|
||||||
|
[theme]="myTheme"
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
<div class="floating-btn-container">
|
<div class="floating-btn-container">
|
||||||
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateSystem()" >Schließanlage anlegen</button>
|
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateSystem()" >Schließanlage anlegen</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { AgGridAngular } from 'ag-grid-angular';
|
import { AgGridAngular } from 'ag-grid-angular';
|
||||||
import { GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community';
|
import { GridApi, GridOptions, GridReadyEvent, Theme, ThemeDefaultParams } from 'ag-grid-community';
|
||||||
import { ApiService } from '../../shared/api.service';
|
import { ApiService } from '../../shared/api.service';
|
||||||
import { HELPER } from '../../shared/helper.service';
|
import { HELPER } from '../../shared/helper.service';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||||
import { CreateSystemComponent } from './create/create.component';
|
import { CreateSystemComponent } from './create/create.component';
|
||||||
import { AgSystemManagerComponent } from '../../shared/ag-grid/components/ag-system-manager/ag-system-manager.component';
|
import { AgSystemManagerComponent } from '../../shared/ag-grid/components/ag-system-manager/ag-system-manager.component';
|
||||||
|
import { AgGridService } from '../../shared/ag-grid/ag-grid.service';
|
||||||
|
import { AgGridContainerComponent } from '../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-system',
|
selector: 'app-system',
|
||||||
@@ -16,16 +18,17 @@ import { AgSystemManagerComponent } from '../../shared/ag-grid/components/ag-sys
|
|||||||
templateUrl: './system.component.html',
|
templateUrl: './system.component.html',
|
||||||
styleUrl: './system.component.scss'
|
styleUrl: './system.component.scss'
|
||||||
})
|
})
|
||||||
export class SystemComponent {
|
export class SystemComponent extends AgGridContainerComponent {
|
||||||
private api: ApiService = inject(ApiService);
|
private api: ApiService = inject(ApiService);
|
||||||
private datePipe = inject(DatePipe);
|
private datePipe = inject(DatePipe);
|
||||||
private dialog: MatDialog = inject(MatDialog);
|
private dialog: MatDialog = inject(MatDialog);
|
||||||
|
|
||||||
gridApi!: GridApi;
|
gridApi!: GridApi;
|
||||||
|
|
||||||
gridOptions: GridOptions = HELPER.getGridOptions();
|
gridOptions: GridOptions = HELPER.getGridOptions();
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super();
|
||||||
this.gridOptions.columnDefs = [
|
this.gridOptions.columnDefs = [
|
||||||
{ colId: 'name', field: 'name', headerName: 'Name', sort: 'asc', flex: 1},
|
{ colId: 'name', field: 'name', headerName: 'Name', sort: 'asc', flex: 1},
|
||||||
{ field: 'createdAt', headerName: 'Angelegt', cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value)) : '-' },
|
{ field: 'createdAt', headerName: 'Angelegt', cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value)) : '-' },
|
||||||
@@ -37,10 +40,9 @@ export class SystemComponent {
|
|||||||
, cellRenderer: AgSystemManagerComponent
|
, cellRenderer: AgSystemManagerComponent
|
||||||
// , onCellClicked: (event) => { this.deleteKey(event.data.id)}
|
// , onCellClicked: (event) => { this.deleteKey(event.data.id)}
|
||||||
}
|
}
|
||||||
]
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
loadSystems() {
|
loadSystems() {
|
||||||
this.api.getSystems().subscribe({
|
this.api.getSystems().subscribe({
|
||||||
next: n => {
|
next: n => {
|
||||||
|
|||||||
16
client/src/app/shared/ag-grid/ag-grid.service.spec.ts
Normal file
16
client/src/app/shared/ag-grid/ag-grid.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AgGridService } from './ag-grid.service';
|
||||||
|
|
||||||
|
describe('AgGridService', () => {
|
||||||
|
let service: AgGridService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(AgGridService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
66
client/src/app/shared/ag-grid/ag-grid.service.ts
Normal file
66
client/src/app/shared/ag-grid/ag-grid.service.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { inject, Injectable } from '@angular/core';
|
||||||
|
import { ApiService } from '../api.service';
|
||||||
|
import { Theme, ThemeDefaultParams, themeQuartz } from 'ag-grid-community';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class AgGridService {
|
||||||
|
private api = inject(ApiService);
|
||||||
|
|
||||||
|
private baseConfig = {
|
||||||
|
|
||||||
|
accentColor: "#125312",
|
||||||
|
backgroundColor: "#FFFFFF",
|
||||||
|
borderColor: "#D7E2E6",
|
||||||
|
borderRadius: 2,
|
||||||
|
browserColorScheme: "light",
|
||||||
|
cellHorizontalPaddingScale: 0.7,
|
||||||
|
chromeBackgroundColor: {
|
||||||
|
ref: "backgroundColor"
|
||||||
|
},
|
||||||
|
columnBorder: false,
|
||||||
|
fontFamily: {
|
||||||
|
googleFont: "Roboto"
|
||||||
|
},
|
||||||
|
headerFontSize: 16,
|
||||||
|
foregroundColor: "#555B62",
|
||||||
|
headerBackgroundColor: "#FFFFFF",
|
||||||
|
|
||||||
|
headerFontWeight: 400,
|
||||||
|
headerTextColor: "#84868B",
|
||||||
|
rowBorder: true,
|
||||||
|
sidePanelBorder: true,
|
||||||
|
|
||||||
|
wrapperBorder: false,
|
||||||
|
wrapperBorderRadius: 2,
|
||||||
|
spacing: 1,
|
||||||
|
cellHorizontalPadding: 10,
|
||||||
|
headerVerticalPaddingScale: 5
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private userScale = {
|
||||||
|
s: {
|
||||||
|
fontSize: 12,
|
||||||
|
rowVerticalPaddingScale: 4
|
||||||
|
},
|
||||||
|
m: {
|
||||||
|
fontSize: 16,
|
||||||
|
rowVerticalPaddingScale: 8
|
||||||
|
},
|
||||||
|
l: {
|
||||||
|
fontSize: 18,
|
||||||
|
rowVerticalPaddingScale: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getGridConfig(): Promise<Theme<ThemeDefaultParams>> {
|
||||||
|
let settings = await this.api.userSettings;
|
||||||
|
const scale = (this.userScale as any)[(settings as any)['uiScale']];
|
||||||
|
const conf = {...this.baseConfig, ...scale};
|
||||||
|
return themeQuartz.withParams(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<p>ag-grid-container works!</p>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AgGridContainerComponent } from './ag-grid-container.component';
|
||||||
|
|
||||||
|
describe('AgGridContainerComponent', () => {
|
||||||
|
let component: AgGridContainerComponent;
|
||||||
|
let fixture: ComponentFixture<AgGridContainerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [AgGridContainerComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AgGridContainerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { Theme, ThemeDefaultParams } from 'ag-grid-community';
|
||||||
|
import { AgGridService } from '../../ag-grid.service';
|
||||||
|
import { ApiService } from '../../../api.service';
|
||||||
|
import { filter } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ag-grid-container',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './ag-grid-container.component.html',
|
||||||
|
styleUrl: './ag-grid-container.component.scss',
|
||||||
|
})
|
||||||
|
export class AgGridContainerComponent {
|
||||||
|
myTheme: Theme<ThemeDefaultParams> = null!;
|
||||||
|
private gridService: AgGridService = inject(AgGridService);
|
||||||
|
private apiService: ApiService = inject(ApiService);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.loadAgTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async loadAgTheme() {
|
||||||
|
this.apiService.userSettings;
|
||||||
|
this.apiService.settings.subscribe(async (v) => {
|
||||||
|
if (v != null) {
|
||||||
|
this.myTheme = await this.gridService.getGridConfig()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,9 +17,26 @@ export class ApiService {
|
|||||||
public cylinders: BehaviorSubject<ICylinder[]> = new BehaviorSubject<ICylinder[]>([]);
|
public cylinders: BehaviorSubject<ICylinder[]> = new BehaviorSubject<ICylinder[]>([]);
|
||||||
|
|
||||||
|
|
||||||
|
public user: BehaviorSubject<IUser> = new BehaviorSubject<IUser>(null!);
|
||||||
|
public settings: BehaviorSubject<Object> = new BehaviorSubject<Object>(null!);
|
||||||
|
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
|
getMe(): Promise<IUser> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.http.get<IUser>('/api/auth/me').subscribe({
|
||||||
|
next: user => {
|
||||||
|
this.user.next(user);
|
||||||
|
resolve(user)
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
resolve(null!)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getAllUsers(): Observable<IUser[]> {
|
getAllUsers(): Observable<IUser[]> {
|
||||||
return this.http.get<IUser[]>('/api/user');
|
return this.http.get<IUser[]>('/api/user');
|
||||||
@@ -157,11 +174,44 @@ export class ApiService {
|
|||||||
return this.http.post<ICylinder>('api/cylinder', data);
|
return this.http.post<ICylinder>('api/cylinder', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSettings(): Observable<any> {
|
private loadSettings(): Promise<Object> {
|
||||||
return this.http.get('api/user/settings')
|
return new Promise(resolve => {
|
||||||
|
this.http.get('api/user/settings').subscribe({
|
||||||
|
next: val => {
|
||||||
|
this.settings.next(val);
|
||||||
|
return resolve(val);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.toast.error("Einstellungen konnten nicht geladen werden");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSettings(settings: any): Observable<any> {
|
get userSettings(): Promise<Object> {
|
||||||
return this.http.post('api/user/settings', settings)
|
if (!this.settings.value) {
|
||||||
|
return this.loadSettings();
|
||||||
|
}
|
||||||
|
return new Promise(resolve => {
|
||||||
|
return resolve(this.settings.value);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSettings(settings: any): Promise<boolean> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.http.post('api/user/settings', settings).subscribe({
|
||||||
|
next: async () => {
|
||||||
|
await this.loadSettings();
|
||||||
|
this.toast.success('Einstellungen gespeichert')
|
||||||
|
return resolve(true);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.toast.error("Fehler beim Speichern der Einstellungen");
|
||||||
|
return resolve(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ export class HELPER {
|
|||||||
columnDefs: [],
|
columnDefs: [],
|
||||||
loading: true,
|
loading: true,
|
||||||
loadingOverlayComponent: AgLoadingComponent,
|
loadingOverlayComponent: AgLoadingComponent,
|
||||||
rowHeight: 54,
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
/* Core Data Grid CSS */
|
/* Core Data Grid CSS */
|
||||||
@import "ag-grid-community/styles/ag-grid.css";
|
// @import "ag-grid-community/styles/ag-grid.css";
|
||||||
/* Quartz Theme Specific CSS */
|
/* Quartz Theme Specific CSS */
|
||||||
@import 'ag-grid-community/styles/ag-theme-quartz.css';
|
// @import 'ag-grid-community/styles/ag-theme-quartz.css';
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@@ -46,11 +46,11 @@ html, body {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background-size: 20px;
|
background-size: 16px;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
width: 38px;
|
width: 28px;
|
||||||
height: 38px;
|
height: 28px;
|
||||||
transition: box-shadow 0.1s ease-in-out;
|
transition: box-shadow 0.1s ease-in-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|||||||
Reference in New Issue
Block a user