refactoring
This commit is contained in:
@@ -21,7 +21,7 @@ export class Cylinder {
|
|||||||
@Column({ nullable: false, unique: true })
|
@Column({ nullable: false, unique: true })
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@ManyToMany(() => Key, (key) => key.cylinder)
|
@ManyToMany(() => Key, (key) => key.cylinder, { onDelete: 'NO ACTION'})
|
||||||
keys: Key[];
|
keys: Key[];
|
||||||
|
|
||||||
@ManyToOne(() => KeySystem, (sys) => sys.cylinders)
|
@ManyToOne(() => KeySystem, (sys) => sys.cylinders)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ export * from './user.entity';
|
|||||||
export * from './role.entity';
|
export * from './role.entity';
|
||||||
export * from './cylinder.entity';
|
export * from './cylinder.entity';
|
||||||
export * from './key.entity';
|
export * from './key.entity';
|
||||||
export * from './key_activity.entity';
|
|
||||||
export * from './customer.entity';
|
export * from './customer.entity';
|
||||||
export * from './key-handout.entity';
|
export * from './key-handout.entity';
|
||||||
export * from './activity.entity';
|
export * from './activity.entity';
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
import {
|
|
||||||
Column,
|
|
||||||
CreateDateColumn,
|
|
||||||
Entity,
|
|
||||||
ManyToMany,
|
|
||||||
ManyToOne,
|
|
||||||
PrimaryGeneratedColumn,
|
|
||||||
} from 'typeorm';
|
|
||||||
import { User } from './user.entity';
|
|
||||||
import { IKey } from '../interface/key.interface';
|
|
||||||
import { Cylinder } from './cylinder.entity';
|
|
||||||
import { Customer } from './customer.entity';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class KeyActivity implements IKey {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
primaryId: number;
|
|
||||||
|
|
||||||
@Column()
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@Column({ nullable: true })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ name: 'key_number' })
|
|
||||||
nr: string;
|
|
||||||
|
|
||||||
@Column({ name: 'handed_out', default: false })
|
|
||||||
handedOut: boolean;
|
|
||||||
|
|
||||||
@ManyToMany(() => Cylinder)
|
|
||||||
cylinder: Cylinder[];
|
|
||||||
|
|
||||||
@ManyToOne(() => Customer)
|
|
||||||
customer: Customer;
|
|
||||||
|
|
||||||
@CreateDateColumn({ name: 'created_at' })
|
|
||||||
createdAt: Date;
|
|
||||||
|
|
||||||
@ManyToOne(() => User)
|
|
||||||
user: User;
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,5 @@ export * from './role.repository';
|
|||||||
export * from './system.repository';
|
export * from './system.repository';
|
||||||
export * from './cylinder.repository';
|
export * from './cylinder.repository';
|
||||||
export * from './key.repository';
|
export * from './key.repository';
|
||||||
export * from './key_activity.repository';
|
|
||||||
export * from './customer.repository';
|
export * from './customer.repository';
|
||||||
export * from './activity.repository';
|
export * from './activity.repository';
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { Repository, DataSource } from 'typeorm';
|
|
||||||
import { KeyActivity } from '../entitites';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class KeyActivityRepository extends Repository<KeyActivity> {
|
|
||||||
constructor(dataSource: DataSource) {
|
|
||||||
super(KeyActivity, dataSource.createEntityManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,9 +8,16 @@ export class CustomerService {
|
|||||||
constructor(private customerRepository: CustomerRepository) {}
|
constructor(private customerRepository: CustomerRepository) {}
|
||||||
|
|
||||||
createCustomer(user: IUser, data: any) {
|
createCustomer(user: IUser, data: any) {
|
||||||
if (!user || !data.name || data.name.length == 0 || !data.system) {
|
if (!user) {
|
||||||
throw new HttpException('invalid', HttpStatus.UNPROCESSABLE_ENTITY);
|
throw new HttpException({ message: 'Der Benutzer ist nicht verfügbar.', field: 'user' }, HttpStatus.UNPROCESSABLE_ENTITY);
|
||||||
}
|
}
|
||||||
|
if (!data.name || data.name.length === 0) {
|
||||||
|
throw new HttpException({ message: 'Der Name des Kunden ist erforderlich.', field: 'name' }, HttpStatus.UNPROCESSABLE_ENTITY);
|
||||||
|
}
|
||||||
|
if (!data.system) {
|
||||||
|
throw new HttpException({ message: 'Die Schließanlage ist nicht gefüllt.', field: 'system' }, HttpStatus.UNPROCESSABLE_ENTITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return this.customerRepository.save(this.customerRepository.create(data));
|
return this.customerRepository.save(this.customerRepository.create(data));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import { CylinderController } from './cylinder.controller';
|
|||||||
import { CylinderService } from './cylinder.service';
|
import { CylinderService } from './cylinder.service';
|
||||||
import { AuthModule } from '../auth/auth.module';
|
import { AuthModule } from '../auth/auth.module';
|
||||||
import { DatabaseModule } from 'src/shared/database/database.module';
|
import { DatabaseModule } from 'src/shared/database/database.module';
|
||||||
|
import { SharedServiceModule } from 'src/shared/service/shared.service.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [CylinderController],
|
controllers: [CylinderController],
|
||||||
providers: [CylinderService],
|
providers: [CylinderService],
|
||||||
imports: [AuthModule, DatabaseModule],
|
imports: [AuthModule, DatabaseModule, SharedServiceModule],
|
||||||
})
|
})
|
||||||
export class CylinderModule {}
|
export class CylinderModule {}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { Cylinder, User } from 'src/model/entitites';
|
import { Cylinder, User } from 'src/model/entitites';
|
||||||
import { ActivityRepository, CylinderRepository, KeyRepository } from 'src/model/repositories';
|
import { ActivityRepository, CylinderRepository, KeyRepository } from 'src/model/repositories';
|
||||||
|
import { ManageHelperService } from 'src/shared/service/system.helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CylinderService {
|
export class CylinderService {
|
||||||
@@ -8,6 +9,7 @@ export class CylinderService {
|
|||||||
private readonly cylinderRepo: CylinderRepository,
|
private readonly cylinderRepo: CylinderRepository,
|
||||||
private readonly keyRepo: KeyRepository,
|
private readonly keyRepo: KeyRepository,
|
||||||
private systemActivityRepo: ActivityRepository,
|
private systemActivityRepo: ActivityRepository,
|
||||||
|
private readonly helper: ManageHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getCylinders(user: User): Promise<Cylinder[]> {
|
async getCylinders(user: User): Promise<Cylinder[]> {
|
||||||
@@ -16,24 +18,26 @@ export class CylinderService {
|
|||||||
order: { name: { direction: 'ASC' } },
|
order: { name: { direction: 'ASC' } },
|
||||||
relations: ['system', 'keys'],
|
relations: ['system', 'keys'],
|
||||||
});
|
});
|
||||||
c.map((cc) => (cc.keys = []));
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteCylinder(user: User, cylinderid: string) {
|
async deleteCylinder(user: User, cylinderid: string) {
|
||||||
const cylinder = await this.cylinderRepo.findOneOrFail({
|
const cylinder = await this.helper.getCylinderIfUserCanManage(user, cylinderid, ['keys', 'system', 'keys.cylinder']);
|
||||||
where: { id: cylinderid, system: { managers: { id: user.id } } },
|
if (!cylinder) {
|
||||||
relations: ['keys'],
|
throw new HttpException('Zylinder nicht gefunden', HttpStatus.BAD_REQUEST)
|
||||||
});
|
}
|
||||||
await this.keyRepo.softRemove(cylinder.keys);
|
|
||||||
return this.cylinderRepo.softRemove(cylinder);
|
const keysToDelete = cylinder.keys.filter(k => k.cylinder.length == 1);
|
||||||
|
await this.keyRepo.softRemove(keysToDelete);
|
||||||
|
await this.cylinderRepo.softDelete({id: cylinder.id})
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateCylinder(user: User, cylinder: Partial<Cylinder>) {
|
async updateCylinder(user: User, cylinder: Partial<Cylinder>) {
|
||||||
const original = await this.cylinderRepo.findOneOrFail({
|
const original = await this.helper.getCylinderIfUserCanManage(user, cylinder.id);
|
||||||
where: { id: cylinder.id, system: { managers: { id: user.id } } },
|
if (!original) {
|
||||||
relations: ['keys', 'system'],
|
throw new HttpException('Zylinder nicht gefunden', HttpStatus.BAD_REQUEST)
|
||||||
});
|
}
|
||||||
|
|
||||||
Object.keys(cylinder).forEach((k: string) => {
|
Object.keys(cylinder).forEach((k: string) => {
|
||||||
original[k] = cylinder[k];
|
original[k] = cylinder[k];
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import { KeyController } from './key.controller';
|
|||||||
import { KeyService } from './key.service';
|
import { KeyService } from './key.service';
|
||||||
import { DatabaseModule } from 'src/shared/database/database.module';
|
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';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [KeyController],
|
controllers: [KeyController],
|
||||||
providers: [KeyService],
|
providers: [KeyService],
|
||||||
imports: [DatabaseModule, AuthModule],
|
imports: [DatabaseModule, AuthModule, SharedServiceModule],
|
||||||
})
|
})
|
||||||
export class KeyModule {}
|
export class KeyModule {}
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { IUser } from 'src/model/interface';
|
|||||||
import {
|
import {
|
||||||
ActivityRepository,
|
ActivityRepository,
|
||||||
CylinderRepository,
|
CylinderRepository,
|
||||||
KeyActivityRepository,
|
|
||||||
KeyRepository,
|
KeyRepository,
|
||||||
KeySystemRepository,
|
KeySystemRepository,
|
||||||
} from 'src/model/repositories';
|
} from 'src/model/repositories';
|
||||||
import { KeyHandoutRepository } from 'src/model/repositories/key-handout.repository';
|
import { KeyHandoutRepository } from 'src/model/repositories/key-handout.repository';
|
||||||
|
import { ActivityHelperService } from 'src/shared/service/activity.logger.service';
|
||||||
import { IsNull, Not } from 'typeorm';
|
import { IsNull, Not } from 'typeorm';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -17,9 +17,8 @@ export class KeyService {
|
|||||||
private readonly keyrepository: KeyRepository,
|
private readonly keyrepository: KeyRepository,
|
||||||
private readonly cylinderRepository: CylinderRepository,
|
private readonly cylinderRepository: CylinderRepository,
|
||||||
private readonly systemRepo: KeySystemRepository,
|
private readonly systemRepo: KeySystemRepository,
|
||||||
private activityRepo: KeyActivityRepository,
|
|
||||||
private handoverRepo: KeyHandoutRepository,
|
private handoverRepo: KeyHandoutRepository,
|
||||||
private systemActivityRepo: ActivityRepository,
|
private readonly activityService: ActivityHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getUsersKeys(user: User): Promise<Key[]> {
|
async getUsersKeys(user: User): Promise<Key[]> {
|
||||||
@@ -41,25 +40,9 @@ export class KeyService {
|
|||||||
where: { cylinder: { system: { managers: { id: user.id } } } },
|
where: { cylinder: { system: { managers: { id: user.id } } } },
|
||||||
});
|
});
|
||||||
|
|
||||||
const original = await this.keyrepository.findOne({
|
|
||||||
where: { id: key.id },
|
|
||||||
relations: ['cylinder'],
|
|
||||||
});
|
|
||||||
this.saveLog(original, user);
|
|
||||||
return this.keyrepository.save(this.keyrepository.create(key));
|
return this.keyrepository.save(this.keyrepository.create(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
private saveLog(key: Key, user: User) {
|
|
||||||
const l = this.activityRepo.create({
|
|
||||||
cylinder: key.cylinder,
|
|
||||||
handedOut: key.handedOut,
|
|
||||||
name: key.name,
|
|
||||||
id: key.id,
|
|
||||||
nr: key.nr,
|
|
||||||
user: user,
|
|
||||||
});
|
|
||||||
this.activityRepo.save(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUsersCylinders(user: User): Promise<Cylinder[]> {
|
async getUsersCylinders(user: User): Promise<Cylinder[]> {
|
||||||
if (!user || !user.id) {
|
if (!user || !user.id) {
|
||||||
@@ -73,7 +56,7 @@ export class KeyService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async handoverKey(user: IUser, data: any, keyID: string) {
|
async handoverKey(user: User, data: any, keyID: string) {
|
||||||
const key: Key = await this.keyrepository.findOneOrFail({
|
const key: Key = await this.keyrepository.findOneOrFail({
|
||||||
where: { id: keyID, cylinder: { system: { managers: { id: user.id } } } },
|
where: { id: keyID, cylinder: { system: { managers: { id: user.id } } } },
|
||||||
relations: [ 'cylinder', 'cylinder.system' ]
|
relations: [ 'cylinder', 'cylinder.system' ]
|
||||||
@@ -92,13 +75,7 @@ export class KeyService {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const msg = `Schlüssel ${key.nr} ${res.direction == 'out' ? 'ausgegeben an ' : 'zurückgegeben von '}${res.customer.name}`
|
this.activityService.logKeyHandover(user, key, key.cylinder[0].system, res);
|
||||||
this.systemActivityRepo.save(
|
|
||||||
this.systemActivityRepo.create({
|
|
||||||
system: key.cylinder[0].system,
|
|
||||||
user: user as any,
|
|
||||||
message: msg,
|
|
||||||
}))
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,11 +113,7 @@ export class KeyService {
|
|||||||
|
|
||||||
async createKey(user: User, key: any) {
|
async createKey(user: User, key: any) {
|
||||||
const k = await this.keyrepository.save(this.keyrepository.create(key));
|
const k = await this.keyrepository.save(this.keyrepository.create(key));
|
||||||
this.systemActivityRepo.save({
|
this.activityService.logKeyCreated(user, key, key.cylinder[0].system);
|
||||||
message: `Schlüssel ${(k as any).nr} angelegt`,
|
|
||||||
user: user,
|
|
||||||
system: (k as any).cylinder[0].system
|
|
||||||
});
|
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export class SystemService {
|
|||||||
constructor(
|
constructor(
|
||||||
private systemRepo: KeySystemRepository,
|
private systemRepo: KeySystemRepository,
|
||||||
private userRepo: UserRepository,
|
private userRepo: UserRepository,
|
||||||
private systemActivityRepo: ActivityRepository,
|
private systemActivityRepo: ActivityRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(user: User, createSystemDto: CreateSystemDto) {
|
async create(user: User, createSystemDto: CreateSystemDto) {
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import { UserController } from './user.controller';
|
|||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
import { AuthModule } from '../auth/auth.module';
|
import { AuthModule } from '../auth/auth.module';
|
||||||
import { DatabaseModule } from 'src/shared/database/database.module';
|
import { DatabaseModule } from 'src/shared/database/database.module';
|
||||||
|
import { SharedServiceModule } from 'src/shared/service/shared.service.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [UserController],
|
controllers: [UserController],
|
||||||
providers: [UserService],
|
providers: [UserService],
|
||||||
imports: [AuthModule, DatabaseModule],
|
imports: [AuthModule, DatabaseModule, SharedServiceModule],
|
||||||
})
|
})
|
||||||
export class UserModule {}
|
export class UserModule {}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { User } from 'src/model/entitites';
|
import { User } from 'src/model/entitites';
|
||||||
import { IUser } from 'src/model/interface';
|
import { IUser } from 'src/model/interface';
|
||||||
import { ActivityRepository, KeyActivityRepository, KeySystemRepository, RoleRepository, UserRepository } from 'src/model/repositories';
|
import { ActivityRepository, KeySystemRepository, RoleRepository, UserRepository } from 'src/model/repositories';
|
||||||
import { FindOperator, FindOperators } from 'typeorm';
|
import { ManageHelperService } from 'src/shared/service/system.helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserService {
|
export class UserService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly userRepo: UserRepository,
|
private readonly userRepo: UserRepository,
|
||||||
private readonly roleRepo: RoleRepository,
|
private readonly roleRepo: RoleRepository,
|
||||||
private readonly systemRepo: KeySystemRepository,
|
private readonly systemRepo: KeySystemRepository,
|
||||||
private readonly systemActivityRepo: ActivityRepository
|
private readonly systemActivityRepo: ActivityRepository,
|
||||||
|
private readonly helper: ManageHelperService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getAllUsers(): Promise<User[]> {
|
getAllUsers(): Promise<User[]> {
|
||||||
@@ -31,7 +31,7 @@ export class UserService {
|
|||||||
return this.userRepo.deleteUserById(id);
|
return this.userRepo.deleteUserById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserStats(user: IUser) {
|
async getUserStats(user: User) {
|
||||||
const systems = await this.systemRepo.find({
|
const systems = await this.systemRepo.find({
|
||||||
where: { managers: { id: user.id }},
|
where: { managers: { id: user.id }},
|
||||||
relations: ['cylinders', 'cylinders.keys'],
|
relations: ['cylinders', 'cylinders.keys'],
|
||||||
@@ -42,10 +42,12 @@ export class UserService {
|
|||||||
const keys = cylinders.map(c => c.keys).flat().map(k => k.id);
|
const keys = cylinders.map(c => c.keys).flat().map(k => k.id);
|
||||||
const keycount = [...new Set(keys)]
|
const keycount = [...new Set(keys)]
|
||||||
|
|
||||||
|
const handedOut = (await this.helper.getUsersKeys(user)).filter(k => k.handedOut).length;
|
||||||
return {
|
return {
|
||||||
keys: keycount.length,
|
keys: keycount.length,
|
||||||
cylinders: cylinders.length,
|
cylinders: cylinders.length,
|
||||||
systems: systems.length
|
systems: systems.length,
|
||||||
|
handedOut: handedOut
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
Customer,
|
Customer,
|
||||||
Cylinder,
|
Cylinder,
|
||||||
Key,
|
Key,
|
||||||
KeyActivity,
|
|
||||||
KeyHandout,
|
KeyHandout,
|
||||||
Role,
|
Role,
|
||||||
SSOUser,
|
SSOUser,
|
||||||
@@ -16,7 +15,6 @@ import {
|
|||||||
ActivityRepository,
|
ActivityRepository,
|
||||||
CustomerRepository,
|
CustomerRepository,
|
||||||
CylinderRepository,
|
CylinderRepository,
|
||||||
KeyActivityRepository,
|
|
||||||
KeyRepository,
|
KeyRepository,
|
||||||
KeySystemRepository,
|
KeySystemRepository,
|
||||||
RoleRepository,
|
RoleRepository,
|
||||||
@@ -32,7 +30,6 @@ const ENTITIES = [
|
|||||||
KeySystem,
|
KeySystem,
|
||||||
Key,
|
Key,
|
||||||
Cylinder,
|
Cylinder,
|
||||||
KeyActivity,
|
|
||||||
Customer,
|
Customer,
|
||||||
KeyHandout,
|
KeyHandout,
|
||||||
Activity,
|
Activity,
|
||||||
@@ -44,7 +41,6 @@ const REPOSITORIES = [
|
|||||||
KeySystemRepository,
|
KeySystemRepository,
|
||||||
KeyRepository,
|
KeyRepository,
|
||||||
CylinderRepository,
|
CylinderRepository,
|
||||||
KeyActivityRepository,
|
|
||||||
CustomerRepository,
|
CustomerRepository,
|
||||||
KeyHandoutRepository,
|
KeyHandoutRepository,
|
||||||
ActivityRepository,
|
ActivityRepository,
|
||||||
|
|||||||
78
api/src/shared/service/activity.logger.service.ts
Normal file
78
api/src/shared/service/activity.logger.service.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
import { Key, KeyHandout, User } from "src/model/entitites";
|
||||||
|
import { KeySystem } from "src/model/entitites/system.entity";
|
||||||
|
import { ActivityRepository, CylinderRepository, KeyRepository } from "src/model/repositories";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ActivityHelperService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly activityRepo: ActivityRepository,
|
||||||
|
private readonly keyRepository: KeyRepository,
|
||||||
|
private readonly cylinderRepo: CylinderRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
|
||||||
|
async logDeleteKey(user: User, key: Key, system?: KeySystem) {
|
||||||
|
if (!key || !user) { return; }
|
||||||
|
|
||||||
|
|
||||||
|
if (!system && !key.cylinder) {
|
||||||
|
key = await this.keyRepository.findOne({
|
||||||
|
where: { id: key.id },
|
||||||
|
relations: ['cylinder', 'cylinder.system']
|
||||||
|
})
|
||||||
|
system = key.cylinder[0].system;
|
||||||
|
} else if (!system && !key.cylinder[0].system) {
|
||||||
|
const c = await this.cylinderRepo.findOne({
|
||||||
|
where: { id: key.cylinder[0].id },
|
||||||
|
relations: ['system']
|
||||||
|
});
|
||||||
|
if (!c) { return; }
|
||||||
|
system = c.system;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!system) { return; }
|
||||||
|
|
||||||
|
let msg = `Schlüssel ${key.nr} entfernt`;
|
||||||
|
|
||||||
|
this.activityRepo.save(
|
||||||
|
this.activityRepo.create({
|
||||||
|
system,
|
||||||
|
user,
|
||||||
|
message: msg,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async logKeyCreated(user: User, key: Key, system: KeySystem) {
|
||||||
|
let msg = `Schlüssel ${key.nr} angelegt`;
|
||||||
|
this.activityRepo.save(
|
||||||
|
this.activityRepo.create({
|
||||||
|
system,
|
||||||
|
user,
|
||||||
|
message: msg,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async logKeyRenamed(user: User, key: Key, system: KeySystem) {
|
||||||
|
let msg = `Schlüssel ${key.nr} in ${key.name} umbenannt`;
|
||||||
|
this.activityRepo.save(
|
||||||
|
this.activityRepo.create({
|
||||||
|
system,
|
||||||
|
user,
|
||||||
|
message: msg,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
logKeyHandover(user: User, key: Key, system: KeySystem, handover: KeyHandout) {
|
||||||
|
|
||||||
|
const msg = `Schlüssel ${key.nr} ${handover.direction == 'out' ? 'ausgegeben an ' : 'zurückgegeben von '}${handover.customer.name}`
|
||||||
|
this.activityRepo.save(
|
||||||
|
this.activityRepo.create({
|
||||||
|
system,
|
||||||
|
user,
|
||||||
|
message: msg,
|
||||||
|
}))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
18
api/src/shared/service/shared.service.module.ts
Normal file
18
api/src/shared/service/shared.service.module.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { DatabaseModule } from "../database/database.module";
|
||||||
|
import { ManageHelperService } from "./system.helper.service";
|
||||||
|
import { CylinderRepository, KeySystemRepository } from "src/model/repositories";
|
||||||
|
import { Cylinder, User } from "src/model/entitites";
|
||||||
|
import { ActivityHelperService } from "./activity.logger.service";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ DatabaseModule ],
|
||||||
|
providers: [ ManageHelperService, ActivityHelperService ],
|
||||||
|
exports: [ ManageHelperService, ActivityHelperService ],
|
||||||
|
})
|
||||||
|
|
||||||
|
export class SharedServiceModule {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
38
api/src/shared/service/system.helper.service.ts
Normal file
38
api/src/shared/service/system.helper.service.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
import { User, Cylinder, Key } from "src/model/entitites";
|
||||||
|
import { KeySystemRepository, CylinderRepository, KeyRepository } from "src/model/repositories";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ManageHelperService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly systemRepository: KeySystemRepository,
|
||||||
|
private readonly cylinderRepository: CylinderRepository,
|
||||||
|
private readonly keyRepo: KeyRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt den Cylinder zurück wenn der user ein Manager ist. Gibt null zurück wenn er nicht existiert oder der
|
||||||
|
* User den Cylinder nicht managen darf.
|
||||||
|
* @param user User
|
||||||
|
* @param id ID vom Cylinder
|
||||||
|
* @returns Cylinder | null
|
||||||
|
*/
|
||||||
|
async getCylinderIfUserCanManage(user: User, id: string, relations: string[] = ['keys', 'system']): Promise<Cylinder> {
|
||||||
|
const cylinder = await this.cylinderRepository.findOne({
|
||||||
|
where: { id: id, system: { managers: { id: user.id } } },
|
||||||
|
relations: relations,
|
||||||
|
});
|
||||||
|
return cylinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async getUsersKeys(user: User): Promise<Key[]> {
|
||||||
|
const keys = await this.keyRepo.find({
|
||||||
|
where: { cylinder: { system: { managers: { id: user.id } } } },
|
||||||
|
relations: ['cylinder', 'cylinder.system', 'customer'],
|
||||||
|
});
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<button mat-button routerLink="/" routerLinkActive="mat-elevation-z1" [routerLinkActiveOptions]="{exact: true}">Home</button>
|
<button mat-button routerLink="/" routerLinkActive="mat-elevation-z1" [routerLinkActiveOptions]="{exact: true}">Home</button>
|
||||||
<button mat-button routerLink="/keys" routerLinkActive="mat-elevation-z1">Schlüssel</button>
|
<button mat-button routerLink="/keys" routerLinkActive="mat-elevation-z1">Schlüssel</button>
|
||||||
<button mat-button routerLink="/cylinders" routerLinkActive="mat-elevation-z1">Zylinder</button>
|
<button mat-button routerLink="/cylinders" routerLinkActive="mat-elevation-z1">Zylinder</button>
|
||||||
<button mat-button routerLink="/systems" routerLinkActive="mat-elevation-z1">System</button>
|
<button mat-button routerLink="/systems" routerLinkActive="mat-elevation-z1">Schließanlagen</button>
|
||||||
@if (isAdmin) {
|
@if (isAdmin) {
|
||||||
<button mat-button routerLink="/users" routerLinkActive="mat-elevation-z1">Alle User</button>
|
<button mat-button routerLink="/users" routerLinkActive="mat-elevation-z1">Alle User</button>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export interface IKey {
|
|||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
handedOut: boolean;
|
handedOut: boolean;
|
||||||
cylinder: ICylinder;
|
cylinder: ICylinder[];
|
||||||
nr: number;
|
nr: number;
|
||||||
deletedAt?: string;
|
deletedAt?: string;
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
<h2 mat-dialog-title>Zylinder <u>{{key.name}}</u> löschen?</h2>
|
<h2 mat-dialog-title>Zylinder <u>{{cylinder.name}}</u> löschen?</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<p>Soll der Zylinder wirklich gelöscht werden? Alle {{ key.keyCount | number:'0.0-0'}} enthaltenen Schlüssel werden mit entfernt!</p>
|
<div class="warning-message">
|
||||||
|
<mat-icon color="warn">warning</mat-icon>
|
||||||
|
<p>
|
||||||
|
<b>{{cylinder.name}}</b> wirklich entfernen?
|
||||||
|
Alle Schlüssel die nur diesen Zylinder haben werden ebenfalls entfernt.
|
||||||
|
</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-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions align="end">
|
||||||
<button mat-button [mat-dialog-close]="false" >Abbrechen</button>
|
<button mat-button [mat-dialog-close]="false">Abbrechen</button>
|
||||||
<button mat-button [mat-dialog-close]="true" color="warn">Ja, löschen</button>
|
<button mat-raised-button color="warn" [mat-dialog-close]="true">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
Entfernen
|
||||||
|
</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -2,17 +2,19 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { Component, inject, LOCALE_ID } from '@angular/core';
|
import { Component, inject, LOCALE_ID } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { ICylinder } from '../../../../model/interface/cylinder.interface';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-delete-cylinder',
|
selector: 'app-delete-cylinder',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [MatDialogModule, MatButtonModule, CommonModule],
|
imports: [MatDialogModule, MatButtonModule, CommonModule, MatIconModule],
|
||||||
providers: [{ provide: LOCALE_ID, useValue: 'de-DE' },],
|
providers: [{ provide: LOCALE_ID, useValue: 'de-DE' },],
|
||||||
templateUrl: './delete-cylinder.component.html',
|
templateUrl: './delete-cylinder.component.html',
|
||||||
styleUrl: './delete-cylinder.component.scss'
|
styleUrl: './delete-cylinder.component.scss'
|
||||||
})
|
})
|
||||||
export class DeleteCylinderComponent {
|
export class DeleteCylinderComponent {
|
||||||
readonly dialogRef = inject(MatDialogRef<DeleteCylinderComponent>);
|
readonly dialogRef = inject(MatDialogRef<DeleteCylinderComponent>);
|
||||||
readonly key = inject<any>(MAT_DIALOG_DATA);
|
readonly cylinder = inject<ICylinder>(MAT_DIALOG_DATA);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<!-- Welcome Section -->
|
<!-- Welcome Section -->
|
||||||
<div class="welcome-section">
|
<!-- <div class="welcome-section">
|
||||||
<h1>Willkommen bei Keyvault Pro</h1>
|
<h1>Willkommen bei Keyvault Pro</h1>
|
||||||
<p>Verwalte deine Schlüssel und Systeme</p>
|
<p>Verwalte deine Schlüssel und Systeme</p>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- Quick Stats Cards -->
|
<!-- Quick Stats Cards -->
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
@@ -38,22 +38,36 @@
|
|||||||
<mat-card class="stat-card">
|
<mat-card class="stat-card">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<mat-icon>admin_panel_settings</mat-icon>
|
<mat-icon>admin_panel_settings</mat-icon>
|
||||||
<mat-card-title>Systeme</mat-card-title>
|
<mat-card-title>Schließanlagen</mat-card-title>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<span class="stat-number">{{ systemCount }}</span>
|
<span class="stat-number">{{ systemCount }}</span>
|
||||||
<p>Aktive Systeme</p>
|
<p>Aktive Schließanlagen</p>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions>
|
<mat-card-actions>
|
||||||
<button mat-button routerLink="/systems">Verwalten</button>
|
<button mat-button routerLink="/systems">Verwalten</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
||||||
|
<mat-card class="stat-card">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-icon>passkey</mat-icon>
|
||||||
|
<mat-card-title>Ausgegebene Schlüssel</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<span class="stat-number">{{ handedOut }}</span>
|
||||||
|
<p>Derzeit ausgegebene Schlüssel</p>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
<button mat-button routerLink="/keys">Verwalten</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Recent Activity Section -->
|
<!-- Recent Activity Section -->
|
||||||
<div class="recent-activity">
|
<div class="recent-activity">
|
||||||
<h2>Letzte Aktivitäten</h2>
|
<h2>Letzte Aktivitäten</h2>
|
||||||
<mat-card>
|
<mat-card style="background: white">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<ag-grid-angular
|
<ag-grid-angular
|
||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.dashboard-container {
|
.dashboard-container {
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
height: calc(100% - 48px);
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import {MatCardModule} from '@angular/material/card';
|
|||||||
import { RouterModule } from '@angular/router';
|
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';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [AgGridAngular, MatIconModule, AgGridAngular, MatCardModule, RouterModule],
|
imports: [AgGridAngular, MatIconModule, AgGridAngular, MatCardModule, RouterModule, MatButtonModule],
|
||||||
providers: [DatePipe],
|
providers: [DatePipe],
|
||||||
templateUrl: './dashboard.component.html',
|
templateUrl: './dashboard.component.html',
|
||||||
styleUrl: './dashboard.component.scss'
|
styleUrl: './dashboard.component.scss'
|
||||||
@@ -40,6 +41,7 @@ export class DashboardComponent {
|
|||||||
keyCount = 0;
|
keyCount = 0;
|
||||||
cylinderCount = 0;
|
cylinderCount = 0;
|
||||||
systemCount = 0;
|
systemCount = 0;
|
||||||
|
handedOut = 0;
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.loadStats();
|
this.loadStats();
|
||||||
@@ -50,6 +52,7 @@ export class DashboardComponent {
|
|||||||
this.keyCount = stats.keys;
|
this.keyCount = stats.keys;
|
||||||
this.cylinderCount = stats.cylinders;
|
this.cylinderCount = stats.cylinders;
|
||||||
this.systemCount = stats.systems;
|
this.systemCount = stats.systems;
|
||||||
|
this.handedOut = stats.handedOut;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
<h2 mat-dialog-title>Schlüssel {{key.name}} löschen?</h2>
|
<h2 mat-dialog-title>Schlüssel <u>{{key.name}}</u> löschen?</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<p>Soll der Schlüssel wirklich gelöscht werden?</p>
|
<div class="warning-message">
|
||||||
|
<mat-icon color="warn">warning</mat-icon>
|
||||||
|
<p>
|
||||||
|
<b>{{key.name}}</b> wirklich entfernen?
|
||||||
|
</p>
|
||||||
|
<p class="additional-info">
|
||||||
|
<!-- Additional information -->
|
||||||
|
<small>Gelöschte Schlüssel können über das Archiv wiederhergestellt werden.</small>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions align="end">
|
||||||
<button mat-button [mat-dialog-close]="false" >Abbrechen</button>
|
<button mat-button [mat-dialog-close]="false">Abbrechen</button>
|
||||||
<button mat-button [mat-dialog-close]="true" color="warn">Ja, löschen</button>
|
<button mat-raised-button color="warn" [mat-dialog-close]="true">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
Entfernen
|
||||||
|
</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -2,11 +2,12 @@ import { Component, inject } from '@angular/core';
|
|||||||
import { IKey } from '../../../../model/interface/key.interface';
|
import { IKey } from '../../../../model/interface/key.interface';
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-delete-key',
|
selector: 'app-delete-key',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [MatDialogModule, MatButtonModule],
|
imports: [MatDialogModule, MatButtonModule, MatIconModule],
|
||||||
templateUrl: './delete-key.component.html',
|
templateUrl: './delete-key.component.html',
|
||||||
styleUrl: './delete-key.component.scss'
|
styleUrl: './delete-key.component.scss'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -43,8 +43,8 @@
|
|||||||
</form>
|
</form>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button (click)="save()" [disabled]="handoverForm.invalid">Speichern</button>
|
|
||||||
<button mat-button mat-dialog-close color="warn" >Schließen</button>
|
<button mat-button mat-dialog-close color="warn" >Schließen</button>
|
||||||
|
<button mat-button (click)="save()" [disabled]="handoverForm.invalid">Speichern</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
|
|
||||||
|
|||||||
@@ -187,10 +187,17 @@ export class HandoverDialogComponent {
|
|||||||
createCustomer(name: string): Promise<any> {
|
createCustomer(name: string): Promise<any> {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.api.createCustomer({ name, system: this.data.cylinder.system}).subscribe({
|
this.api.createCustomer({ name, system: this.data.cylinder[0].system}).subscribe({
|
||||||
next: n => {
|
next: n => {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
resolve(n);
|
resolve(n);
|
||||||
|
},
|
||||||
|
error: e => {
|
||||||
|
this.isLoading = false;
|
||||||
|
const field = e.error.field;
|
||||||
|
const message = field ? e.error.message : 'Ein Fehler ist aufgetreten. Bitte versuche es später erneut';
|
||||||
|
this.toast.error(message);
|
||||||
|
reject(e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<mat-icon color="warn">warning</mat-icon>
|
<mat-icon color="warn">warning</mat-icon>
|
||||||
<p>
|
<p>
|
||||||
<b>{{ manager.firstName }} {{ manager.lastName }}</b> wirklich entfernen?
|
<b>{{ manager.firstName }} {{ manager.lastName }}</b> wirklich entfernen?
|
||||||
Der Benutzer hat dann keinen Zugriff mehr auf das System mit allen seinen Daten.
|
Der Benutzer hat dann keinen Zugriff mehr auf diese Schließanlage mit allen ihren Daten.
|
||||||
</p>
|
</p>
|
||||||
<p class="additional-info">
|
<p class="additional-info">
|
||||||
<!-- Additional information -->
|
<!-- Additional information -->
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<h2 mat-dialog-title>Neuen Schlüssel anlegen</h2>
|
<h2 mat-dialog-title>Neue Schließanlage anlegen</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<form [formGroup]="createForm" class="flex flex-col gap-3">
|
<form [formGroup]="createForm" class="flex flex-col gap-3">
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
@if ((createForm.controls.name.value || '').length > 20) {
|
@if ((createForm.controls.name.value || '').length > 20) {
|
||||||
<mat-hint>{{ (createForm.controls.name.value || '').length }} / 100 Zeichen</mat-hint>
|
<mat-hint>{{ (createForm.controls.name.value || '').length }} / 100 Zeichen</mat-hint>
|
||||||
} @else {
|
} @else {
|
||||||
<mat-hint>Wie soll der Schlüssel heißen?</mat-hint>
|
<mat-hint>Wie soll die Anlage heißen?</mat-hint>
|
||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="floating-btn-container">
|
<div class="floating-btn-container">
|
||||||
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateSystem()" color="accent" >System anlegen</button>
|
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateSystem()" color="accent" >Schließanlage anlegen</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,7 +35,9 @@ export class AgDeleteKeyComponent implements ICellRendererAngularComp {
|
|||||||
delete() {
|
delete() {
|
||||||
const ref = this.dialog.open(DeleteKeyComponent, {
|
const ref = this.dialog.open(DeleteKeyComponent, {
|
||||||
data: this.key,
|
data: this.key,
|
||||||
autoFocus: false
|
autoFocus: false,
|
||||||
|
width: '500px',
|
||||||
|
maxWidth: 'calc(100vw - 24px)',
|
||||||
})
|
})
|
||||||
|
|
||||||
ref.afterClosed().subscribe({
|
ref.afterClosed().subscribe({
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ export class ApiService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getStats(): Observable<{ keys: number, cylinders: number, systems: number }> {
|
getStats(): Observable<{ keys: number, cylinders: number, systems: number, handedOut: number }> {
|
||||||
return this.http.get<{ keys: number, cylinders: number, systems: number }>('api/user/stats');
|
return this.http.get<{ keys: number, cylinders: number, systems: number, handedOut: number }>('api/user/stats');
|
||||||
}
|
}
|
||||||
|
|
||||||
getActivities(): Observable<any[]> {
|
getActivities(): Observable<any[]> {
|
||||||
|
|||||||
@@ -112,3 +112,23 @@ div.ag-row {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user