create cylinder
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Cylinder, User } from 'src/model/entitites';
|
import { Cylinder, User } from 'src/model/entitites';
|
||||||
import { CylinderRepository, KeyRepository } from 'src/model/repositories';
|
import { ActivityRepository, CylinderRepository, KeyRepository } from 'src/model/repositories';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CylinderService {
|
export class CylinderService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly cylinderRepo: CylinderRepository,
|
private readonly cylinderRepo: CylinderRepository,
|
||||||
private readonly keyRepo: KeyRepository,
|
private readonly keyRepo: KeyRepository,
|
||||||
|
private systemActivityRepo: ActivityRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getCylinders(user: User): Promise<Cylinder[]> {
|
async getCylinders(user: User): Promise<Cylinder[]> {
|
||||||
@@ -40,7 +41,14 @@ export class CylinderService {
|
|||||||
return this.cylinderRepo.save(original);
|
return this.cylinderRepo.save(original);
|
||||||
}
|
}
|
||||||
|
|
||||||
createCylinder(user: User, cylinder: Partial<Cylinder>) {
|
async createCylinder(user: User, cylinder: Partial<Cylinder>) {
|
||||||
return this.cylinderRepo.save(this.cylinderRepo.create(cylinder));
|
const c = await this.cylinderRepo.save(this.cylinderRepo.create(cylinder));
|
||||||
|
|
||||||
|
this.systemActivityRepo.save({
|
||||||
|
message: `Zylinder ${(c as any).name} angelegt`,
|
||||||
|
user: user,
|
||||||
|
system: (c as any).system
|
||||||
|
});
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,31 @@
|
|||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { CreateSystemDto } from './dto/create-system.dto';
|
import { CreateSystemDto } from './dto/create-system.dto';
|
||||||
import { UpdateSystemDto } from './dto/update-system.dto';
|
import { UpdateSystemDto } from './dto/update-system.dto';
|
||||||
import { KeySystemRepository, UserRepository } from 'src/model/repositories';
|
import { ActivityRepository, KeySystemRepository, UserRepository } from 'src/model/repositories';
|
||||||
import { User } from 'src/model/entitites';
|
import { User } from 'src/model/entitites';
|
||||||
import { IUser } from 'src/model/interface';
|
import { IUser } from 'src/model/interface';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SystemService {
|
export class SystemService {
|
||||||
constructor(private systemRepo: KeySystemRepository, private userRepo: UserRepository) {}
|
constructor(
|
||||||
|
private systemRepo: KeySystemRepository,
|
||||||
|
private userRepo: UserRepository,
|
||||||
|
private systemActivityRepo: ActivityRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
async create(user: User, createSystemDto: CreateSystemDto) {
|
async create(user: User, createSystemDto: CreateSystemDto) {
|
||||||
const sys = this.systemRepo.create(createSystemDto);
|
const sys = this.systemRepo.create(createSystemDto);
|
||||||
sys.managers = [user];
|
sys.managers = [user];
|
||||||
try {
|
try {
|
||||||
const res = await this.systemRepo.save(sys);
|
const res = await this.systemRepo.save(sys);
|
||||||
|
|
||||||
|
this.systemActivityRepo.save({
|
||||||
|
message: `Schließanlage ${(res as any).name} angelegt`,
|
||||||
|
user: user,
|
||||||
|
system: res
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new HttpException(e.code, HttpStatus.UNPROCESSABLE_ENTITY);
|
throw new HttpException(e.code, HttpStatus.UNPROCESSABLE_ENTITY);
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<h2 mat-dialog-title>Neuen Zylinder anlegen</h2>
|
||||||
|
<mat-dialog-content>
|
||||||
|
<form [formGroup]="createForm" class="flex flex-col gap-3">
|
||||||
|
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Name</mat-label>
|
||||||
|
<input type="text" matInput formControlName="name" maxlength="100">
|
||||||
|
@if ((createForm.controls.name.value || '').length > 20) {
|
||||||
|
<mat-hint>{{ (createForm.controls.name.value || '').length }} / 100 Zeichen</mat-hint>
|
||||||
|
} @else {
|
||||||
|
<mat-hint>Wie soll der Zylinder heißen?</mat-hint>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Schließanlage</mat-label>
|
||||||
|
<mat-select formControlName="system">
|
||||||
|
@for (item of systems; track $index) {
|
||||||
|
<mat-option [value]="item">{{ item.name }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
<mat-hint>Zu welcher Schließanlage gehört der Zylinder?</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<button mat-button mat-dialog-close>Abbrechen</button>
|
||||||
|
<button mat-button (click)="save()" [disabled]="createForm.disabled || createForm.invalid">Speichern</button>
|
||||||
|
</mat-dialog-actions>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CreateCylinderComponent } from './create-cylinder.component';
|
||||||
|
import { MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { HotToastService } from '@ngxpert/hot-toast';
|
||||||
|
import { ApiService } from '../../../../shared/api.service';
|
||||||
|
import { MockApiService } from '../../../../../../mocks/services/mock.api.service';
|
||||||
|
import { MockHotToastService } from '../../../../../../mocks/services/mock.hottoast.service';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
describe('CreateCylinderComponent', () => {
|
||||||
|
let component: CreateCylinderComponent;
|
||||||
|
let fixture: ComponentFixture<CreateCylinderComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [CreateCylinderComponent, NoopAnimationsModule],
|
||||||
|
providers: [
|
||||||
|
{ provide: ApiService, useClass: MockApiService },
|
||||||
|
{ provide: MatDialogRef, useValue: [] },
|
||||||
|
{ provide: HotToastService, useClass: MockHotToastService }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(CreateCylinderComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { FormGroup, FormControl, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||||
|
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { HotToastService } from '@ngxpert/hot-toast';
|
||||||
|
import { ApiService } from '../../../../shared/api.service';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-create-cylinder',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, MatFormFieldModule, MatInputModule, MatDialogModule, ReactiveFormsModule, FormsModule, MatSelectModule, MatButtonModule],
|
||||||
|
templateUrl: './create-cylinder.component.html',
|
||||||
|
styleUrl: './create-cylinder.component.scss'
|
||||||
|
})
|
||||||
|
export class CreateCylinderComponent {
|
||||||
|
private api: ApiService = inject(ApiService);
|
||||||
|
private toast: HotToastService = inject(HotToastService);
|
||||||
|
readonly dialogRef = inject(MatDialogRef<CreateCylinderComponent>);
|
||||||
|
|
||||||
|
systems: any[] = [];
|
||||||
|
|
||||||
|
createForm = new FormGroup({
|
||||||
|
name: new FormControl<string | null>(null, Validators.required),
|
||||||
|
system: new FormControl<any>(null, Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.api.getSystems().subscribe({
|
||||||
|
next: systems => {
|
||||||
|
this.systems = systems;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.api.createCylinder(this.createForm.value as any)
|
||||||
|
.pipe(
|
||||||
|
this.toast.observe({
|
||||||
|
loading: 'Speichern...',
|
||||||
|
success: 'Gespeichert!',
|
||||||
|
error: 'Konnte nicht gespeichert werden'
|
||||||
|
})
|
||||||
|
).subscribe({
|
||||||
|
next: cylinder => {
|
||||||
|
this.dialogRef.close(cylinder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,8 @@
|
|||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
[gridOptions]="gridOptions!"
|
[gridOptions]="gridOptions!"
|
||||||
/>
|
/>
|
||||||
|
<div class="floating-btn-container">
|
||||||
|
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateCylinder()" color="accent" >Zylinder anlegen</button>
|
||||||
|
<button mat-mini-fab disabled><mat-icon>inventory_2</mat-icon></button>
|
||||||
|
</div>
|
||||||
@@ -5,11 +5,15 @@ import { AgGridAngular } from 'ag-grid-angular';
|
|||||||
import { ApiService } from '../../shared/api.service';
|
import { ApiService } from '../../shared/api.service';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { AgDeleteCylinderComponent } from '../../shared/ag-grid/components/ag-delete-cylinder/ag-delete-cylinder.component';
|
import { AgDeleteCylinderComponent } from '../../shared/ag-grid/components/ag-delete-cylinder/ag-delete-cylinder.component';
|
||||||
|
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { CreateCylinderComponent } from './components/create-cylinder/create-cylinder.component';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-cylinder',
|
selector: 'app-cylinder',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [AgGridAngular],
|
imports: [AgGridAngular, MatDialogModule, MatIconModule, MatButtonModule],
|
||||||
providers: [DatePipe],
|
providers: [DatePipe],
|
||||||
templateUrl: './cylinder.component.html',
|
templateUrl: './cylinder.component.html',
|
||||||
styleUrl: './cylinder.component.scss'
|
styleUrl: './cylinder.component.scss'
|
||||||
@@ -17,6 +21,7 @@ import { AgDeleteCylinderComponent } from '../../shared/ag-grid/components/ag-de
|
|||||||
export class CylinderComponent {
|
export class CylinderComponent {
|
||||||
private api: ApiService = inject(ApiService);
|
private api: ApiService = inject(ApiService);
|
||||||
private datePipe = inject(DatePipe);
|
private datePipe = inject(DatePipe);
|
||||||
|
private dialog = inject(MatDialog);
|
||||||
|
|
||||||
gridApi!: GridApi;
|
gridApi!: GridApi;
|
||||||
|
|
||||||
@@ -38,7 +43,6 @@ export class CylinderComponent {
|
|||||||
, cellRenderer: AgDeleteCylinderComponent
|
, cellRenderer: AgDeleteCylinderComponent
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadCylinders() {
|
loadCylinders() {
|
||||||
@@ -54,4 +58,19 @@ export class CylinderComponent {
|
|||||||
this.gridApi = params.api;
|
this.gridApi = params.api;
|
||||||
this.loadCylinders();
|
this.loadCylinders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openCreateCylinder() {
|
||||||
|
this.dialog.open(CreateCylinderComponent, {
|
||||||
|
maxWidth: "calc(100vw - 24px)",
|
||||||
|
width: "30vw",
|
||||||
|
minWidth: "200px",
|
||||||
|
disableClose: true
|
||||||
|
}).afterClosed().subscribe({
|
||||||
|
next: (cylinder) => {
|
||||||
|
if (cylinder) {
|
||||||
|
this.loadCylinders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
<mat-card>
|
<mat-card>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<ag-grid-angular
|
<ag-grid-angular
|
||||||
style="width: 100%; height: 300px;"
|
style="width: 100%; height: 100%;"
|
||||||
[gridOptions]="gridOptions"
|
[gridOptions]="gridOptions"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import {MatCardModule} from '@angular/material/card';
|
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';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
@@ -31,6 +32,7 @@ export class DashboardComponent {
|
|||||||
pagination: true,
|
pagination: true,
|
||||||
paginationPageSize: 10,
|
paginationPageSize: 10,
|
||||||
loading: true,
|
loading: true,
|
||||||
|
localeText: AG_GRID_LOCALE_DE,
|
||||||
loadingOverlayComponent: AgLoadingComponent
|
loadingOverlayComponent: AgLoadingComponent
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -111,4 +111,8 @@ export class ApiService {
|
|||||||
getActivities(): Observable<any[]> {
|
getActivities(): Observable<any[]> {
|
||||||
return this.http.get<any[]>('api/user/activities');
|
return this.http.get<any[]>('api/user/activities');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createCylinder(data: any) {
|
||||||
|
return this.http.post<ICylinder>('api/cylinder', data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user