Files
keyvault/client/src/app/modules/keys/keys.component.ts
Bastian Wagner f15df81fed hidden columns
2026-02-25 14:17:36 +01:00

243 lines
8.7 KiB
TypeScript

import { Component, inject } from '@angular/core';
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
import { AgGridAngular } from 'ag-grid-angular';
import { GridOptions,GridApi, GridReadyEvent, CellEditingStoppedEvent, ICellEditorParams, FilterActionParams, FilterAction, themeQuartz, Theme, ThemeDefaultParams, AgGridEvent, CellClickedEvent, CellDoubleClickedEvent, ColDef } from 'ag-grid-community';
import { DatePipe } from '@angular/common';
import { ApiService } from '../../shared/api.service';
import { IKey } from '../../model/interface/key.interface';
import { HotToastService } from '@ngxpert/hot-toast';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { CreateKeyComponent } from './create/create.component';
import { AgKeyActionsComponent } from '../../shared/ag-grid/components/ag-key-actions/ag-key-actions.component';
import { MatIconModule } from '@angular/material/icon';
import { ArchiveComponent } from './components/archive/archive.component';
import { AgLoadingComponent } from '../../shared/ag-grid/components/ag-loading/ag-loading.component';
import { map, of } from 'rxjs';
import { ICylinder } from '../../model/interface/cylinder.interface';
import { LostKeysComponent } from './components/lost-keys/lost-keys.component';
import { MatTooltipModule } from '@angular/material/tooltip';
import { SelectKeyCylinderComponent } from './create/select-key-cylinder/select-key-cylinder.component';
import { ActivatedRoute, Route } from '@angular/router';
import { ModuleRegistry } from 'ag-grid-community';
import { AgGridService } from '../../shared/ag-grid/ag-grid.service';
import { AgGridContainerComponent } from '../../shared/ag-grid/components/ag-grid-container/ag-grid-container.component';
@Component({
selector: 'app-keys',
imports: [AgGridAngular, MatButtonModule, MatDialogModule, MatIconModule, MatTooltipModule],
providers: [DatePipe, ModuleRegistry],
templateUrl: './keys.component.html',
styleUrl: './keys.component.scss'
})
export class KeysComponent extends AgGridContainerComponent {
private api: ApiService = inject(ApiService);
private datePipe = inject(DatePipe);
private toast: HotToastService = inject(HotToastService);
private dialog: MatDialog = inject(MatDialog);
private route: ActivatedRoute = inject(ActivatedRoute);
// cylinders: any[] = [];
gridApi!: GridApi;
gridOptions: GridOptions = {
localeText: AG_GRID_LOCALE_DE,
rowData: [],
columnDefs: [
{ colId: 'id', field: 'id', headerName: 'ID', hide: true },
{ colId: 'name', field: 'name' , headerName: 'Name', flex: 1, editable: true, sort: 'asc', filter: true },
{ colId: 'nr', field: 'nr' , headerName: 'Schlüsselnummer', flex: 1, editable: true, filter: true },
{
colId: 'cylinder', field: 'cylinder' , headerName: 'Zylinder', flex: 1, editable: false, filter: true,
valueFormatter: (data: any) => { return data; },
cellRenderer: (data: any) => {return data.value?.map((m: ICylinder) => m.name).join(', ')},
tooltipValueGetter: (data: any) => data.value?.map((m: ICylinder) => m.name).join(','),
onCellDoubleClicked: (event) => { this.openSelectCylinder(event) },
cellEditorPopup: true,
filterValueGetter: (params: any) => {return params.data.cylinder?.map((m: ICylinder) => m.name).join(', ')},
},
{
colId: 'system', field: 'cylinder' , headerName: 'Schließanlage', flex: 1, editable: false, filter: true, cellRenderer: (data: any) => {
const s = new Set<string>(data.value?.map((m: ICylinder) => m.system?.name));
return [...s].join(', ')
},
filterValueGetter: (params: any) => {
const s = new Set<string>(params.data.cylinder?.map((m: ICylinder) => m.system?.name));
return [...s].join(', ')
},
valueFormatter: (data: any) => { return data; },
},
{
colId: 'customer', field: 'customer' , headerName: 'Mieter', flex: 1, editable: false, filter: true,
cellRenderer: (data: any) => {return data.value?.name},
filterValueGetter: (params: any) => {return params.data.customer?.name},
valueFormatter: (data: any) => { return data; },
},
{
field: 'createdAt', headerName: 'Erstellt', width: 120
, cellRenderer: (data: any) => this.datePipe.transform(new Date(data.value))
, tooltipValueGetter: (data: any) => this.datePipe.transform(new Date(data.value), 'medium'),
valueFormatter: (data: any) => { return data; },
},{
colId: 'updatedAt', field: 'updatedAt', headerName: 'Geändert', width: 120, hide: true
, cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value)) : '-'
, tooltipValueGetter: (data: any) => this.datePipe.transform(new Date(data.value), 'medium')
},
{ colId: 'handedOut', field: 'handedOut' , headerName: 'Ausgegeben', width: 100, editable: false, filter: true, headerTooltip: 'Ausgegeben' },
{ colId: 'digital', field: 'digital', headerName: 'Digital', hide: true },
{
colId: 'actions', headerName: 'Aktionen', width: 140, sortable: false
, cellRenderer: AgKeyActionsComponent
,valueFormatter: (data: any) => { return data; },
}
],
loading: true,
loadingOverlayComponent: AgLoadingComponent,
pagination: true,
}
editKey(id: string) {
}
ngOnInit(): void {
}
private setFilterToParams() {
const params = this.route.snapshot.queryParams;
if (Object.keys(params).includes('handedOut')) {
this.gridApi.setFilterModel({
handedOut: {
filterType: 'text',
type: params['handedOut']
}
})
} if (Object.keys(params).includes('nr')) {
this.gridApi.setFilterModel({
nr: {
filterType: 'text',
type: 'equals',
filter: params['nr']
}
})
}
}
loadKeys() {
this.gridApi.setGridOption("loading", true);
this.api.refreshKeys();
}
onGridReady(params: GridReadyEvent) {
this.gridApi = params.api;
this.gridApi.addEventListener("cellEditingStopped", evt => this.cellEditEnd(evt));
this.api.keys.asObservable().subscribe({
next: keys => {
this.gridApi.setGridOption("rowData", keys);
this.gridApi.setGridOption("loading", false);
}
})
this.loadKeys();
this.setFilterToParams();
}
async cellEditEnd(event: CellEditingStoppedEvent) {
const key: IKey = event.data;
if (!event.valueChanged || event.newValue == event.oldValue) { return; }
this.gridApi.setGridOption("loading", true);
await this.api.updateKey(key)
this.gridApi.setGridOption("loading", false);
}
openCreateKey() {
this.dialog.open(CreateKeyComponent, {
maxWidth: "calc(100vw - 48px)",
width: "800px",
minWidth: "200px",
disableClose: true
}).afterClosed().subscribe({
next: key => {
if (key) {
let d = [...this.gridApi.getGridOption("rowData") || [], key];
this.gridApi.setGridOption("rowData", d);
this.loadKeys();
}
}
})
}
async openSelectCylinder(event: CellDoubleClickedEvent) {
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 - 48px)",
maxWidth: "calc(100vw - 48px)",
width: "50vw",
minWidth: "300px",
height: "70vh",
disableClose: true,
});
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() {
this.dialog.open(ArchiveComponent, {
maxHeight: "calc(100vh - 24px)",
maxWidth: "calc(100vw - 24px)",
width: "50vw",
minWidth: "300px",
height: "70vh",
disableClose: true
}).afterClosed().subscribe({
next: changed => {
if (changed) {
this.loadKeys();
}
}
})
}
openLostKeys() {
this.dialog.open(LostKeysComponent, {
maxHeight: "calc(100vh - 24px)",
maxWidth: "calc(100vw - 24px)",
width: "50vw",
minWidth: "min(700px,calc(100vw - 24px))",
height: "70vh",
disableClose: true
}).afterClosed().subscribe({
next: changed => {
if (changed) {
this.loadKeys();
}
}
})
}
}