changes
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
<h2 mat-dialog-title>Manager</h2>
|
||||
<mat-dialog-content>
|
||||
<ag-grid-angular
|
||||
style="width: 100%; height: 100%;"
|
||||
(gridReady)="onGridReady($event)"
|
||||
[gridOptions]="gridOptions!"
|
||||
/>
|
||||
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button [mat-dialog-close]="true">Schließen</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
min-height: 500px;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SystemManagerComponent } from './system-manager.component';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
import { AgGridAngular } from 'ag-grid-angular';
|
||||
import { ApiService } from '../../../../shared/api.service';
|
||||
import { HotToastService } from '@ngxpert/hot-toast';
|
||||
import { MockApiService } from '../../../../../../mocks/services/mock.api.service';
|
||||
import { GridReadyEvent } from 'ag-grid-community';
|
||||
|
||||
|
||||
|
||||
describe('SystemManagerComponent', () => {
|
||||
let component: SystemManagerComponent;
|
||||
let fixture: ComponentFixture<SystemManagerComponent>;
|
||||
let api: ApiService;
|
||||
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SystemManagerComponent, AgGridAngular, MatDialogModule],
|
||||
providers: [
|
||||
HotToastService,
|
||||
{ provide: ApiService, useClass: MockApiService },
|
||||
{
|
||||
provide: MatDialogRef,
|
||||
useValue: []
|
||||
},
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: []
|
||||
}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SystemManagerComponent);
|
||||
component = fixture.componentInstance;
|
||||
api = component['api']
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should initialize gridApi and gridColumnApi on gridReady and fill data', () => {
|
||||
// Mock des GridReadyEvent
|
||||
let mockData = [{ id: 1, name: 'Test' }];
|
||||
const mockGridReadyEvent: GridReadyEvent = {
|
||||
api: { setGridOption: jest.fn() },
|
||||
columnApi: { someColumnApiMethod: jest.fn() },
|
||||
type: 'gridReady',
|
||||
} as any;
|
||||
|
||||
// Methode aufrufen
|
||||
component.onGridReady(mockGridReadyEvent);
|
||||
|
||||
// Assertions
|
||||
expect(component.gridApi).toBe(mockGridReadyEvent.api);
|
||||
expect(api.getSystemManagers).toHaveBeenCalled();
|
||||
expect(component.gridApi.setGridOption).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community';
|
||||
import { HELPER } from '../../../../shared/helper.service';
|
||||
import { AgGridAngular } from 'ag-grid-angular';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||
import { HotToastService } from '@ngxpert/hot-toast';
|
||||
import { ApiService } from '../../../../shared/api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-system-manager',
|
||||
standalone: true,
|
||||
imports: [AgGridAngular, MatDialogModule],
|
||||
templateUrl: './system-manager.component.html',
|
||||
styleUrl: './system-manager.component.scss'
|
||||
})
|
||||
export class SystemManagerComponent {
|
||||
|
||||
gridApi!: GridApi;
|
||||
|
||||
gridOptions: GridOptions = HELPER.getGridOptions();
|
||||
readonly dialogRef = inject(MatDialogRef<SystemManagerComponent>);
|
||||
readonly system = inject<any>(MAT_DIALOG_DATA);
|
||||
|
||||
private api: ApiService = inject(ApiService);
|
||||
private dialog: MatDialog = inject(MatDialog);
|
||||
private toast = inject(HotToastService);
|
||||
|
||||
|
||||
constructor() {
|
||||
this.gridOptions.columnDefs = [
|
||||
{ colId: 'name', field: 'firstName', headerName: 'Name', sort: 'asc', flex: 1, cellRenderer: (data: any) => data.data.firstName + ' ' + data.data.lastName, sortable: true, filter: true},
|
||||
{ colId: 'mail', field: 'username', headerName: 'E-Mail', flex: 1},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
onGridReady(params: GridReadyEvent) {
|
||||
this.gridApi = params.api;
|
||||
this.loadManagers();
|
||||
}
|
||||
|
||||
loadManagers() {
|
||||
this.api.getSystemManagers(this.system.id).subscribe({
|
||||
next: n => {
|
||||
this.gridApi.setGridOption("rowData", n);
|
||||
this.gridApi.setGridOption("loading", false);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
19
client/src/app/modules/system/create/create.component.html
Normal file
19
client/src/app/modules/system/create/create.component.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<h2 mat-dialog-title>Neuen Schlüssel 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 Schlüssel heißen?</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">Speichern</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -0,0 +1,66 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { CreateSystemComponent } from './create.component';
|
||||
import { ApiService } from '../../../shared/api.service';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { HotToastService } from '@ngxpert/hot-toast';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MockApiService } from '../../../../../mocks/services/mock.api.service';
|
||||
|
||||
describe('CreateComponent', () => {
|
||||
let component: CreateSystemComponent;
|
||||
let fixture: ComponentFixture<CreateSystemComponent>;
|
||||
let apiService: ApiService;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CreateSystemComponent, NoopAnimationsModule, FormsModule, ReactiveFormsModule],
|
||||
providers: [
|
||||
HotToastService,
|
||||
{ provide: ApiService, useClass: MockApiService },
|
||||
{
|
||||
provide: MatDialogRef,
|
||||
useValue: []
|
||||
},
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: []
|
||||
}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CreateSystemComponent);
|
||||
component = fixture.componentInstance;
|
||||
apiService = component['api'];
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should call apiService.createSystem when createSystem is called', () => {
|
||||
expect(apiService.createSystem).not.toHaveBeenCalled();
|
||||
component.createForm.setValue({ name: 'Test System' });
|
||||
component.save();
|
||||
expect(apiService.createSystem).toHaveBeenCalledWith({ name: 'Test System' });
|
||||
});
|
||||
|
||||
it('should handle success response correctly', () => {
|
||||
jest.spyOn(apiService, 'createSystem').mockReturnValue(of({}));
|
||||
const toastSpy = jest.spyOn(component['toast'], 'observe');
|
||||
component.createForm.setValue({ name: 'Test System' });
|
||||
component.save();
|
||||
expect(toastSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle error response correctly', () => {
|
||||
jest.spyOn(apiService, 'createSystem').mockReturnValue(throwError(() => new Error('Test Error')));
|
||||
const toastSpy = jest.spyOn(component['toast'], 'observe');
|
||||
component.save();
|
||||
expect(toastSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
43
client/src/app/modules/system/create/create.component.ts
Normal file
43
client/src/app/modules/system/create/create.component.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
import { HotToastService } from '@ngxpert/hot-toast';
|
||||
import { ApiService } from '../../../shared/api.service';
|
||||
import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create',
|
||||
standalone: true,
|
||||
imports: [MatDialogModule, MatButtonModule, ReactiveFormsModule, FormsModule, MatFormFieldModule, MatInputModule, MatDialogModule],
|
||||
templateUrl: './create.component.html',
|
||||
styleUrl: './create.component.scss'
|
||||
})
|
||||
export class CreateSystemComponent {
|
||||
private api: ApiService = inject(ApiService);
|
||||
private toast: HotToastService = inject(HotToastService);
|
||||
readonly dialogRef = inject(MatDialogRef<CreateSystemComponent>);
|
||||
|
||||
|
||||
createForm = new FormGroup({
|
||||
name: new FormControl<string | null>(null, Validators.required),
|
||||
})
|
||||
|
||||
|
||||
save() {
|
||||
this.api.createSystem(this.createForm.value as any)
|
||||
.pipe(
|
||||
this.toast.observe({
|
||||
error: 'Konnte nicht angelegt werden...',
|
||||
loading: 'Speichern...',
|
||||
success: 'Gespeichert'
|
||||
}))
|
||||
.subscribe({
|
||||
next: (sys) => {
|
||||
this.dialogRef.close(sys);
|
||||
},
|
||||
error: e => {}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,8 @@
|
||||
style="width: 100%; height: 100%;"
|
||||
(gridReady)="onGridReady($event)"
|
||||
[gridOptions]="gridOptions!"
|
||||
/>
|
||||
/>
|
||||
|
||||
<div class="floating-btn-container">
|
||||
<button mat-flat-button class="btn-create mat-elevation-z8" (click)="openCreateSystem()" color="accent" >System anlegen</button>
|
||||
</div>
|
||||
@@ -4,11 +4,15 @@ import { AgGridAngular } from 'ag-grid-angular';
|
||||
import { GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community';
|
||||
import { ApiService } from '../../shared/api.service';
|
||||
import { HELPER } from '../../shared/helper.service';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||
import { CreateSystemComponent } from './create/create.component';
|
||||
import { AgSystemManagerComponent } from '../../shared/ag-grid/components/ag-system-manager/ag-system-manager.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-system',
|
||||
standalone: true,
|
||||
imports: [AgGridAngular],
|
||||
imports: [AgGridAngular, MatButtonModule, MatDialogModule],
|
||||
providers: [DatePipe],
|
||||
templateUrl: './system.component.html',
|
||||
styleUrl: './system.component.scss'
|
||||
@@ -16,6 +20,7 @@ import { HELPER } from '../../shared/helper.service';
|
||||
export class SystemComponent {
|
||||
private api: ApiService = inject(ApiService);
|
||||
private datePipe = inject(DatePipe);
|
||||
private dialog: MatDialog = inject(MatDialog);
|
||||
|
||||
gridApi!: GridApi;
|
||||
|
||||
@@ -26,6 +31,13 @@ export class SystemComponent {
|
||||
{ colId: 'name', field: 'name', headerName: 'Name', sort: 'asc', flex: 1},
|
||||
{ field: 'createdAt', headerName: 'Angelegt', cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value)) : '-' },
|
||||
{ field: 'updatedAt', headerName: 'Upgedated', cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value)) : '-' },
|
||||
{
|
||||
colId: 'actions'
|
||||
, headerName: 'Aktionen'
|
||||
, width: 120
|
||||
, cellRenderer: AgSystemManagerComponent
|
||||
// , onCellClicked: (event) => { this.deleteKey(event.data.id)}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -44,4 +56,16 @@ export class SystemComponent {
|
||||
this.loadSystems();
|
||||
}
|
||||
|
||||
openCreateSystem() {
|
||||
this.dialog.open(CreateSystemComponent).afterClosed().subscribe({
|
||||
next: sys => {
|
||||
if (sys) {
|
||||
let d = [...this.gridApi.getGridOption("rowData") || [], sys];
|
||||
this.gridApi.setGridOption("rowData", d);
|
||||
this.loadSystems();
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user