Compare commits
5 Commits
cba564a811
...
321ffc3b7c
| Author | SHA1 | Date | |
|---|---|---|---|
| 321ffc3b7c | |||
| 0fa5b080d8 | |||
| 85052df8a5 | |||
| bcbf76fda6 | |||
| b989c43ec3 |
@@ -113,5 +113,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/Vegasco-Web/src/app/api/api-base-path.ts
Normal file
6
src/Vegasco-Web/src/app/api/api-base-path.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { InjectionToken } from "@angular/core";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base path for all API requests, e.g. when using a proxy on the origin's address.
|
||||||
|
*/
|
||||||
|
export const API_BASE_PATH = new InjectionToken<string>('API_BASE_PATH');
|
||||||
35
src/Vegasco-Web/src/app/api/cars/car-client.ts
Normal file
35
src/Vegasco-Web/src/app/api/cars/car-client.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import {inject, Injectable} from "@angular/core";
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {map, Observable} from 'rxjs';
|
||||||
|
import {API_BASE_PATH} from '../api-base-path';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class CarClient {
|
||||||
|
private readonly http = inject(HttpClient);
|
||||||
|
private readonly apiBasePath = inject(API_BASE_PATH, {optional: true});
|
||||||
|
|
||||||
|
getAll(): Observable<GetCarsResponse> {
|
||||||
|
return this.http.get<GetCarsResponse>(`${this.apiBasePath}/v1/cars`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSingle(id: string): Observable<Car> {
|
||||||
|
return this.http.get<Car>(`${this.apiBasePath}/v1/cars/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
create(request: CreateCarRequest): Observable<Car> {
|
||||||
|
return this.http.post<Car>(`${this.apiBasePath}/v1/cars`, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(request: UpdateCarRequest): Observable<Car> {
|
||||||
|
return this.http.put<Car>(`${this.apiBasePath}/v1/cars`, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: string): Observable<void> {
|
||||||
|
return this.http.delete(`${this.apiBasePath}/v1/cars/${id}`)
|
||||||
|
.pipe(
|
||||||
|
map(_ => undefined)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/Vegasco-Web/src/app/api/cars/car.ts
Normal file
4
src/Vegasco-Web/src/app/api/cars/car.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
interface Car {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
3
src/Vegasco-Web/src/app/api/cars/create-car-request.ts
Normal file
3
src/Vegasco-Web/src/app/api/cars/create-car-request.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
interface CreateCarRequest {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
3
src/Vegasco-Web/src/app/api/cars/get-cars-response.ts
Normal file
3
src/Vegasco-Web/src/app/api/cars/get-cars-response.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
interface GetCarsResponse {
|
||||||
|
cars: Car[];
|
||||||
|
}
|
||||||
3
src/Vegasco-Web/src/app/api/cars/update-car-request.ts
Normal file
3
src/Vegasco-Web/src/app/api/cars/update-car-request.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
interface UpdateCarRequest {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import {inject, Injectable} from '@angular/core';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {API_BASE_PATH} from '../api-base-path';
|
||||||
|
import {map, Observable} from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class ConsumptionClient {
|
||||||
|
private readonly http = inject(HttpClient);
|
||||||
|
private readonly apiBasePath = inject(API_BASE_PATH, {optional: true});
|
||||||
|
|
||||||
|
getAll(): Observable<GetConsumptionEntriesResponse> {
|
||||||
|
return this.http.get<GetConsumptionEntriesResponse>(`${this.apiBasePath}/v1/consumptions`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSingle(id: string): Observable<ConsumptionEntry> {
|
||||||
|
return this.http.get<ConsumptionEntry>(`${this.apiBasePath}/v1/consumptions/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
create(request: CreateCarRequest): Observable<ConsumptionEntry> {
|
||||||
|
return this.http.post<ConsumptionEntry>(`${this.apiBasePath}/v1/consumptions`, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(request: UpdateCarRequest): Observable<ConsumptionEntry> {
|
||||||
|
return this.http.put<ConsumptionEntry>(`${this.apiBasePath}/v1/consumptions`, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: string): Observable<void> {
|
||||||
|
return this.http.delete(`${this.apiBasePath}/v1/consumptions/${id}`)
|
||||||
|
.pipe(
|
||||||
|
map(_ => undefined),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
interface CreateConsumptionEntry {
|
||||||
|
dateTime: string;
|
||||||
|
distance: number;
|
||||||
|
amount: number;
|
||||||
|
ignoreInCalculation: boolean;
|
||||||
|
carId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
interface UpdateConsumptionEntry {
|
||||||
|
dateTime: string;
|
||||||
|
distance: number;
|
||||||
|
amount: number;
|
||||||
|
ignoreInCalculation: boolean;
|
||||||
|
carId: string;
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import { includeBearerTokenInterceptor } from 'keycloak-angular';
|
|||||||
import { providePrimeNG } from 'primeng/config';
|
import { providePrimeNG } from 'primeng/config';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import { provideKeycloakAngular } from './auth/auth.config';
|
import { provideKeycloakAngular } from './auth/auth.config';
|
||||||
|
import {API_BASE_PATH} from './api/api-base-path';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
@@ -21,5 +22,9 @@ export const appConfig: ApplicationConfig = {
|
|||||||
},
|
},
|
||||||
ripple: true
|
ripple: true
|
||||||
}),
|
}),
|
||||||
|
{
|
||||||
|
provide: API_BASE_PATH,
|
||||||
|
useValue: '/api'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,31 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import {AsyncPipe, CommonModule} from '@angular/common';
|
||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
import { MessageService } from 'primeng/api';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from 'primeng/button';
|
||||||
import { DataViewModule } from 'primeng/dataview';
|
import { DataViewModule } from 'primeng/dataview';
|
||||||
import { ScrollTopModule } from 'primeng/scrolltop';
|
|
||||||
import { SelectModule } from 'primeng/select';
|
import { SelectModule } from 'primeng/select';
|
||||||
|
import { ScrollTopModule } from 'primeng/scrolltop';
|
||||||
import { SkeletonModule } from 'primeng/skeleton';
|
import { SkeletonModule } from 'primeng/skeleton';
|
||||||
import {
|
import {
|
||||||
|
BehaviorSubject,
|
||||||
|
combineLatest,
|
||||||
map,
|
map,
|
||||||
Observable,
|
Observable,
|
||||||
tap
|
of,
|
||||||
|
startWith,
|
||||||
|
tap,
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
import { Client, GetConsumptions_ResponseDto } from '../../../shared/api/swagger.generated';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import {CarClient} from '../../../api/cars/car-client';
|
||||||
|
import {ConsumptionClient} from '../../../api/consumptions/consumption-client';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-entries',
|
selector: 'app-entries',
|
||||||
imports: [
|
imports: [
|
||||||
|
AsyncPipe,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
DataViewModule,
|
DataViewModule,
|
||||||
@@ -31,24 +39,29 @@ import { Client, GetConsumptions_ResponseDto } from '../../../shared/api/swagger
|
|||||||
styleUrl: './entries.component.scss'
|
styleUrl: './entries.component.scss'
|
||||||
})
|
})
|
||||||
export class EntriesComponent {
|
export class EntriesComponent {
|
||||||
private readonly client = inject(Client);
|
private readonly consumptionClient = inject(ConsumptionClient);
|
||||||
|
private readonly carClient = inject(CarClient);
|
||||||
|
|
||||||
protected readonly consumptionEntries$: Observable<GetConsumptions_ResponseDto[] | undefined>;
|
protected readonly consumptionEntries$: Observable<ConsumptionEntry[]>;
|
||||||
|
protected readonly cars$: Observable<Car[]>;
|
||||||
protected readonly rowsPerPageDefaultOption = 25;
|
|
||||||
protected readonly rowsPerPageOptions = [10, 25, 50, 100];
|
|
||||||
protected readonly currentPageReportTemplate = '{currentPage} / {totalPages}';
|
|
||||||
|
|
||||||
protected readonly skeletonsIterationSource = Array(10).fill(0);
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.consumptionEntries$ = this.client.consumptionsGET()
|
this.consumptionEntries$ = this.consumptionClient.getAll()
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntilDestroyed(),
|
takeUntilDestroyed(),
|
||||||
tap((response) => {
|
tap((response) => {
|
||||||
console.log('Entries response:', response);
|
console.log('Entries response:', response);
|
||||||
}),
|
}),
|
||||||
map((response) => response.consumptions)
|
map(response => response.consumptions)
|
||||||
)
|
);
|
||||||
|
|
||||||
|
this.cars$ = this.carClient.getAll()
|
||||||
|
.pipe(
|
||||||
|
takeUntilDestroyed(),
|
||||||
|
tap((response) => {
|
||||||
|
console.log('Cars response:', response);
|
||||||
|
}),
|
||||||
|
map(response => response.cars)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ public static class CreateCar
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapPost("cars", Endpoint)
|
.MapPost("cars", Endpoint)
|
||||||
.WithTags("Cars");
|
.WithTags("Cars")
|
||||||
|
.WithDescription("Creates a new car")
|
||||||
|
.Produces<Response>(201)
|
||||||
|
.ProducesValidationProblem();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Validator : AbstractValidator<Request>
|
public class Validator : AbstractValidator<Request>
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ public static class DeleteCar
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapDelete("cars/{id:guid}", Endpoint)
|
.MapDelete("cars/{id:guid}", Endpoint)
|
||||||
.WithTags("Cars");
|
.WithTags("Cars")
|
||||||
|
.WithDescription("Deletes a car by ID")
|
||||||
|
.Produces(204)
|
||||||
|
.Produces(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<IResult> Endpoint(
|
public static async Task<IResult> Endpoint(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Vegasco.Server.Api.Persistence;
|
using Microsoft.AspNetCore.Http.HttpResults;
|
||||||
|
using Vegasco.Server.Api.Persistence;
|
||||||
|
|
||||||
namespace Vegasco.Server.Api.Cars;
|
namespace Vegasco.Server.Api.Cars;
|
||||||
|
|
||||||
@@ -10,7 +11,10 @@ public static class GetCar
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapGet("cars/{id:guid}", Endpoint)
|
.MapGet("cars/{id:guid}", Endpoint)
|
||||||
.WithTags("Cars");
|
.WithDescription("Returns a single car by ID")
|
||||||
|
.WithTags("Cars")
|
||||||
|
.Produces<Response>()
|
||||||
|
.Produces(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IResult> Endpoint(
|
private static async Task<IResult> Endpoint(
|
||||||
@@ -28,4 +32,4 @@ public static class GetCar
|
|||||||
var response = new Response(car.Id.Value, car.Name);
|
var response = new Response(car.Id.Value, car.Name);
|
||||||
return TypedResults.Ok(response);
|
return TypedResults.Ok(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,10 +25,11 @@ public static class GetCars
|
|||||||
return builder
|
return builder
|
||||||
.MapGet("cars", Endpoint)
|
.MapGet("cars", Endpoint)
|
||||||
.WithDescription("Returns all cars")
|
.WithDescription("Returns all cars")
|
||||||
.WithTags("Cars");
|
.WithTags("Cars")
|
||||||
|
.Produces<ApiResponse>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Ok<ApiResponse>> Endpoint(
|
private static async Task<IResult> Endpoint(
|
||||||
[AsParameters] Request request,
|
[AsParameters] Request request,
|
||||||
ApplicationDbContext dbContext,
|
ApplicationDbContext dbContext,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
|
|||||||
@@ -15,7 +15,11 @@ public static class UpdateCar
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapPut("cars/{id:guid}", Endpoint)
|
.MapPut("cars/{id:guid}", Endpoint)
|
||||||
.WithTags("Cars");
|
.WithTags("Cars")
|
||||||
|
.WithDescription("Updates a car by ID")
|
||||||
|
.Produces<Response>()
|
||||||
|
.ProducesValidationProblem()
|
||||||
|
.Produces(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Validator : AbstractValidator<Request>
|
public class Validator : AbstractValidator<Request>
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ public static class CreateConsumption
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapPost("consumptions", Endpoint)
|
.MapPost("consumptions", Endpoint)
|
||||||
.WithTags("Consumptions");
|
.WithTags("Consumptions")
|
||||||
|
.WithDescription("Creates a new consumption entry")
|
||||||
|
.Produces<Response>(201);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Validator : AbstractValidator<Request>
|
public class Validator : AbstractValidator<Request>
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ public static class DeleteConsumption
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapDelete("consumptions/{id:guid}", Endpoint)
|
.MapDelete("consumptions/{id:guid}", Endpoint)
|
||||||
.WithTags("Consumptions");
|
.WithTags("Consumptions")
|
||||||
|
.WithDescription("Deletes a consumption entry by ID")
|
||||||
|
.Produces(204)
|
||||||
|
.Produces(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IResult> Endpoint(
|
private static async Task<IResult> Endpoint(
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ public static class GetConsumption
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapGet("consumptions/{id:guid}", Endpoint)
|
.MapGet("consumptions/{id:guid}", Endpoint)
|
||||||
.WithTags("Consumptions");
|
.WithTags("Consumptions")
|
||||||
|
.WithDescription("Returns a single consumption entry by ID")
|
||||||
|
.Produces<Response>()
|
||||||
|
.Produces(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IResult> Endpoint(
|
private static async Task<IResult> Endpoint(
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ public static class GetConsumptions
|
|||||||
return builder
|
return builder
|
||||||
.MapGet("consumptions", Endpoint)
|
.MapGet("consumptions", Endpoint)
|
||||||
.WithDescription("Returns all consumption entries")
|
.WithDescription("Returns all consumption entries")
|
||||||
.WithTags("Consumptions");
|
.WithTags("Consumptions")
|
||||||
|
.Produces<ApiResponse>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Ok<ApiResponse>> Endpoint(
|
private static async Task<Ok<ApiResponse>> Endpoint(
|
||||||
@@ -44,7 +45,7 @@ public static class GetConsumptions
|
|||||||
new ResponseDto(x.Id.Value, x.DateTime, x.Distance, x.Amount, x.IgnoreInCalculation, x.CarId.Value))
|
new ResponseDto(x.Id.Value, x.DateTime, x.Distance, x.Amount, x.IgnoreInCalculation, x.CarId.Value))
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
var apiResponse = new ApiResponse
|
ApiResponse apiResponse = new()
|
||||||
{
|
{
|
||||||
Consumptions = consumptions
|
Consumptions = consumptions
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,11 @@ public static class UpdateConsumption
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.MapPut("consumptions/{id:guid}", Endpoint)
|
.MapPut("consumptions/{id:guid}", Endpoint)
|
||||||
.WithTags("Consumptions");
|
.WithTags("Consumptions")
|
||||||
|
.WithDescription("Updates a consumption entry by ID")
|
||||||
|
.Produces<Response>()
|
||||||
|
.ProducesValidationProblem()
|
||||||
|
.Produces(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Validator : AbstractValidator<Request>
|
public class Validator : AbstractValidator<Request>
|
||||||
|
|||||||
Reference in New Issue
Block a user