diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index e067b23..c23b496 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -6,6 +6,7 @@ import { TableOverviewComponent } from './pages/table-overview/table-overview.co import { BikesComponent} from './pages/tables/bikes/bikes.component' import { EngagementTypesComponent } from './pages/tables/engagement-types/engagement-types.component'; import { EquipmentTypesComponent } from './pages/tables/equipment-types/equipment-types.component'; +import { EquipmentComponent } from './pages/tables/equipment/equipment.component'; import { LendingStationsComponent } from './pages/tables/lending-stations/lending-stations.component'; import { ParticipantsComponent } from './pages/tables/participants/participants.component'; @@ -18,6 +19,7 @@ const routes: Routes = [ { path: 'table/lendingStations', component: LendingStationsComponent }, { path: 'table/equipmentTypes', component: EquipmentTypesComponent }, { path: 'table/engagementTypes', component: EngagementTypesComponent }, + { path: 'table/equipment', component: EquipmentComponent }, { path: '', redirectTo: 'tableOverview', pathMatch: 'full' }, { path: 'table', redirectTo: 'tableOverview', pathMatch: 'full' }, { path: '**', redirectTo: 'tableOverview' }, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4493791..54e03db 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -52,6 +52,7 @@ import { EngagementTypesComponent } from './pages/tables/engagement-types/engage import { WorkshopsComponent } from './pages/tables/workshops/workshops.component'; import { ReferenceTableComponent } from './components/reference-table/reference-table.component' import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { EquipmentComponent } from './pages/tables/equipment/equipment.component'; @NgModule({ @@ -72,7 +73,8 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; EquipmentTypesComponent, EngagementTypesComponent, WorkshopsComponent, - ReferenceTableComponent + ReferenceTableComponent, + EquipmentComponent ], imports: [ BrowserModule, diff --git a/src/app/components/data-page/data-page.component.html b/src/app/components/data-page/data-page.component.html index 2ac2568..39b5fb5 100644 --- a/src/app/components/data-page/data-page.component.html +++ b/src/app/components/data-page/data-page.component.html @@ -25,7 +25,20 @@ - {{ object.title }} + {{ object.title }} + + subdirectory_arrow_right + table_chart + + - + deleteLöschen - diff --git a/src/app/components/table/table.component.scss b/src/app/components/table/table.component.scss index d600d31..7a6475d 100644 --- a/src/app/components/table/table.component.scss +++ b/src/app/components/table/table.component.scss @@ -41,7 +41,8 @@ min-width: 50px !important; } } - .mat-header-cell:first-child { + .mat-header-cell:first-child, + .mat-cell:first-child { padding-left: 1.5em; } ::ng-deep.mat-form-field { diff --git a/src/app/components/table/table.component.ts b/src/app/components/table/table.component.ts index 165c3f6..2497178 100644 --- a/src/app/components/table/table.component.ts +++ b/src/app/components/table/table.component.ts @@ -16,6 +16,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-table', @@ -77,7 +78,9 @@ export class TableComponent { @Output() cancelEvent = new EventEmitter(); @Output() deleteEvent = new EventEmitter(); - constructor(private schemaService: SchemaService, public dialog: MatDialog) {} + constructor(private schemaService: SchemaService, public dialog: MatDialog, private activatedroute:ActivatedRoute) { + this.filter.includesString = this.activatedroute.snapshot.queryParamMap.get('filter') || ''; + } ngAfterViewInit() { this.addColumnPropertiesFromGQLSchemaToColumnInfo(); diff --git a/src/app/graphqlOperations/equipment.graphql b/src/app/graphqlOperations/equipment.graphql new file mode 100644 index 0000000..50facd9 --- /dev/null +++ b/src/app/graphqlOperations/equipment.graphql @@ -0,0 +1,33 @@ +query GetEquipments { + equipment { + ...EquipmentFieldsForTable + } +} + +mutation CreateEquipment($equipmentType: EquipmentCreateInput!) { + createEquipment(equipment: $equipmentType) { + ...EquipmentFieldsForTable + } +} + +mutation UpdateEquipment($equipmentType: EquipmentUpdateInput!) { + updateEquipment(equipment: $equipmentType) { + ...EquipmentFieldsForTable + } +} + +mutation LockEquipment($id: ID!) { + lockEquipment(id: $id) { + ...EquipmentFieldsForTable + } +} + +mutation UnlockEquipment($id: ID!) { + unlockEquipment(id: $id) { + ...EquipmentFieldsForTable + } +} + +mutation DeleteEquipment($id: ID!) { + deleteEquipment(id: $id) +} diff --git a/src/app/graphqlOperations/fragments/equipment.graphql b/src/app/graphqlOperations/fragments/equipment.graphql index 4e88d4f..a777431 100644 --- a/src/app/graphqlOperations/fragments/equipment.graphql +++ b/src/app/graphqlOperations/fragments/equipment.graphql @@ -3,6 +3,17 @@ fragment EquipmentFieldsForBikePage on Equipment { serialNo title description +} + +fragment EquipmentFieldsForTable on Equipment { + id + serialNo + title + description + cargoBike { + id + name + } isLocked isLockedByMe lockedBy diff --git a/src/app/pages/dataPages/bike/bike.component.ts b/src/app/pages/dataPages/bike/bike.component.ts index bc04539..14fe6fc 100644 --- a/src/app/pages/dataPages/bike/bike.component.ts +++ b/src/app/pages/dataPages/bike/bike.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { BikesService } from 'src/app/services/bikes.service'; +import { EquipmentService } from 'src/app/services/equipment.service'; import { EquipmentTypeService } from 'src/app/services/equipmentType.service'; @Component({ @@ -206,8 +207,30 @@ export class BikeComponent implements OnInit { nameToShowInSelection: (element) => { return element.name; }, + linkToTable: (element) => { + return '/table/equipmentTypes'; + }, propertyNameOfUpdateInput: 'equipmentTypeIds', }, + { + type: 'ReferenceTable', + title: 'Equipment', + dataPath: 'equipment', + dataService: null, + columnInfo: [ + { dataPath: 'serialNo', translation: 'Seriennummer' }, + { dataPath: 'title', translation: 'Name' }, + { dataPath: 'description', translation: 'Beschreibung' }, + ], + nameToShowInSelection: (element) => { + return element.title + ' (' + element.serialNo + ')'; + }, + linkToTable: (element) => '/table/equipment', + linkToTableParams: (bike) => { + return {filter: bike.name}; + }, + propertyNameOfUpdateInput: 'equipmentIds', + }, ]; headlineDataPath = 'name'; @@ -218,11 +241,16 @@ export class BikeComponent implements OnInit { constructor( private bikesService: BikesService, - private equipmentTypeService: EquipmentTypeService + private equipmentTypeService: EquipmentTypeService, + private equipmentService: EquipmentService ) { this.propertiesInfo.find( (prop) => prop.dataPath === 'equipmentType' ).dataService = this.equipmentTypeService; + + this.propertiesInfo.find( + (prop) => prop.dataPath === 'equipment' + ).dataService = this.equipmentService; } ngOnInit(): void { diff --git a/src/app/pages/tables/equipment-types/equipment-types.component.ts b/src/app/pages/tables/equipment-types/equipment-types.component.ts index f8aaae1..72bfa16 100644 --- a/src/app/pages/tables/equipment-types/equipment-types.component.ts +++ b/src/app/pages/tables/equipment-types/equipment-types.component.ts @@ -7,7 +7,7 @@ import {EquipmentTypeService} from 'src/app/services/equipmentType.service' styleUrls: ['./equipment-types.component.scss'] }) export class EquipmentTypesComponent implements OnInit { - headline = 'Ausstattungstypen'; + headline = 'Equipmenttypen'; columnInfo = [ { dataPath: 'id', translation: 'ID', readonly: true }, diff --git a/src/app/pages/tables/equipment/equipment.component.html b/src/app/pages/tables/equipment/equipment.component.html new file mode 100644 index 0000000..fb3a5aa --- /dev/null +++ b/src/app/pages/tables/equipment/equipment.component.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/src/app/pages/tables/equipment/equipment.component.scss b/src/app/pages/tables/equipment/equipment.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/pages/tables/equipment/equipment.component.ts b/src/app/pages/tables/equipment/equipment.component.ts new file mode 100644 index 0000000..14fb55a --- /dev/null +++ b/src/app/pages/tables/equipment/equipment.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit } from '@angular/core'; +import { EquipmentService } from 'src/app/services/equipment.service'; + +@Component({ + selector: 'app-equipment', + templateUrl: './equipment.component.html', + styleUrls: ['./equipment.component.scss'], +}) +export class EquipmentComponent implements OnInit { + headline = 'Equipment'; + + columnInfo = [ + { dataPath: 'id', translation: 'ID', readonly: true }, + { dataPath: 'serialNo', translation: 'Seriennummer' }, + { dataPath: 'title', translation: 'Name' }, + { dataPath: 'description', translation: 'Beschreibung' }, + { + dataPath: 'cargoBike.name', + translation: 'Lastenrad', + link: (element) => { + return '/bike/' + element['cargoBike.id']; + }, + }, + ]; + + dataService: EquipmentService; + + tableDataGQLType: string = 'Equipment'; + tableDataGQLCreateInputType: string = 'EquipmentCreateInput'; + tableDataGQLUpdateInputType: string = 'EquipmentUpdateInput'; + + loadingRowIds: string[] = []; + constructor(private service: EquipmentService) {} + + ngOnInit() { + this.dataService = this.service; + } + + create(value: { currentId: string; row: any }) { + this.dataService.create(value.currentId, { equipmentType: value.row }); + } + + lock(row: any) { + this.dataService.lock({ id: row.id }); + } + + save(row: any) { + this.dataService.update({ equipmentType: row }); + } + + cancel(row: any) { + this.dataService.unlock({ id: row.id }); + } + + delete(row: any) { + this.dataService.delete({ id: row.id }); + } +} diff --git a/src/app/services/equipment.service.ts b/src/app/services/equipment.service.ts new file mode 100644 index 0000000..8dca971 --- /dev/null +++ b/src/app/services/equipment.service.ts @@ -0,0 +1,125 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { + GetEquipmentsGQL, + CreateEquipmentGQL, + CreateEquipmentMutationVariables, + UpdateEquipmentGQL, + UpdateEquipmentMutationVariables, + LockEquipmentGQL, + LockEquipmentMutationVariables, + UnlockEquipmentGQL, + UnlockEquipmentMutationVariables, + DeleteEquipmentGQL, + DeleteEquipmentMutationVariables, +} from '../../generated/graphql'; + +@Injectable({ + providedIn: 'root', +}) +export class EquipmentService { + /** Equipments Array */ + tableData: BehaviorSubject = new BehaviorSubject(null); + loadingRowIds: BehaviorSubject = new BehaviorSubject([]); + successfullyCreatedRowWithId: Subject = new Subject(); + //pageData: BehaviorSubject = new BehaviorSubject([]); + //isLoadingPageData: BehaviorSubject = new BehaviorSubject(false); + + constructor( + private getEquipmentsGQL: GetEquipmentsGQL, + private createEquipmentGQL: CreateEquipmentGQL, + private updateEquipmentGQL: UpdateEquipmentGQL, + private lockEquipmentGQL: LockEquipmentGQL, + private unlockEquipmentGQL: UnlockEquipmentGQL, + private deleteEquipmentGQL: DeleteEquipmentGQL + ) {} + + addLoadingRowId(id: string) { + this.loadingRowIds.next([...this.loadingRowIds.value, id]); + } + + removeLoadingRowId(id: string) { + this.loadingRowIds.value.forEach((item, index) => { + if (item === id) { + this.loadingRowIds.value.splice(index, 1); + } + }); + this.loadingRowIds.next(this.loadingRowIds.value); + } + + loadTableData() { + this.tableData.next(null); + this.getEquipmentsGQL.fetch().subscribe((result) => { + this.tableData.next(result.data.equipment); + }); + } + + create(currentId: string, variables: CreateEquipmentMutationVariables) { + this.createEquipmentGQL.mutate(variables).subscribe((result) => { + const newRow = result.data.createEquipment; + this.tableData.next([newRow, ...this.tableData.value]); + this.successfullyCreatedRowWithId.next(currentId); + }); + } + + update(variables: UpdateEquipmentMutationVariables) { + this.addLoadingRowId(variables.equipmentType.id); + this.updateEquipmentGQL + .mutate(variables) + .subscribe((result) => { + this.updateDataRowFromResponse(result.data.updateEquipment); + }) + .add(() => { + this.removeLoadingRowId(variables.equipmentType.id); + }); + } + + lock(variables: LockEquipmentMutationVariables) { + this.addLoadingRowId(variables.id); + this.lockEquipmentGQL + .mutate(variables) + .subscribe((result) => { + this.updateDataRowFromResponse(result.data.lockEquipment); + }) + .add(() => { + this.removeLoadingRowId(variables.id); + }); + } + + unlock(variables: UnlockEquipmentMutationVariables) { + this.addLoadingRowId(variables.id); + this.unlockEquipmentGQL + .mutate(variables) + .subscribe((result) => { + this.updateDataRowFromResponse(result.data.unlockEquipment); + }) + .add(() => { + this.removeLoadingRowId(variables.id); + }); + } + + delete(variables: DeleteEquipmentMutationVariables) { + this.addLoadingRowId(variables.id); + this.deleteEquipmentGQL + .mutate(variables) + .subscribe((result) => { + if (result.data.deleteEquipment) { + this.tableData.next( + [...this.tableData.value].filter((bike) => bike.id !== variables.id) + ); + } + }) + .add(() => { + this.removeLoadingRowId(variables.id); + }); + } + + private updateDataRowFromResponse(rowFromResponse: any) { + if (this.tableData.value) { + const newTableData = this.tableData.value.map((row) => + rowFromResponse.id === row.id ? rowFromResponse : row + ); + this.tableData.next(newTableData); + } + } +} diff --git a/src/app/services/equipmentType.service.ts b/src/app/services/equipmentType.service.ts index a595930..68d2de5 100644 --- a/src/app/services/equipmentType.service.ts +++ b/src/app/services/equipmentType.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Subject } from 'rxjs'; import { GetEquipmentTypesGQL, - GetEquipmentTypesQueryVariables, CreateEquipmentTypeGQL, CreateEquipmentTypeMutationVariables, UpdateEquipmentTypeGQL, diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts index 5140973..713d337 100644 --- a/src/generated/graphql.ts +++ b/src/generated/graphql.ts @@ -1845,6 +1845,79 @@ export type DeleteCargoBikeMutation = ( & Pick ); +export type GetEquipmentsQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetEquipmentsQuery = ( + { __typename?: 'Query' } + & { equipment: Array<( + { __typename?: 'Equipment' } + & EquipmentFieldsForTableFragment + )> } +); + +export type CreateEquipmentMutationVariables = Exact<{ + equipmentType: EquipmentCreateInput; +}>; + + +export type CreateEquipmentMutation = ( + { __typename?: 'Mutation' } + & { createEquipment: ( + { __typename?: 'Equipment' } + & EquipmentFieldsForTableFragment + ) } +); + +export type UpdateEquipmentMutationVariables = Exact<{ + equipmentType: EquipmentUpdateInput; +}>; + + +export type UpdateEquipmentMutation = ( + { __typename?: 'Mutation' } + & { updateEquipment: ( + { __typename?: 'Equipment' } + & EquipmentFieldsForTableFragment + ) } +); + +export type LockEquipmentMutationVariables = Exact<{ + id: Scalars['ID']; +}>; + + +export type LockEquipmentMutation = ( + { __typename?: 'Mutation' } + & { lockEquipment: ( + { __typename?: 'Equipment' } + & EquipmentFieldsForTableFragment + ) } +); + +export type UnlockEquipmentMutationVariables = Exact<{ + id: Scalars['ID']; +}>; + + +export type UnlockEquipmentMutation = ( + { __typename?: 'Mutation' } + & { unlockEquipment: ( + { __typename?: 'Equipment' } + & EquipmentFieldsForTableFragment + ) } +); + +export type DeleteEquipmentMutationVariables = Exact<{ + id: Scalars['ID']; +}>; + + +export type DeleteEquipmentMutation = ( + { __typename?: 'Mutation' } + & Pick +); + export type GetEquipmentTypesQueryVariables = Exact<{ [key: string]: never; }>; @@ -2019,8 +2092,17 @@ export type EngagementTypeFieldsFragment = ( ); export type EquipmentFieldsForBikePageFragment = ( + { __typename?: 'Equipment' } + & Pick +); + +export type EquipmentFieldsForTableFragment = ( { __typename?: 'Equipment' } & Pick + & { cargoBike?: Maybe<( + { __typename?: 'CargoBike' } + & Pick + )> } ); export type EquipmentTypeFieldsFragment = ( @@ -2313,10 +2395,6 @@ export const EquipmentFieldsForBikePageFragmentDoc = gql` serialNo title description - isLocked - isLockedByMe - lockedBy - lockedUntil } `; export const EquipmentTypeFieldsFragmentDoc = gql` @@ -2402,6 +2480,22 @@ ${EquipmentFieldsForBikePageFragmentDoc} ${EquipmentTypeFieldsFragmentDoc} ${EngagementFieldsForBikePageFragmentDoc} ${TimeFrameFieldsForBikePageFragmentDoc}`; +export const EquipmentFieldsForTableFragmentDoc = gql` + fragment EquipmentFieldsForTable on Equipment { + id + serialNo + title + description + cargoBike { + id + name + } + isLocked + isLockedByMe + lockedBy + lockedUntil +} + `; export const GetCargoBikesDocument = gql` query GetCargoBikes { cargoBikes { @@ -2540,6 +2634,112 @@ export const DeleteCargoBikeDocument = gql` export class DeleteCargoBikeGQL extends Apollo.Mutation { document = DeleteCargoBikeDocument; + constructor(apollo: Apollo.Apollo) { + super(apollo); + } + } +export const GetEquipmentsDocument = gql` + query GetEquipments { + equipment { + ...EquipmentFieldsForTable + } +} + ${EquipmentFieldsForTableFragmentDoc}`; + + @Injectable({ + providedIn: 'root' + }) + export class GetEquipmentsGQL extends Apollo.Query { + document = GetEquipmentsDocument; + + constructor(apollo: Apollo.Apollo) { + super(apollo); + } + } +export const CreateEquipmentDocument = gql` + mutation CreateEquipment($equipmentType: EquipmentCreateInput!) { + createEquipment(equipment: $equipmentType) { + ...EquipmentFieldsForTable + } +} + ${EquipmentFieldsForTableFragmentDoc}`; + + @Injectable({ + providedIn: 'root' + }) + export class CreateEquipmentGQL extends Apollo.Mutation { + document = CreateEquipmentDocument; + + constructor(apollo: Apollo.Apollo) { + super(apollo); + } + } +export const UpdateEquipmentDocument = gql` + mutation UpdateEquipment($equipmentType: EquipmentUpdateInput!) { + updateEquipment(equipment: $equipmentType) { + ...EquipmentFieldsForTable + } +} + ${EquipmentFieldsForTableFragmentDoc}`; + + @Injectable({ + providedIn: 'root' + }) + export class UpdateEquipmentGQL extends Apollo.Mutation { + document = UpdateEquipmentDocument; + + constructor(apollo: Apollo.Apollo) { + super(apollo); + } + } +export const LockEquipmentDocument = gql` + mutation LockEquipment($id: ID!) { + lockEquipment(id: $id) { + ...EquipmentFieldsForTable + } +} + ${EquipmentFieldsForTableFragmentDoc}`; + + @Injectable({ + providedIn: 'root' + }) + export class LockEquipmentGQL extends Apollo.Mutation { + document = LockEquipmentDocument; + + constructor(apollo: Apollo.Apollo) { + super(apollo); + } + } +export const UnlockEquipmentDocument = gql` + mutation UnlockEquipment($id: ID!) { + unlockEquipment(id: $id) { + ...EquipmentFieldsForTable + } +} + ${EquipmentFieldsForTableFragmentDoc}`; + + @Injectable({ + providedIn: 'root' + }) + export class UnlockEquipmentGQL extends Apollo.Mutation { + document = UnlockEquipmentDocument; + + constructor(apollo: Apollo.Apollo) { + super(apollo); + } + } +export const DeleteEquipmentDocument = gql` + mutation DeleteEquipment($id: ID!) { + deleteEquipment(id: $id) +} + `; + + @Injectable({ + providedIn: 'root' + }) + export class DeleteEquipmentGQL extends Apollo.Mutation { + document = DeleteEquipmentDocument; + constructor(apollo: Apollo.Apollo) { super(apollo); }