Add delete functionallity

urls
Max Ehrlicher-Schmidt 4 years ago
parent daeb4b1a0a
commit bfa8a4f0ef

@ -26,13 +26,15 @@ import {MatTooltipModule} from '@angular/material/tooltip';
import {MatSelectModule} from '@angular/material/select'; import {MatSelectModule} from '@angular/material/select';
import { MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort'; import { MatSortModule } from '@angular/material/sort';
import {MatDialogModule} from '@angular/material/dialog';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { LoginComponent } from './pages/login/login.component'; import { LoginComponent } from './pages/login/login.component';
import { BikesComponent } from './pages/tables/bikes/bikes.component'; import { BikesComponent, DeleteConfirmationDialog } from './pages/tables/bikes/bikes.component';
import { GraphQLModule } from './graphql.module'; import { GraphQLModule } from './graphql.module';
import { ParticipantsComponent } from './pages/tables/participants/participants.component'; import { ParticipantsComponent } from './pages/tables/participants/participants.component';
import { LendingStationsComponent } from './pages/tables/lending-stations/lending-stations.component'; import { LendingStationsComponent } from './pages/tables/lending-stations/lending-stations.component';
@ -52,6 +54,7 @@ import { TokenInterceptor } from './helper/token.interceptor'
LendingStationsComponent, LendingStationsComponent,
TableOverviewComponent, TableOverviewComponent,
CellComponent, CellComponent,
DeleteConfirmationDialog
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -81,7 +84,8 @@ import { TokenInterceptor } from './helper/token.interceptor'
MatTooltipModule, MatTooltipModule,
MatSelectModule, MatSelectModule,
MatPaginatorModule, MatPaginatorModule,
MatSortModule MatSortModule,
MatDialogModule
], ],
providers: [NavService, providers: [NavService,
{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true }], { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true }],

@ -27,3 +27,7 @@ mutation UnlockCargoBike($id: ID!) {
...CargoBikeFields ...CargoBikeFields
} }
} }
mutation DeleteCargoBike($id: ID!) {
deleteCargoBike(id: $id)
}

@ -1,6 +1,12 @@
<div class="table-page-wrapper"> <div class="table-page-wrapper">
<div class="table-control"> <div class="table-control">
<button mat-raised-button color="primary" class="table-control-button" disabled i18n> <button
mat-raised-button
color="primary"
class="table-control-button"
disabled
i18n
>
Alle ausgewählten Fahrräder bearbeiten Alle ausgewählten Fahrräder bearbeiten
</button> </button>
<button <button
@ -35,7 +41,6 @@
></mat-paginator> ></mat-paginator>
</div> </div>
<div class="table-container"> <div class="table-container">
<table <table
mat-table mat-table
class="mat-elevation-z8" class="mat-elevation-z8"
@ -68,7 +73,6 @@
</td> </td>
</ng-container> </ng-container>
<!-- Other Columns --> <!-- Other Columns -->
<ng-container <ng-container
*ngFor="let column of columnInfo" *ngFor="let column of columnInfo"
@ -81,9 +85,17 @@
</th> </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<app-cell <app-cell
*ngIf="column.type === 'Boolean' || (element.newObject || !column.readonly && element.isLockedByMe); else stringValue" *ngIf="
[editable]="(element.newObject && column.acceptedForCreation) || !column.readonly && element.isLockedByMe" column.type === 'Boolean' ||
[required]="(element.newObject && column.requiredForCreation)" element.newObject ||
(!column.readonly && element.isLockedByMe);
else stringValue
"
[editable]="
(element.newObject && column.acceptedForCreation) ||
(!column.readonly && element.isLockedByMe)
"
[required]="element.newObject && column.requiredForCreation"
(validityChange)="validityChange(element, column.name, $event)" (validityChange)="validityChange(element, column.name, $event)"
[(value)]="element[column.name]" [(value)]="element[column.name]"
[inputType]="column.type" [inputType]="column.type"
@ -110,14 +122,21 @@
</button> </button>
<button <button
mat-icon-button mat-icon-button
[matMenuTriggerFor]="menu"
*ngIf=" *ngIf="
!element.isLockedByMe && !element.isLockedByMe &&
!isLoading(element.id) && !isLoading(element.id) &&
!element.isLocked !element.isLocked
" "
> >
<mat-icon>delete</mat-icon> <mat-icon>more_vert</mat-icon>
</button> </button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="openDeleteConfirmationDialog(element)"><mat-icon>delete</mat-icon>Löschen</button>
<button mat-menu-item>
<mat-icon>content_copy</mat-icon>Duplizieren
</button>
</mat-menu>
<mat-spinner <mat-spinner
[diameter]="32" [diameter]="32"
@ -146,7 +165,13 @@
>locked</mat-icon >locked</mat-icon
> >
</div> </div>
<div class="button-wrapper" *ngIf="element.newObject" [matTooltip]="'Nicht ausgefüllte Felder: '+countUnvalidFields(element)"> <div
class="button-wrapper"
*ngIf="element.newObject"
[matTooltip]="
'Nicht ausgefüllte Felder: ' + countUnvalidFields(element)
"
>
<button <button
mat-icon-button mat-icon-button
[disabled]="countUnvalidFields(element) > 0" [disabled]="countUnvalidFields(element) > 0"
@ -167,10 +192,13 @@
<!-- Table Definition --> <!-- Table Definition -->
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
<mat-card *ngIf="!isLoaded" style="display: flex; justify-content: center; align-items: center"> <mat-card
*ngIf="!isLoaded"
style="display: flex; justify-content: center; align-items: center"
>
<mat-spinner [diameter]="32"></mat-spinner> <mat-spinner [diameter]="32"></mat-spinner>
</mat-card> </mat-card>
</div> </div>

@ -1,5 +1,5 @@
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { Component, ViewChild } from '@angular/core'; import { Component, Inject, ViewChild } from '@angular/core';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { BikesService, CargoBikeResult } from 'src/app/services/bikes.service'; import { BikesService, CargoBikeResult } from 'src/app/services/bikes.service';
import { flatten } from 'src/app/helperFunctions/flattenObject'; import { flatten } from 'src/app/helperFunctions/flattenObject';
@ -11,6 +11,11 @@ import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator'; import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort'; import { MatSort } from '@angular/material/sort';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import {
MatDialog,
MatDialogRef,
MAT_DIALOG_DATA,
} from '@angular/material/dialog';
@Component({ @Component({
selector: 'app-bikes', selector: 'app-bikes',
@ -128,12 +133,13 @@ export class BikesComponent {
relockingInterval = null; relockingInterval = null;
relockingDuration = 1000 * 60 * 1; relockingDuration = 1000 * 60 * 1;
filterValue: string = ""; filterValue: string = '';
isLoaded = false; isLoaded = false;
constructor( constructor(
private bikesService: BikesService, private bikesService: BikesService,
private schemaService: SchemaService private schemaService: SchemaService,
public dialog: MatDialog
) {} ) {}
ngAfterViewInit() { ngAfterViewInit() {
@ -145,7 +151,7 @@ export class BikesComponent {
} }
return item[columnName]; return item[columnName];
} };
this.data.sort = this.sort; this.data.sort = this.sort;
this.columnInfo.forEach((column) => this.columnInfo.forEach((column) =>
@ -177,7 +183,6 @@ export class BikesComponent {
}); });
this.bikesService.loadBikes(); this.bikesService.loadBikes();
this.relockingInterval = setInterval(() => { this.relockingInterval = setInterval(() => {
for (const row of this.data.data) { for (const row of this.data.data) {
if (row.isLockedByMe) { if (row.isLockedByMe) {
@ -265,19 +270,22 @@ export class BikesComponent {
this.paginator.firstPage(); this.paginator.firstPage();
this.resetFilter(); this.resetFilter();
this.resetSorting(); this.resetSorting();
this.data.data = [{ newObject: true, id: this.getNewId() }, ...this.data.data]; this.data.data = [
{ newObject: true, id: this.getNewId() },
...this.data.data,
];
} }
getNewId(): string { getNewId(): string {
let id = -1; let id = -1;
while(this.getRowById(id.toString())) { while (this.getRowById(id.toString())) {
id--; id--;
} }
return id.toString(); return id.toString();
} }
deleteNewObject(row: any) { deleteNewObject(row: any) {
this.data.data = this.data.data.filter(element => row.id !== element.id); this.data.data = this.data.data.filter((element) => row.id !== element.id);
} }
create(row: any) { create(row: any) {
@ -304,6 +312,22 @@ export class BikesComponent {
this.bikesService.unlockBike({ id: row.id }); this.bikesService.unlockBike({ id: row.id });
} }
delete(row: any) {
this.bikesService.deleteBike({ id: row.id });
}
openDeleteConfirmationDialog(row: any) {
const dialogRef = this.dialog.open(DeleteConfirmationDialog, {
width: '250px',
});
dialogRef.afterClosed().subscribe((result) => {
if (result === true) {
this.delete(row);
}
});
}
getRowById(id: string) { getRowById(id: string) {
return this.data.data.find((row) => row.id === id); return this.data.data.find((row) => row.id === id);
} }
@ -335,11 +359,26 @@ export class BikesComponent {
} }
resetFilter() { resetFilter() {
this.filterValue = ""; this.filterValue = '';
this.applyFilter(); this.applyFilter();
} }
resetSorting() { resetSorting() {
this.sort.sort({id: null, start: 'asc', disableClear: false }); this.sort.sort({ id: null, start: 'asc', disableClear: false });
}
}
@Component({
selector: 'delete-confirmation-dialog',
templateUrl: 'delete-confirmation-dialog.html',
})
export class DeleteConfirmationDialog {
constructor(public dialogRef: MatDialogRef<DeleteConfirmationDialog>) {}
onConfirmClick(): void {
this.dialogRef.close(true);
}
onNoClick(): void {
this.dialogRef.close(false);
} }
} }

@ -0,0 +1,7 @@
<div mat-dialog-content>
<p i18n>Soll das Element wirklich gelöscht werden?</p>
</div>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()" i18n>Nein</button>
<button mat-button (click)="onConfirmClick()" color="warn">Ja, löschen</button>
</div>

@ -15,6 +15,8 @@ import {
UnlockCargoBikeMutationVariables, UnlockCargoBikeMutationVariables,
CreateCargoBikeGQL, CreateCargoBikeGQL,
CreateCargoBikeMutationVariables, CreateCargoBikeMutationVariables,
DeleteCargoBikeGQL,
DeleteCargoBikeMutationVariables,
} from 'src/generated/graphql'; } from 'src/generated/graphql';
import { DeepExtractTypeSkipArrays } from 'ts-deep-extract-types'; import { DeepExtractTypeSkipArrays } from 'ts-deep-extract-types';
@ -32,13 +34,13 @@ export class BikesService {
groupEnum: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]); groupEnum: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
constructor( constructor(
private schemaService: SchemaService,
private getCargoBikesGQL: GetCargoBikesGQL, private getCargoBikesGQL: GetCargoBikesGQL,
private getCargoBikeByIdGQL: GetCargoBikeByIdGQL, private getCargoBikeByIdGQL: GetCargoBikeByIdGQL,
private updateCargoBikeGQL: UpdateCargoBikeGQL, private updateCargoBikeGQL: UpdateCargoBikeGQL,
private lockCargoBikeGQL: LockCargoBikeGQL, private lockCargoBikeGQL: LockCargoBikeGQL,
private unlockCargoBikeGQL: UnlockCargoBikeGQL, private unlockCargoBikeGQL: UnlockCargoBikeGQL,
private createCargoBikeGQL: CreateCargoBikeGQL, private createCargoBikeGQL: CreateCargoBikeGQL,
private deleteCargoBikeGQL: DeleteCargoBikeGQL,
) {} ) {}
addLoadingRowId(id: string) { addLoadingRowId(id: string) {
@ -55,12 +57,6 @@ export class BikesService {
loadBikes() { loadBikes() {
this.getCargoBikesGQL.fetch().subscribe((result) => { this.getCargoBikesGQL.fetch().subscribe((result) => {
// comment in for performance testing
/*for (let i = 1; i <= 500; i++) {
const newBike = deepCopy(result.data.cargoBikes[0]);
newBike.id = (i + 100).toString();
result.data.cargoBikes.push(newBike);
}*/
this.bikes.next(result.data.cargoBikes); this.bikes.next(result.data.cargoBikes);
}); });
@ -146,6 +142,20 @@ export class BikesService {
}); });
} }
deleteBike(variables: DeleteCargoBikeMutationVariables) {
this.addLoadingRowId(variables.id);
this.deleteCargoBikeGQL
.mutate(variables)
.subscribe((result) => {
if(result.data.deleteCargoBike) {
this.bikes.next([...this.bikes.value].filter(bike => bike.id !== variables.id));
}
})
.add(() => {
this.removeLoadingRowId(variables.id);
});
}
relockBike(variables: LockCargoBikeMutationVariables) { relockBike(variables: LockCargoBikeMutationVariables) {
this.lockCargoBikeGQL.mutate(variables).subscribe(); this.lockCargoBikeGQL.mutate(variables).subscribe();
} }

@ -1,5 +1,6 @@
{ {
"__schema": { "__schema": {
"description": null,
"queryType": { "queryType": {
"name": "Query" "name": "Query"
}, },

@ -1764,6 +1764,16 @@ export type UnlockCargoBikeMutation = (
) } ) }
); );
export type DeleteCargoBikeMutationVariables = Exact<{
id: Scalars['ID'];
}>;
export type DeleteCargoBikeMutation = (
{ __typename?: 'Mutation' }
& Pick<Mutation, 'deleteCargoBike'>
);
export type GetCargoBikesQueryVariables = Exact<{ [key: string]: never; }>; export type GetCargoBikesQueryVariables = Exact<{ [key: string]: never; }>;
@ -2078,6 +2088,22 @@ export const UnlockCargoBikeDocument = gql`
export class UnlockCargoBikeGQL extends Apollo.Mutation<UnlockCargoBikeMutation, UnlockCargoBikeMutationVariables> { export class UnlockCargoBikeGQL extends Apollo.Mutation<UnlockCargoBikeMutation, UnlockCargoBikeMutationVariables> {
document = UnlockCargoBikeDocument; document = UnlockCargoBikeDocument;
constructor(apollo: Apollo.Apollo) {
super(apollo);
}
}
export const DeleteCargoBikeDocument = gql`
mutation DeleteCargoBike($id: ID!) {
deleteCargoBike(id: $id)
}
`;
@Injectable({
providedIn: 'root'
})
export class DeleteCargoBikeGQL extends Apollo.Mutation<DeleteCargoBikeMutation, DeleteCargoBikeMutationVariables> {
document = DeleteCargoBikeDocument;
constructor(apollo: Apollo.Apollo) { constructor(apollo: Apollo.Apollo) {
super(apollo); super(apollo);
} }

Loading…
Cancel
Save