Dashboard
This commit is contained in:
28
api/src/model/entitites/activity.entity.ts
Normal file
28
api/src/model/entitites/activity.entity.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { User } from './user.entity';
|
||||
import { KeySystem } from './system.entity';
|
||||
|
||||
@Entity()
|
||||
export class Activity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
user: User;
|
||||
|
||||
@ManyToOne(() => KeySystem)
|
||||
system: KeySystem;
|
||||
|
||||
@Column({ type: 'text'})
|
||||
message: string;
|
||||
}
|
||||
@@ -6,3 +6,4 @@ export * from './key.entity';
|
||||
export * from './key_activity.entity';
|
||||
export * from './customer.entity';
|
||||
export * from './key-handout.entity';
|
||||
export * from './activity.entity';
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from 'typeorm';
|
||||
import { Key } from './key.entity';
|
||||
import { Customer } from './customer.entity';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity()
|
||||
export class KeyHandout {
|
||||
@@ -29,6 +30,9 @@ export class KeyHandout {
|
||||
@CreateDateColumn()
|
||||
created: Date;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
user: User;
|
||||
|
||||
@BeforeInsert()
|
||||
insertTimestamp() {
|
||||
if (this.timestamp == null) {
|
||||
|
||||
@@ -6,12 +6,14 @@ import {
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { Cylinder } from './cylinder.entity';
|
||||
import { IKey } from '../interface/key.interface';
|
||||
import { Customer } from './customer.entity';
|
||||
import { KeyHandout } from './key-handout.entity';
|
||||
|
||||
@Entity()
|
||||
export class Key implements IKey {
|
||||
@@ -45,4 +47,7 @@ export class Key implements IKey {
|
||||
|
||||
@DeleteDateColumn()
|
||||
deletedAt: Date;
|
||||
|
||||
@OneToMany(() => KeyHandout, (handout) => handout.key)
|
||||
handouts: KeyHandout[];
|
||||
}
|
||||
|
||||
10
api/src/model/repositories/activity.repository.ts
Normal file
10
api/src/model/repositories/activity.repository.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Repository, DataSource } from 'typeorm';
|
||||
import { Activity } from '../entitites';
|
||||
|
||||
@Injectable()
|
||||
export class ActivityRepository extends Repository<Activity> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(Activity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@@ -6,3 +6,4 @@ export * from './cylinder.repository';
|
||||
export * from './key.repository';
|
||||
export * from './key_activity.repository';
|
||||
export * from './customer.repository';
|
||||
export * from './activity.repository';
|
||||
|
||||
@@ -2,6 +2,7 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { Customer, Cylinder, Key, User } from 'src/model/entitites';
|
||||
import { IUser } from 'src/model/interface';
|
||||
import {
|
||||
ActivityRepository,
|
||||
CylinderRepository,
|
||||
KeyActivityRepository,
|
||||
KeyRepository,
|
||||
@@ -18,6 +19,7 @@ export class KeyService {
|
||||
private readonly systemRepo: KeySystemRepository,
|
||||
private activityRepo: KeyActivityRepository,
|
||||
private handoverRepo: KeyHandoutRepository,
|
||||
private systemActivityRepo: ActivityRepository,
|
||||
) {}
|
||||
|
||||
async getUsersKeys(user: User): Promise<Key[]> {
|
||||
@@ -74,19 +76,30 @@ export class KeyService {
|
||||
async handoverKey(user: IUser, data: any, keyID: string) {
|
||||
const key: Key = await this.keyrepository.findOneOrFail({
|
||||
where: { id: keyID, cylinder: { system: { managers: { id: user.id } } } },
|
||||
relations: [ 'cylinder', 'cylinder.system' ]
|
||||
});
|
||||
|
||||
key.handedOut = data.direction == 'out';
|
||||
this.keyrepository.save(key);
|
||||
|
||||
return this.handoverRepo.save(
|
||||
const res = await this.handoverRepo.save(
|
||||
this.handoverRepo.create({
|
||||
customer: data.customer,
|
||||
direction: data.direction,
|
||||
timestamp: data.timestamp,
|
||||
key: key,
|
||||
user: user as any
|
||||
}),
|
||||
);
|
||||
|
||||
const msg = `Schlüssel ${key.nr} ${res.direction == 'out' ? 'ausgegeben an ' : 'zurückgegeben von '}${res.customer.name}`
|
||||
this.systemActivityRepo.save(
|
||||
this.systemActivityRepo.create({
|
||||
system: key.cylinder[0].system,
|
||||
user: user as any,
|
||||
message: msg,
|
||||
}))
|
||||
return res;
|
||||
}
|
||||
|
||||
getKeyHandovers(user: User, keyID: string) {
|
||||
@@ -121,8 +134,14 @@ export class KeyService {
|
||||
}
|
||||
}
|
||||
|
||||
createKey(user: User, key: any) {
|
||||
return this.keyrepository.save(this.keyrepository.create(key));
|
||||
async createKey(user: User, key: any) {
|
||||
const k = await this.keyrepository.save(this.keyrepository.create(key));
|
||||
this.systemActivityRepo.save({
|
||||
message: `Schlüssel ${(k as any).nr} angelegt`,
|
||||
user: user,
|
||||
system: (k as any).cylinder[0].system
|
||||
});
|
||||
return k;
|
||||
}
|
||||
|
||||
async deleteKey(user: User, id: string) {
|
||||
|
||||
@@ -33,15 +33,19 @@ export class SystemController {
|
||||
return this.systemService.findAll(req.user);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.systemService.findOne(id);
|
||||
}
|
||||
|
||||
@Get(':id/manager')
|
||||
getManagers(@Param('id') id: string) {
|
||||
return this.systemService.getManagers(id);
|
||||
}
|
||||
@Post(':id/manager')
|
||||
manaManager(@Param('id') id: string, @Body() body: any){
|
||||
return this.systemService.manageManagers(id, body);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.systemService.findOne(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
update(@Param('id') id: string, @Body() updateSystemDto: UpdateSystemDto) {
|
||||
@@ -52,9 +56,4 @@ export class SystemController {
|
||||
remove(@Param('id') id: string) {
|
||||
return this.systemService.remove(id);
|
||||
}
|
||||
|
||||
@Post(':id/manager')
|
||||
manaManager(@Param('id') id: string, @Body() body: any){
|
||||
return this.systemService.manageManagers(id, body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { CreateSystemDto } from './dto/create-system.dto';
|
||||
import { UpdateSystemDto } from './dto/update-system.dto';
|
||||
import { KeySystemRepository, UserRepository } from 'src/model/repositories';
|
||||
import { User } from 'src/model/entitites';
|
||||
import { IUser } from 'src/model/interface';
|
||||
|
||||
@Injectable()
|
||||
export class SystemService {
|
||||
|
||||
@@ -22,6 +22,16 @@ export class UserController {
|
||||
return this.userService.saveUser(user);
|
||||
}
|
||||
|
||||
@Get('stats')
|
||||
getStats(@Req() req: AuthenticatedRequest) {
|
||||
return this.userService.getUserStats(req.user);
|
||||
}
|
||||
|
||||
@Get('activities')
|
||||
getUseractivities(@Req() req: AuthenticatedRequest) {
|
||||
return this.userService.getActivitiesforUser(req.user)
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
deleteUserWithId(@Req() req: AuthenticatedRequest, @Param('id') id: string) {
|
||||
if (req.user.role.name != "admin") {
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { User } from 'src/model/entitites';
|
||||
import { IUser } from 'src/model/interface';
|
||||
import { RoleRepository, UserRepository } from 'src/model/repositories';
|
||||
import { ActivityRepository, KeyActivityRepository, KeySystemRepository, RoleRepository, UserRepository } from 'src/model/repositories';
|
||||
import { FindOperator, FindOperators } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(
|
||||
private readonly userRepo: UserRepository,
|
||||
private readonly roleRepo: RoleRepository,
|
||||
private readonly systemRepo: KeySystemRepository,
|
||||
private readonly systemActivityRepo: ActivityRepository
|
||||
) {}
|
||||
|
||||
getAllUsers(): Promise<User[]> {
|
||||
@@ -28,4 +31,30 @@ export class UserService {
|
||||
return this.userRepo.deleteUserById(id);
|
||||
}
|
||||
|
||||
async getUserStats(user: IUser) {
|
||||
const systems = await this.systemRepo.find({
|
||||
where: { managers: { id: user.id }},
|
||||
relations: ['cylinders', 'cylinders.keys'],
|
||||
|
||||
});
|
||||
|
||||
const cylinders = systems.map(s => s.cylinders).flat()
|
||||
const keys = cylinders.map(c => c.keys).flat().map(k => k.id);
|
||||
const keycount = [...new Set(keys)]
|
||||
|
||||
return {
|
||||
keys: keycount.length,
|
||||
cylinders: cylinders.length,
|
||||
systems: systems.length
|
||||
}
|
||||
}
|
||||
|
||||
async getActivitiesforUser(user: IUser) {
|
||||
const activities = await this.systemActivityRepo.find({
|
||||
where: { system: { managers: { id: user.id } }},
|
||||
order: { createdAt: 'DESC' },
|
||||
relations: ['user']
|
||||
});
|
||||
return activities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import {
|
||||
Activity,
|
||||
Customer,
|
||||
Cylinder,
|
||||
Key,
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
} from 'src/model/entitites';
|
||||
import { KeySystem } from 'src/model/entitites/system.entity';
|
||||
import {
|
||||
ActivityRepository,
|
||||
CustomerRepository,
|
||||
CylinderRepository,
|
||||
KeyActivityRepository,
|
||||
@@ -33,6 +35,7 @@ const ENTITIES = [
|
||||
KeyActivity,
|
||||
Customer,
|
||||
KeyHandout,
|
||||
Activity,
|
||||
];
|
||||
const REPOSITORIES = [
|
||||
UserRepository,
|
||||
@@ -44,6 +47,7 @@ const REPOSITORIES = [
|
||||
KeyActivityRepository,
|
||||
CustomerRepository,
|
||||
KeyHandoutRepository,
|
||||
ActivityRepository,
|
||||
];
|
||||
|
||||
@Module({
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<div class="dashboard-container">
|
||||
<!-- Welcome Section -->
|
||||
<div class="welcome-section">
|
||||
<h1>Willkommen bei Keyvault Pro</h1>
|
||||
<p>Verwalte deine Schlüssel und Systeme</p>
|
||||
</div>
|
||||
|
||||
<!-- Quick Stats Cards -->
|
||||
<div class="stats-grid">
|
||||
<mat-card class="stat-card">
|
||||
<mat-card-header>
|
||||
<mat-icon>key</mat-icon>
|
||||
<mat-card-title>Schlüssel</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<span class="stat-number">{{ keyCount }}</span>
|
||||
<p>Aktive Schlüssel</p>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-button routerLink="/keys">Verwalten</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="stat-card">
|
||||
<mat-card-header>
|
||||
<mat-icon>lock</mat-icon>
|
||||
<mat-card-title>Zylinder</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<span class="stat-number">{{ cylinderCount }}</span>
|
||||
<p>Registrierte Zylinder</p>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-button routerLink="/cylinders">Verwalten</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="stat-card">
|
||||
<mat-card-header>
|
||||
<mat-icon>admin_panel_settings</mat-icon>
|
||||
<mat-card-title>Systeme</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<span class="stat-number">{{ systemCount }}</span>
|
||||
<p>Aktive Systeme</p>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-button routerLink="/systems">Verwalten</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity Section -->
|
||||
<div class="recent-activity">
|
||||
<h2>Letzte Aktivitäten</h2>
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<ag-grid-angular
|
||||
style="width: 100%; height: 300px;"
|
||||
[gridOptions]="gridOptions"
|
||||
(gridReady)="onGridReady($event)"
|
||||
>
|
||||
</ag-grid-angular>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,85 @@
|
||||
.dashboard-container {
|
||||
padding: 24px;
|
||||
height: calc(100% - 48px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
|
||||
.welcome-section {
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
margin: 0;
|
||||
color: #333;
|
||||
}
|
||||
p {
|
||||
margin: 8px 0 0 0;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 24px;
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
|
||||
mat-card-header {
|
||||
padding: 16px 16px 0;
|
||||
gap: 12px;
|
||||
|
||||
mat-icon {
|
||||
color: #2D6B05;
|
||||
}
|
||||
}
|
||||
|
||||
mat-card-content {
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
|
||||
.stat-number {
|
||||
font-size: 36px;
|
||||
font-weight: 500;
|
||||
color: #2D6B05;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0 0;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
mat-card-actions {
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recent-activity {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-height: 0;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
mat-card {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
mat-card-content {
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,62 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { AgGridAngular } from 'ag-grid-angular';
|
||||
import { ColDef } from 'ag-grid-community'; // Column Definition Type Interface
|
||||
import { ColDef, GridOptions, GridReadyEvent } from 'ag-grid-community'; // Column Definition Type Interface
|
||||
import { ApiService } from '../../shared/api.service';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import {MatCardModule} from '@angular/material/card';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AgLoadingComponent } from '../../shared/ag-grid/components/ag-loading/ag-loading.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
standalone: true,
|
||||
imports: [AgGridAngular],
|
||||
imports: [AgGridAngular, MatIconModule, AgGridAngular, MatCardModule, RouterModule],
|
||||
providers: [DatePipe],
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrl: './dashboard.component.scss'
|
||||
})
|
||||
export class DashboardComponent {
|
||||
private api = inject(ApiService);
|
||||
private datePipe = inject(DatePipe);
|
||||
|
||||
gridOptions: GridOptions = {
|
||||
columnDefs: [
|
||||
{ field: 'createdAt', headerName: 'Zeitpunkt', width: 160,
|
||||
cellRenderer: (data: any) => this.datePipe.transform(new Date(data.value)) },
|
||||
{ field: 'message', headerName: 'Aktion', flex: 1 },
|
||||
{ field: 'user', headerName: 'Benutzer', flex: 0,
|
||||
cellRenderer: (data: any) => `${data.value?.firstName} ${data.value?.lastName}` }
|
||||
],
|
||||
pagination: true,
|
||||
paginationPageSize: 10,
|
||||
loading: true,
|
||||
loadingOverlayComponent: AgLoadingComponent
|
||||
};
|
||||
|
||||
// Stats
|
||||
keyCount = 0;
|
||||
cylinderCount = 0;
|
||||
systemCount = 0;
|
||||
|
||||
ngOnInit() {
|
||||
this.loadStats();
|
||||
}
|
||||
|
||||
loadStats() {
|
||||
this.api.getStats().subscribe(stats => {
|
||||
this.keyCount = stats.keys;
|
||||
this.cylinderCount = stats.cylinders;
|
||||
this.systemCount = stats.systems;
|
||||
});
|
||||
}
|
||||
|
||||
onGridReady(params: GridReadyEvent) {
|
||||
params.api.setGridOption("loading", true);
|
||||
this.api.getActivities().subscribe(activity => {
|
||||
params.api.setGridOption("rowData", activity)
|
||||
params.api.setGridOption("loading", false);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
<h2 mat-dialog-title>Manager entfernen</h2>
|
||||
<mat-dialog-content>
|
||||
<div class="warning-message">
|
||||
<mat-icon color="warn">warning</mat-icon>
|
||||
<p>
|
||||
<b>{{ manager.firstName }} {{ manager.lastName }}</b> wirklich entfernen?
|
||||
Der Benutzer hat dann keinen Zugriff mehr auf das System mit allen seinen Daten.
|
||||
</p>
|
||||
<p class="additional-info">
|
||||
<!-- Additional information -->
|
||||
<small>Diese Aktion kann nicht rückgängig gemacht werden.</small>
|
||||
</p>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button [mat-dialog-close]="false">Abbrechen</button>
|
||||
<button mat-raised-button color="warn" [mat-dialog-close]="true">
|
||||
<mat-icon>delete</mat-icon>
|
||||
Entfernen
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -0,0 +1,19 @@
|
||||
.warning-message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
|
||||
mat-icon {
|
||||
font-size: 48px;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.additional-info {
|
||||
margin-top: 1rem;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RemoveManagerPopupComponent } from './remove-manager-popup.component';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
describe('RemoveManagerPopupComponent', () => {
|
||||
let component: RemoveManagerPopupComponent;
|
||||
let fixture: ComponentFixture<RemoveManagerPopupComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [RemoveManagerPopupComponent],
|
||||
providers: [
|
||||
{
|
||||
provide: MatDialogRef,
|
||||
useValue: []
|
||||
},
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: ''
|
||||
},
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RemoveManagerPopupComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
import { IUser } from '../../../../model/interface/user.interface';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
@Component({
|
||||
selector: 'app-remove-manager-popup',
|
||||
standalone: true,
|
||||
imports: [MatButtonModule, MatDialogModule, MatIconModule],
|
||||
templateUrl: './remove-manager-popup.component.html',
|
||||
styleUrl: './remove-manager-popup.component.scss'
|
||||
})
|
||||
export class RemoveManagerPopupComponent {
|
||||
readonly dialogRef = inject(MatDialogRef<RemoveManagerPopupComponent>);
|
||||
readonly manager = inject<IUser>(MAT_DIALOG_DATA);
|
||||
|
||||
}
|
||||
@@ -11,13 +11,20 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 items-center">
|
||||
<div class="flex gap-2 items-center p-4 bg-gray-50 rounded-md shadow-sm">
|
||||
<mat-form-field class="flex-1">
|
||||
<mat-label>Email</mat-label>
|
||||
<input matInput [(ngModel)]="email">
|
||||
<input matInput [(ngModel)]="email" placeholder="beispiel@email.com">
|
||||
<mat-hint>Emailadresse des neuen Users eingeben</mat-hint>
|
||||
<mat-icon matPrefix class="text-gray-400 mr-2">email</mat-icon>
|
||||
</mat-form-field>
|
||||
<button mat-button (click)="addManagerByEmail()" [disabled]="email == '' || email == null">Hinzufügen</button>
|
||||
<button mat-raised-button
|
||||
color="primary"
|
||||
(click)="addManagerByEmail()"
|
||||
[disabled]="email == '' || email == null">
|
||||
<mat-icon>person_add</mat-icon>
|
||||
Hinzufügen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
|
||||
@@ -1,3 +1,31 @@
|
||||
:host {
|
||||
min-height: 500px;
|
||||
}
|
||||
::ng-deep .ag-theme-alpine {
|
||||
--ag-row-hover-color: rgb(243 244 246);
|
||||
--ag-selected-row-background-color: rgb(229 231 235);
|
||||
}
|
||||
|
||||
.p-4 {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.bg-gray-50 {
|
||||
background-color: rgb(249 250 251);
|
||||
}
|
||||
|
||||
.rounded-md {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.shadow-sm {
|
||||
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
}
|
||||
|
||||
.text-gray-400 {
|
||||
color: rgb(156 163 175);
|
||||
}
|
||||
|
||||
.mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
@@ -12,11 +12,14 @@ import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { AuthService } from '../../../../core/auth/auth.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { RemoveManagerPopupComponent } from '../remove-manager-popup/remove-manager-popup.component';
|
||||
import { IUser } from '../../../../model/interface/user.interface';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
@Component({
|
||||
selector: 'app-system-manager',
|
||||
standalone: true,
|
||||
imports: [AgGridAngular, MatDialogModule, MatButtonModule, MatInputModule, MatFormFieldModule, CommonModule, FormsModule],
|
||||
imports: [AgGridAngular, MatDialogModule, MatButtonModule, MatInputModule, MatFormFieldModule, CommonModule, FormsModule, MatIconModule],
|
||||
templateUrl: './system-manager.component.html',
|
||||
styleUrl: './system-manager.component.scss'
|
||||
})
|
||||
@@ -51,7 +54,7 @@ export class SystemManagerComponent {
|
||||
return;
|
||||
}
|
||||
if (event.colDef.colId == 'delete') {
|
||||
this.removeManagerByEmail(event.data.username);
|
||||
this.removeManager(event.data);
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -95,12 +98,25 @@ export class SystemManagerComponent {
|
||||
});
|
||||
}
|
||||
|
||||
removeManagerByEmail(username: string) {
|
||||
const resume = confirm('Soll der Manager wirklich entfernt werden?');
|
||||
openPopup(manager: IUser): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
this.dialog.open(RemoveManagerPopupComponent, {
|
||||
data: manager,
|
||||
disableClose: false,
|
||||
autoFocus: false,
|
||||
}).afterClosed().subscribe({
|
||||
next: (n: boolean) => resolve(n)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async removeManager(manager: IUser) {
|
||||
|
||||
const resume = await this.openPopup(manager);
|
||||
if (!resume) return;
|
||||
|
||||
this.gridApi.setGridOption("loading", true);
|
||||
this.api.removeManager(this.system.id, username)
|
||||
this.api.removeManager(this.system.id, manager.username)
|
||||
.pipe(
|
||||
this.toast.observe({
|
||||
loading: 'Manager entfernen',
|
||||
|
||||
@@ -43,13 +43,5 @@ export class AgSystemManagerComponent implements ICellRendererAngularComp {
|
||||
height: "70vh",
|
||||
disableClose: false
|
||||
})
|
||||
|
||||
// ref.afterClosed().subscribe({
|
||||
// next: n => {
|
||||
// if (n) {
|
||||
// this.deleteThisKey();
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,4 +103,12 @@ export class ApiService {
|
||||
action: 'remove'
|
||||
});
|
||||
}
|
||||
|
||||
getStats(): Observable<{ keys: number, cylinders: number, systems: number }> {
|
||||
return this.http.get<{ keys: number, cylinders: number, systems: number }>('api/user/stats');
|
||||
}
|
||||
|
||||
getActivities(): Observable<any[]> {
|
||||
return this.http.get<any[]>('api/user/activities');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user