schlüssel neuen zylindern zuordnen geht
This commit is contained in:
1
api/package-lock.json
generated
1
api/package-lock.json
generated
@@ -5691,7 +5691,6 @@
|
|||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|||||||
@@ -122,5 +122,8 @@
|
|||||||
"@schematics/angular:resolver": {
|
"@schematics/angular:resolver": {
|
||||||
"typeSeparator": "."
|
"typeSeparator": "."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1293
client/package-lock.json
generated
1293
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -78,16 +78,11 @@ export class LostKeysComponent extends AgGridContainerComponent {
|
|||||||
|
|
||||||
markAsFound(key: IKey) {
|
markAsFound(key: IKey) {
|
||||||
this.dialog.open(LostKeyComponent, { data: key, autoFocus: false }).afterClosed().subscribe({
|
this.dialog.open(LostKeyComponent, { data: key, autoFocus: false }).afterClosed().subscribe({
|
||||||
next: (result) => {
|
next: async (result) => {
|
||||||
if (result == "") {
|
if (result == "") {
|
||||||
key.keyLost = null;
|
key.keyLost = null;
|
||||||
this.api.updateKey(key).subscribe({
|
await this.api.updateKey(key);
|
||||||
next: () => {
|
|
||||||
this.toast.success('Schlüssel als gefunden markiert');
|
|
||||||
this.loadLostKeys();
|
this.loadLostKeys();
|
||||||
this.api.refreshKeys();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.dataChanged = true;
|
this.dataChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<h2 mat-dialog-title>Mehrere Schließanlagen gewählt!</h2>
|
||||||
|
<mat-dialog-content>
|
||||||
|
<div class="warning-message">
|
||||||
|
<mat-icon>warning</mat-icon>
|
||||||
|
<p>
|
||||||
|
Der Schlüssel ist Zylindern in mehreren Schließanlagen zugeordnet!
|
||||||
|
</p>
|
||||||
|
<p class="additional-info">
|
||||||
|
<!-- Additional information -->
|
||||||
|
<small>Zum Korrigieren abbrechen, ansonsten speichern</small>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions align="end">
|
||||||
|
<button matButton [mat-dialog-close]="false">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
Vorgang abbrechen
|
||||||
|
</button>
|
||||||
|
<button matButton="elevated" [mat-dialog-close]="true" class="btn-warning">
|
||||||
|
<mat-icon>check</mat-icon>
|
||||||
|
Schlüssel speichern
|
||||||
|
</button>
|
||||||
|
</mat-dialog-actions>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MultipleCylinderSystemsDialogComponent } from './multiple-cylinder-systems-dialog.component';
|
||||||
|
|
||||||
|
describe('MultipleCylinderSystemsDialogComponent', () => {
|
||||||
|
let component: MultipleCylinderSystemsDialogComponent;
|
||||||
|
let fixture: ComponentFixture<MultipleCylinderSystemsDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [MultipleCylinderSystemsDialogComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(MultipleCylinderSystemsDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-multiple-cylinder-systems-dialog',
|
||||||
|
imports: [MatDialogModule, MatButtonModule, MatIconModule],
|
||||||
|
templateUrl: './multiple-cylinder-systems-dialog.component.html',
|
||||||
|
styleUrl: './multiple-cylinder-systems-dialog.component.scss',
|
||||||
|
})
|
||||||
|
export class MultipleCylinderSystemsDialogComponent {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,6 +11,6 @@
|
|||||||
|
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button matButton [mat-dialog-close]="null">Abbrechen</button>
|
<button matButton (click)="close(false)">Abbrechen</button>
|
||||||
<button matButton [mat-dialog-close]="selectedCylinders">Übernehmen</button>
|
<button matButton="elevated" (click)="close(true)" class="btn-primary" [disabled]="selectedCylinders.length < 1" >Übernehmen</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -3,11 +3,12 @@ import { ApiService } from '../../../../shared/api.service';
|
|||||||
import { ICylinder } from '../../../../model/interface/cylinder.interface';
|
import { ICylinder } from '../../../../model/interface/cylinder.interface';
|
||||||
import { HotToastService } from '@ngxpert/hot-toast';
|
import { HotToastService } from '@ngxpert/hot-toast';
|
||||||
import { AgGridAngular } from 'ag-grid-angular';
|
import { AgGridAngular } from 'ag-grid-angular';
|
||||||
import { GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community';
|
import { GridApi, GridOptions, GridReadyEvent, IRowNode } from 'ag-grid-community';
|
||||||
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
||||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { AgGridContainerComponent } from '../../../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
|
import { AgGridContainerComponent } from '../../../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
|
||||||
|
import { MultipleCylinderSystemsDialogComponent } from './multiple-cylinder-systems-dialog/multiple-cylinder-systems-dialog.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-select-key-cylinder',
|
selector: 'app-select-key-cylinder',
|
||||||
@@ -20,6 +21,8 @@ export class SelectKeyCylinderComponent extends AgGridContainerComponent {
|
|||||||
readonly dialogRef = inject(MatDialogRef<SelectKeyCylinderComponent>);
|
readonly dialogRef = inject(MatDialogRef<SelectKeyCylinderComponent>);
|
||||||
readonly cylinders = inject<ICylinder[]>(MAT_DIALOG_DATA);
|
readonly cylinders = inject<ICylinder[]>(MAT_DIALOG_DATA);
|
||||||
|
|
||||||
|
private dialog = inject(MatDialog);
|
||||||
|
|
||||||
gridApi!: GridApi;
|
gridApi!: GridApi;
|
||||||
|
|
||||||
gridOptions: GridOptions = {
|
gridOptions: GridOptions = {
|
||||||
@@ -49,5 +52,45 @@ export class SelectKeyCylinderComponent extends AgGridContainerComponent {
|
|||||||
|
|
||||||
selectionChanged(): void {
|
selectionChanged(): void {
|
||||||
this.selectedCylinders = this.gridApi?.getSelectedRows();
|
this.selectedCylinders = this.gridApi?.getSelectedRows();
|
||||||
|
if (this.selectedCylinders.length == 0 ) {
|
||||||
|
this.toast.info('Jeder Schlüssel muss mindestens einem Zylinder zugeordnet sein. Bitte Zylinder wählen.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preselectCylinders(cylinders: ICylinder[]) {
|
||||||
|
this.gridApi.setGridOption('loading', true)
|
||||||
|
|
||||||
|
const nodesToSelect: IRowNode<ICylinder>[] = [];
|
||||||
|
this.gridApi.forEachNode(node => {
|
||||||
|
if (cylinders.some(c => c.id == node.data.id )) {
|
||||||
|
nodesToSelect.push(node);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.gridApi.setNodesSelected({
|
||||||
|
nodes: nodesToSelect,
|
||||||
|
newValue: true
|
||||||
|
})
|
||||||
|
this.gridApi.setGridOption('loading', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(data = false) {
|
||||||
|
if (!data) { return this.dialogRef.close() }
|
||||||
|
|
||||||
|
|
||||||
|
const amountOfSystems = Array.from(new Set(this.selectedCylinders.map( c => c.system.id )));
|
||||||
|
if (amountOfSystems.length == 1) {
|
||||||
|
return this.dialogRef.close(this.selectedCylinders);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dialog.open(MultipleCylinderSystemsDialogComponent, {}).afterClosed().subscribe({
|
||||||
|
next: val => {
|
||||||
|
if (val) {
|
||||||
|
return this.dialogRef.close(this.selectedCylinders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
||||||
import { AgGridAngular } from 'ag-grid-angular';
|
import { AgGridAngular } from 'ag-grid-angular';
|
||||||
import { GridOptions,GridApi, GridReadyEvent, CellEditingStoppedEvent, ICellEditorParams, FilterActionParams, FilterAction, themeQuartz, Theme, ThemeDefaultParams } from 'ag-grid-community';
|
import { GridOptions,GridApi, GridReadyEvent, CellEditingStoppedEvent, ICellEditorParams, FilterActionParams, FilterAction, themeQuartz, Theme, ThemeDefaultParams, AgGridEvent, CellClickedEvent, CellDoubleClickedEvent } from 'ag-grid-community';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { ApiService } from '../../shared/api.service';
|
import { ApiService } from '../../shared/api.service';
|
||||||
import { IKey } from '../../model/interface/key.interface';
|
import { IKey } from '../../model/interface/key.interface';
|
||||||
@@ -54,7 +54,9 @@ export class KeysComponent extends AgGridContainerComponent {
|
|||||||
valueFormatter: (data: any) => { return data; },
|
valueFormatter: (data: any) => { return data; },
|
||||||
cellRenderer: (data: any) => {return data.value?.map((m: ICylinder) => m.name).join(', ')},
|
cellRenderer: (data: any) => {return data.value?.map((m: ICylinder) => m.name).join(', ')},
|
||||||
tooltipValueGetter: (data: any) => data.value?.map((m: ICylinder) => m.name).join(','),
|
tooltipValueGetter: (data: any) => data.value?.map((m: ICylinder) => m.name).join(','),
|
||||||
onCellDoubleClicked(event) {},
|
onCellDoubleClicked: (event) => {
|
||||||
|
this.openSelectCylinder(event)
|
||||||
|
},
|
||||||
cellEditorPopup: true,
|
cellEditorPopup: true,
|
||||||
filterValueGetter: (params: any) => {return params.data.cylinder?.map((m: ICylinder) => m.name).join(', ')},
|
filterValueGetter: (params: any) => {return params.data.cylinder?.map((m: ICylinder) => m.name).join(', ')},
|
||||||
},
|
},
|
||||||
@@ -157,24 +159,13 @@ export class KeysComponent extends AgGridContainerComponent {
|
|||||||
this.setFilterToParams();
|
this.setFilterToParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
cellEditEnd(event: CellEditingStoppedEvent) {
|
async cellEditEnd(event: CellEditingStoppedEvent) {
|
||||||
const key: IKey = event.data;
|
const key: IKey = event.data;
|
||||||
if (!event.valueChanged || event.newValue == event.oldValue) { return; }
|
if (!event.valueChanged || event.newValue == event.oldValue) { return; }
|
||||||
|
|
||||||
this.gridApi.setGridOption("loading", true);
|
this.gridApi.setGridOption("loading", true);
|
||||||
this.api.updateKey(key)
|
await this.api.updateKey(key)
|
||||||
.pipe(
|
this.gridApi.setGridOption("loading", false);
|
||||||
this.toast.observe({
|
|
||||||
loading: 'speichern...',
|
|
||||||
success: 'Änderungen gespeichert',
|
|
||||||
error: 'Änderungen konnten nicht gespeichert werden!'
|
|
||||||
})
|
|
||||||
).subscribe({
|
|
||||||
next: () => {this.gridApi.setGridOption("loading", false);},
|
|
||||||
error: () => {
|
|
||||||
this.loadKeys();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openCreateKey() {
|
openCreateKey() {
|
||||||
@@ -195,17 +186,33 @@ export class KeysComponent extends AgGridContainerComponent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
openSelectCylinder(params: any) {
|
async openSelectCylinder(event: CellDoubleClickedEvent) {
|
||||||
this.dialog.open(SelectKeyCylinderComponent, {
|
const key: IKey = event.data;
|
||||||
|
this.gridApi.setGridOption("loading", true);
|
||||||
|
const cylinders = await this.api.refreshCylinders()
|
||||||
|
this.gridApi.setGridOption('loading', false)
|
||||||
|
const ref = this.dialog.open(SelectKeyCylinderComponent, {
|
||||||
|
data: cylinders,
|
||||||
|
maxHeight: "calc(100vh - 24px)",
|
||||||
maxWidth: "calc(100vw - 24px)",
|
maxWidth: "calc(100vw - 24px)",
|
||||||
width: "30vw",
|
width: "50vw",
|
||||||
minWidth: "200px",
|
minWidth: "300px",
|
||||||
disableClose: true
|
height: "70vh",
|
||||||
}).afterClosed().subscribe({
|
disableClose: true,
|
||||||
next: key => {
|
});
|
||||||
console.log(key)
|
|
||||||
|
ref.afterOpened().subscribe({
|
||||||
|
next: () => {
|
||||||
|
ref.componentInstance.preselectCylinders(event.data.cylinder);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
ref.afterClosed().subscribe({
|
||||||
|
next: (cylinders: ICylinder[]) => {
|
||||||
|
if (cylinders == null) { return; }
|
||||||
|
key.cylinder = cylinders;
|
||||||
|
this.api.updateKey(key)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
openArchive() {
|
openArchive() {
|
||||||
|
|||||||
@@ -105,8 +105,7 @@ export class AgKeyActionsComponent implements ICellRendererAngularComp {
|
|||||||
}
|
}
|
||||||
this.key.keyLost = n;
|
this.key.keyLost = n;
|
||||||
this.params.api.refreshCells();
|
this.params.api.refreshCells();
|
||||||
await this.api.updateKey(this.key).subscribe();
|
await this.api.updateKey(this.key)
|
||||||
this.api.refreshKeys();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -76,8 +76,20 @@ export class ApiService {
|
|||||||
return this.http.get<IKey[]>('api/key/lost')
|
return this.http.get<IKey[]>('api/key/lost')
|
||||||
}
|
}
|
||||||
|
|
||||||
updateKey(key: IKey): Observable<IKey> {
|
updateKey(key: IKey): Promise<IKey | null> {
|
||||||
return this.http.put<IKey>('api/key', key);
|
return new Promise<IKey | null>(resolve => {
|
||||||
|
this.http.put<IKey>('api/key', key).pipe(
|
||||||
|
this.toast.observe({
|
||||||
|
loading: `Speichere Schlüssel ${key.name}....`,
|
||||||
|
success: `Schlüssel ${key.name} gespeichert.`,
|
||||||
|
error: `Es ist ein Fehler aufgetreten!`
|
||||||
|
})
|
||||||
|
).subscribe({
|
||||||
|
next: (key: IKey) => resolve(key),
|
||||||
|
error: () => resolve(null),
|
||||||
|
complete: () => { this.refreshKeys(); }
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCylinder(cylinder: ICylinder): Promise<boolean> {
|
updateCylinder(cylinder: ICylinder): Promise<boolean> {
|
||||||
@@ -275,8 +287,8 @@ export class ApiService {
|
|||||||
* cylinders
|
* cylinders
|
||||||
* @returns Promise wenn geladen
|
* @returns Promise wenn geladen
|
||||||
*/
|
*/
|
||||||
refreshCylinders(): Promise<void> {
|
refreshCylinders(): Promise<ICylinder[]> {
|
||||||
return new Promise<void>(resolve => {
|
return new Promise<ICylinder[]>(resolve => {
|
||||||
this.getCylinders().subscribe({
|
this.getCylinders().subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
this.cylinders.next(data);
|
this.cylinders.next(data);
|
||||||
@@ -284,7 +296,7 @@ export class ApiService {
|
|||||||
error: () => {
|
error: () => {
|
||||||
this.toast.error('Fehler beim Laden der Zylinder')
|
this.toast.error('Fehler beim Laden der Zylinder')
|
||||||
},
|
},
|
||||||
complete: () => resolve()
|
complete: () => resolve(this.cylinders.value)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user