From 7bd6dfae27b70c26b7b909f323c5d19fe020bb0f Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Thu, 19 Feb 2026 16:19:46 +0100 Subject: [PATCH] Archive und Logging --- api/src/modules/auth/auth.service.ts | 1 - .../modules/cylinder/cylinder.controller.ts | 10 +++ api/src/modules/cylinder/cylinder.service.ts | 31 +++++++- api/src/modules/key/key.controller.ts | 2 +- api/src/modules/key/key.service.ts | 14 +++- api/src/modules/log/log.service.ts | 3 +- api/src/modules/mail/mail.service.ts | 44 ++++++++++- api/src/modules/system/system.service.ts | 1 + api/src/modules/user/user.controller.ts | 2 - api/src/modules/user/user.service.ts | 2 +- .../shared/service/activity.logger.service.ts | 28 ++++++- .../shared/service/system.helper.service.ts | 10 +++ client/src/app/app.config.ts | 12 ++- .../cylinder-archive.component.html | 15 ++++ .../cylinder-archive.component.scss | 0 .../cylinder-archive.component.spec.ts | 23 ++++++ .../cylinder-archive.component.ts | 78 +++++++++++++++++++ .../modules/cylinder/cylinder.component.html | 2 +- .../modules/cylinder/cylinder.component.ts | 11 +++ .../components/archive/archive.component.html | 5 +- .../components/archive/archive.component.ts | 7 +- .../lost-keys/lost-keys.component.html | 5 +- .../lost-keys/lost-keys.component.ts | 5 +- .../system-manager.component.html | 7 +- .../system-manager.component.ts | 6 +- .../app/modules/system/system.component.ts | 10 +-- .../ag-delete-cylinder.component.ts | 19 ++--- client/src/app/shared/api.service.ts | 49 +++++++++++- 28 files changed, 358 insertions(+), 44 deletions(-) create mode 100644 client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.html create mode 100644 client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.scss create mode 100644 client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.spec.ts create mode 100644 client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.ts diff --git a/api/src/modules/auth/auth.service.ts b/api/src/modules/auth/auth.service.ts index 702b4f3..c9555ac 100644 --- a/api/src/modules/auth/auth.service.ts +++ b/api/src/modules/auth/auth.service.ts @@ -55,7 +55,6 @@ export class AuthService { const payload: IExternalAccessPayload = this.jwt.decode(access_token); return new Promise(async (resolve) => { let user = await this.userRepo.findByUsername(payload.username, { settings: true }); - if (!user) { user = await this.userRepo.createUser({ username: payload.username, diff --git a/api/src/modules/cylinder/cylinder.controller.ts b/api/src/modules/cylinder/cylinder.controller.ts index e281290..4733a0c 100644 --- a/api/src/modules/cylinder/cylinder.controller.ts +++ b/api/src/modules/cylinder/cylinder.controller.ts @@ -24,6 +24,11 @@ export class CylinderController { return this.service.getCylinders(req.user); } + @Get('archive') + getCylinderArchive(@Req() req: AuthenticatedRequest): Promise { + return this.service.getDeletedCylinders(req.user); + } + @Delete(':id') deleteKey(@Req() req: AuthenticatedRequest, @Param('id') id: string) { return this.service.deleteCylinder(req.user, id); @@ -44,4 +49,9 @@ export class CylinderController { ) { return this.service.createCylinder(req.user, b); } + + @Put(':id/restore') + restoreKey(@Req() req: AuthenticatedRequest, @Param('id') id: string) { + return this.service.restoreCylinder(req.user, id); + } } diff --git a/api/src/modules/cylinder/cylinder.service.ts b/api/src/modules/cylinder/cylinder.service.ts index 6571328..1e67748 100644 --- a/api/src/modules/cylinder/cylinder.service.ts +++ b/api/src/modules/cylinder/cylinder.service.ts @@ -2,7 +2,9 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Cylinder, User } from 'src/model/entitites'; import { ActivityRepository, CylinderRepository, KeyRepository } from 'src/model/repositories'; +import { ActivityHelperService } from 'src/shared/service/activity.logger.service'; import { HelperService } from 'src/shared/service/system.helper.service'; +import { IsNull, Not } from 'typeorm'; @Injectable() export class CylinderService { @@ -11,7 +13,8 @@ export class CylinderService { private readonly keyRepo: KeyRepository, private systemActivityRepo: ActivityRepository, private readonly helper: HelperService, - private readonly configService: ConfigService + private readonly configService: ConfigService, + private activityService: ActivityHelperService ) {} get isDevelopMode(): boolean { @@ -39,7 +42,8 @@ export class CylinderService { const keysToDelete = cylinder.keys.filter(k => k.cylinder.length == 1); await this.keyRepo.softRemove(keysToDelete); - await this.cylinderRepo.softDelete({id: cylinder.id}) + await this.cylinderRepo.softDelete({id: cylinder.id}); + this.activityService.logCylinderDeleted(user, cylinder) return; } @@ -65,4 +69,27 @@ export class CylinderService { }); return c } + + getDeletedCylinders(user: User) { + return this.cylinderRepo.find({ + where: { + system: { managers: { id: user.id } }, + deletedAt: Not(IsNull()), + }, + withDeleted: true, + order: { deletedAt: { direction: 'DESC' } }, + }); + } + + async restoreCylinder(user: User, keyID: string) { + + const cylinder = await this.cylinderRepo.findOneOrFail({ + where: { system: { managers: { id: user.id } } , id: keyID }, + withDeleted: true, + }); + cylinder.deletedAt = null; + await this.activityService.logCylinderRestored(user, cylinder); + await this.helper.deleteKeyArchiveCache(); + return this.cylinderRepo.save(cylinder); + } } diff --git a/api/src/modules/key/key.controller.ts b/api/src/modules/key/key.controller.ts index f1e04c5..9b65019 100644 --- a/api/src/modules/key/key.controller.ts +++ b/api/src/modules/key/key.controller.ts @@ -63,7 +63,7 @@ export class KeyController { return this.service.getKeyHandovers(req.user, id); } - @Get('Archive') + @Get('archive') getArchive(@Req() req: AuthenticatedRequest) { return this.service.getDeletedKeys(req.user); } diff --git a/api/src/modules/key/key.service.ts b/api/src/modules/key/key.service.ts index abb3a52..c987ed5 100644 --- a/api/src/modules/key/key.service.ts +++ b/api/src/modules/key/key.service.ts @@ -74,7 +74,19 @@ export class KeyService { } if (k.keyLost != key.keyLost) { await this.activityService.logKeyLostUpdate(user, key, key.keyLost); - } + try { + const k = await this.keyrepository.findOne({ + where: { id: key.id }, + relations: ['cylinder', 'cylinder.system', 'cylinder.system.managers', 'cylinder.system.managers.settings'], + withDeleted: false + }); + for (const to of k.cylinder[0].system.managers.filter(m => m.settings.sendSystemUpdateMails)) { + this.mailService.sendKeyLostOrFoundMail({ key, to } ) + } + } catch (e) { + console.error(e); + } + } return this.keyrepository.save(this.keyrepository.create(key)); } diff --git a/api/src/modules/log/log.service.ts b/api/src/modules/log/log.service.ts index 46a09c3..3fdaf3f 100644 --- a/api/src/modules/log/log.service.ts +++ b/api/src/modules/log/log.service.ts @@ -36,7 +36,8 @@ export enum LogType { export enum EmailEvent { GrantSystemAccess, RemoveSystemAccess, - KeyHandout + KeyHandout, + KeyLostOrFound } export interface EmailLogDto { diff --git a/api/src/modules/mail/mail.service.ts b/api/src/modules/mail/mail.service.ts index 7cf44f1..a0a98fa 100644 --- a/api/src/modules/mail/mail.service.ts +++ b/api/src/modules/mail/mail.service.ts @@ -10,10 +10,52 @@ export class MailService { constructor( private mailserService: MailerService, private readonly configService: ConfigService, - private readonly logService: LogService, + private readonly logService: LogService ) { } + async sendKeyLostOrFoundMail({to, key}: {to: User, key: Key}) { + // const subject + const keyAction = key.keyLost == null ? 'wurde gefunden' : 'wurde als verloren gemeldet'; + const keyExtendedAction = key.keyLost == null ? `wurde als gefunden gemeldet` : `wurde am ${new Date(key.keyLost).toLocaleDateString()} als verloren gemeldet`; + const subject = key.keyLost == null ? 'Schlüssel gefunden' : 'Schlüssel verloren'; + 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('MAILER_FROM'), + subject: subject, + context + }).then(v => { + + this.logService.log(LogType.Mail, { + to: to.username, + success: true, + message: v.response, + type: EmailEvent.KeyLostOrFound, + system: key.cylinder[0].system, + context: JSON.stringify(key) + }) + }).catch(e => { + this.logService.log(LogType.Mail, { + to, + success: false, + message: e.response, + type: EmailEvent.KeyLostOrFound, + system: key.cylinder[0].system, + context: JSON.stringify(key) + }) + }) + } + 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`; diff --git a/api/src/modules/system/system.service.ts b/api/src/modules/system/system.service.ts index 607cd0c..8e826cc 100644 --- a/api/src/modules/system/system.service.ts +++ b/api/src/modules/system/system.service.ts @@ -44,6 +44,7 @@ export class SystemService { let systems = await this.systemRepo.find({ where: { managers: { id: user.id } }, order: { name: { direction: 'ASC' } }, + relations: ['cylinders'] }); if (this.isDevelopMode) { diff --git a/api/src/modules/user/user.controller.ts b/api/src/modules/user/user.controller.ts index 187e84d..87e01db 100644 --- a/api/src/modules/user/user.controller.ts +++ b/api/src/modules/user/user.controller.ts @@ -4,8 +4,6 @@ import { UserService } from './user.service'; import { User } from 'src/model/entitites'; import { IUser } from 'src/model/interface'; import { AuthenticatedRequest } from 'src/model/interface/authenticated-request.interface'; -import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util'; -import { HttpStatusCode } from 'axios'; import { UserSettings } from 'src/model/entitites/user/user.settings.entity'; @UseGuards(AuthGuard) diff --git a/api/src/modules/user/user.service.ts b/api/src/modules/user/user.service.ts index 5a1c6a4..a38c5d4 100644 --- a/api/src/modules/user/user.service.ts +++ b/api/src/modules/user/user.service.ts @@ -46,7 +46,7 @@ export class UserService { const keys = cylinders.map(c => c.keys).flat().map(k => k.id); const keycount = [...new Set(keys)] - const handedOut = (await this.helper.getUsersKeys(user)).filter(k => k.handedOut).length; + const handedOut = (await this.helper.getUsersKeys(user)).filter(k => k.handedOut && k.keyLost == null).length; return { keys: keycount.length, cylinders: cylinders.length, diff --git a/api/src/shared/service/activity.logger.service.ts b/api/src/shared/service/activity.logger.service.ts index bb3eda4..3e99962 100644 --- a/api/src/shared/service/activity.logger.service.ts +++ b/api/src/shared/service/activity.logger.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@nestjs/common"; -import { Key, KeyHandout, User } from "src/model/entitites"; +import { Cylinder, Key, KeyHandout, User } from "src/model/entitites"; import { KeySystem } from "src/model/entitites/system.entity"; import { ActivityRepository, CylinderRepository, KeyRepository } from "src/model/repositories"; import { HelperService } from "./system.helper.service"; @@ -115,4 +115,30 @@ export class ActivityHelperService { message: msg, })) } + + async logCylinderRestored(user: User, cylinder: Cylinder) { + let msg = `Zylinder ${cylinder.name} wiederhergestellt`; + + const system: KeySystem = await this.helper.getSystemOCylinder(cylinder); + + this.activityRepo.save( + this.activityRepo.create({ + system, + user, + message: msg, + })) + } + + async logCylinderDeleted(user: User, cylinder: Cylinder) { + let msg = `Zylinder ${cylinder.name} gelöscht`; + + const system: KeySystem = await this.helper.getSystemOCylinder(cylinder); + + this.activityRepo.save( + this.activityRepo.create({ + system, + user, + message: msg, + })) + } } \ No newline at end of file diff --git a/api/src/shared/service/system.helper.service.ts b/api/src/shared/service/system.helper.service.ts index 02418ed..67c0aab 100644 --- a/api/src/shared/service/system.helper.service.ts +++ b/api/src/shared/service/system.helper.service.ts @@ -50,6 +50,16 @@ export class HelperService { return found.system; } + async getSystemOCylinder(cylinder: Cylinder): Promise { + const k = await this.cylinderRepository.findOne({ + where: { id: cylinder.id }, + relations: ['system'], + withDeleted: true, + }); + this.cache() + return k.system; + } + async cache() { const value = await this.cacheManager.store.keys() console.log(value) diff --git a/client/src/app/app.config.ts b/client/src/app/app.config.ts index 30563d4..6e1f4e5 100644 --- a/client/src/app/app.config.ts +++ b/client/src/app/app.config.ts @@ -7,6 +7,7 @@ import { provideHttpClient, withInterceptors } from '@angular/common/http'; import { tokenInterceptor } from './core/interceptor/token.interceptor'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { provideServiceWorker } from '@angular/service-worker'; +import { OVERLAY_DEFAULT_CONFIG } from "@angular/cdk/overlay"; export const appConfig: ApplicationConfig = { providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideHttpClient(withInterceptors([tokenInterceptor])) @@ -17,11 +18,18 @@ export const appConfig: ApplicationConfig = { theme: 'toast', autoClose: true, dismissible: false, - duration: 5000 + duration: 5000, + }), provideAnimationsAsync(), provideServiceWorker('ngsw-worker.js', { enabled: !isDevMode(), registrationStrategy: 'registerWhenStable:30000' - }) + }), + { + provide: OVERLAY_DEFAULT_CONFIG, + useValue: { + usePopover: false, + }, +}, ] }; diff --git a/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.html b/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.html new file mode 100644 index 0000000..a0cd097 --- /dev/null +++ b/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.html @@ -0,0 +1,15 @@ +

Gelöschte Zylinder

+ + @if(myTheme && gridOptions) { + + } + + + + + \ No newline at end of file diff --git a/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.scss b/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.spec.ts b/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.spec.ts new file mode 100644 index 0000000..d747b5b --- /dev/null +++ b/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CylinderArchiveComponent } from './cylinder-archive.component'; + +describe('CylinderArchiveComponent', () => { + let component: CylinderArchiveComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CylinderArchiveComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CylinderArchiveComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.ts b/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.ts new file mode 100644 index 0000000..c95b2cb --- /dev/null +++ b/client/src/app/modules/cylinder/components/cylinder-archive/cylinder-archive.component.ts @@ -0,0 +1,78 @@ +import { Component, inject, LOCALE_ID } from '@angular/core'; +import { AgGridContainerComponent } from '../../../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component'; +import { CommonModule, DatePipe } from '@angular/common'; +import { HotToastService } from '@ngxpert/hot-toast'; +import { ApiService } from '../../../../shared/api.service'; +import { GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community'; +import { HELPER } from '../../../../shared/helper.service'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { AgGridAngular } from 'ag-grid-angular'; +import { ICylinder } from '../../../../model/interface/cylinder.interface'; + +@Component({ + selector: 'app-cylinder-archive', + imports: [MatDialogModule, AgGridAngular, MatButtonModule, MatIconModule, CommonModule], + providers: [DatePipe, { provide: LOCALE_ID, useValue: 'de-DE' }], + templateUrl: './cylinder-archive.component.html', + styleUrl: './cylinder-archive.component.scss', +}) +export class CylinderArchiveComponent extends AgGridContainerComponent { + private api: ApiService = inject(ApiService); + private datePipe = inject(DatePipe); + private toast = inject(HotToastService); + + gridApi!: GridApi; + + gridOptions: GridOptions = HELPER.getGridOptions(); + + constructor() { + super(); + + this.createGridOptions(); + + } + + private createGridOptions() { + this.gridOptions.columnDefs = [ + { colId: 'name', field: 'name' , headerName: 'Name', flex: 1, editable: true, sort: 'asc', filter: true }, + { colId: 'nr', field: 'nr' , headerName: 'Name', flex: 1, editable: true, filter: true }, + { + field: 'deletedAt' + , headerName: 'Gelöscht' + , width: 160 + , cellRenderer: (data: any) => this.datePipe.transform(new Date(data.value), 'short') + }, + { + width: 40, + cellRenderer: () => '
', + onCellClicked: (event) => { this.restoreCylinder(event.data);}, + tooltipValueGetter: () => 'Wiederherstellen', + sortable: false + } + ]; + this.gridOptions.rowHeight = 36; + this.gridOptions.overlayNoRowsTemplate = 'Bisher wurden keine Zylinder gelöscht. Sobald dies der Fall ist, werden sie hier angezeigt.'; + } + + + async restoreCylinder(data: ICylinder) { + this.gridApi.setGridOption("loading", true); + await this.api.restoreCylinder(data.id); + this.loadCylinders(); + } + + onGridReady(params: GridReadyEvent) { + this.gridApi = params.api; + this.loadCylinders(); + } + + async loadCylinders() { + this.gridApi.setGridOption("loading", true); + const cylinders = await this.api.getCylinderArchive(); + this.gridApi.setGridOption("rowData", cylinders); + this.gridApi.setGridOption("loading", false); + } + +} diff --git a/client/src/app/modules/cylinder/cylinder.component.html b/client/src/app/modules/cylinder/cylinder.component.html index ebcfad8..642979c 100644 --- a/client/src/app/modules/cylinder/cylinder.component.html +++ b/client/src/app/modules/cylinder/cylinder.component.html @@ -8,5 +8,5 @@ }
- +
\ No newline at end of file diff --git a/client/src/app/modules/cylinder/cylinder.component.ts b/client/src/app/modules/cylinder/cylinder.component.ts index af2c3e1..2981d60 100644 --- a/client/src/app/modules/cylinder/cylinder.component.ts +++ b/client/src/app/modules/cylinder/cylinder.component.ts @@ -10,6 +10,7 @@ import { CreateCylinderComponent } from './components/create-cylinder/create-cyl import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { AgGridContainerComponent } from '../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component'; +import { CylinderArchiveComponent } from './components/cylinder-archive/cylinder-archive.component'; @Component({ selector: 'app-cylinder', @@ -76,4 +77,14 @@ export class CylinderComponent extends AgGridContainerComponent { } }); } + + openArchive() { + this.dialog.open(CylinderArchiveComponent, { + maxHeight: "calc(100vh - 24px)", + maxWidth: "calc(100vw - 24px)", + width: "50vw", + minWidth: "min(700px,calc(100vw - 24px))", + height: "70vh", + }) + } } diff --git a/client/src/app/modules/keys/components/archive/archive.component.html b/client/src/app/modules/keys/components/archive/archive.component.html index a42e2d7..2ac8e31 100644 --- a/client/src/app/modules/keys/components/archive/archive.component.html +++ b/client/src/app/modules/keys/components/archive/archive.component.html @@ -1,10 +1,13 @@

Gelöschte Schlüssel

- + } diff --git a/client/src/app/modules/keys/components/archive/archive.component.ts b/client/src/app/modules/keys/components/archive/archive.component.ts index c956c45..7d12f09 100644 --- a/client/src/app/modules/keys/components/archive/archive.component.ts +++ b/client/src/app/modules/keys/components/archive/archive.component.ts @@ -11,6 +11,7 @@ import { IKey } from '../../../../model/interface/key.interface'; import { HotToastService } from '@ngxpert/hot-toast'; import { AgLoadingComponent } from '../../../../shared/ag-grid/components/ag-loading/ag-loading.component'; import { HELPER } from '../../../../shared/helper.service'; +import { AgGridContainerComponent } from '../../../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component'; @Component({ selector: 'app-archive', @@ -19,7 +20,7 @@ import { HELPER } from '../../../../shared/helper.service'; templateUrl: './archive.component.html', styleUrl: './archive.component.scss' }) -export class ArchiveComponent { +export class ArchiveComponent extends AgGridContainerComponent { private api: ApiService = inject(ApiService); private datePipe = inject(DatePipe); private toast = inject(HotToastService); @@ -31,6 +32,7 @@ export class ArchiveComponent { gridOptions: GridOptions = HELPER.getGridOptions(); constructor() { + super(); this.gridOptions.columnDefs = [ { colId: 'name', field: 'name' , headerName: 'Name', flex: 1, editable: true, sort: 'asc', filter: true }, { colId: 'nr', field: 'nr' , headerName: 'Schlüsselnummer', flex: 1, editable: true, filter: true }, @@ -87,6 +89,9 @@ export class ArchiveComponent { }, error: () => { this.gridApi.setGridOption("loading", false); + }, + complete: () => { + this.api.refreshKeys(); } }); } diff --git a/client/src/app/modules/keys/components/lost-keys/lost-keys.component.html b/client/src/app/modules/keys/components/lost-keys/lost-keys.component.html index 7e314d7..5719cf2 100644 --- a/client/src/app/modules/keys/components/lost-keys/lost-keys.component.html +++ b/client/src/app/modules/keys/components/lost-keys/lost-keys.component.html @@ -1,10 +1,13 @@

Verlorene Schlüssel

- + } diff --git a/client/src/app/modules/keys/components/lost-keys/lost-keys.component.ts b/client/src/app/modules/keys/components/lost-keys/lost-keys.component.ts index c0292c4..10036d7 100644 --- a/client/src/app/modules/keys/components/lost-keys/lost-keys.component.ts +++ b/client/src/app/modules/keys/components/lost-keys/lost-keys.component.ts @@ -10,6 +10,7 @@ import { HELPER } from '../../../../shared/helper.service'; import { AgGridAngular } from 'ag-grid-angular'; import { LostKeyComponent } from '../lost-key/lost-key.component'; import { MatButtonModule } from '@angular/material/button'; +import { AgGridContainerComponent } from '../../../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component'; @Component({ selector: 'app-lost-keys', @@ -18,7 +19,7 @@ import { MatButtonModule } from '@angular/material/button'; templateUrl: './lost-keys.component.html', styleUrl: './lost-keys.component.scss' }) -export class LostKeysComponent { +export class LostKeysComponent extends AgGridContainerComponent { private api: ApiService = inject(ApiService); private datePipe = inject(DatePipe); private dialog: MatDialog = inject(MatDialog); @@ -31,6 +32,7 @@ export class LostKeysComponent { gridOptions: GridOptions = HELPER.getGridOptions(); constructor() { + super(); this.gridOptions.columnDefs = [ { colId: 'name', field: 'name', headerName: 'Name', sort: 'asc', flex: 1, filter: true }, { colId: 'nr', field: 'nr', headerName: 'Schlüsselnummer', flex: 1, filter: true }, @@ -83,6 +85,7 @@ export class LostKeysComponent { next: () => { this.toast.success('Schlüssel als gefunden markiert'); this.loadLostKeys(); + this.api.refreshKeys(); } }); this.dataChanged = true; diff --git a/client/src/app/modules/system/components/system-manager/system-manager.component.html b/client/src/app/modules/system/components/system-manager/system-manager.component.html index 541152d..0a3366f 100644 --- a/client/src/app/modules/system/components/system-manager/system-manager.component.html +++ b/client/src/app/modules/system/components/system-manager/system-manager.component.html @@ -4,18 +4,21 @@
- + }
Email - Emailadresse des neuen Users eingeben + Emailadresse des Benutzers eingeben email