mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 13:49:36 +01:00
feat: Paginierung für alle GET-List-Endpoints (#61)
Einheitliches Paginierungs-Pattern mit page, size und Multi-Field sort
für alle 14 List-Endpoints. Response-Format ändert sich von [...] zu
{ content: [...], page: { number, size, totalElements, totalPages } }.
Backend:
- Shared Kernel: Page<T>, PageRequest, SortField, SortDirection
- PaginationHelper (SQL ORDER BY mit Whitelist), PageResponse DTO
- Paginated Methoden in allen 14 Domain-Repos + JDBC-Implementierungen
- Safety-Limit (500) für findAllBelowMinimumLevel/ExpiryRelevantBatches
- Alle List-Use-Cases akzeptieren PageRequest, liefern Page<T>
- Alle Controller mit page/size/sort Query-Params + PageResponse
Frontend:
- PagedResponse<T> Type auf nested page-Format aktualisiert
- Alle 14 API-Client-Resourcen liefern PagedResponse mit PaginationParams
- Alle Hooks mit Pagination-State (currentPage, totalPages, pageSize)
- Alle List-Screens mit Seiten-Navigation (Pfeiltasten) und Footer
Loadtest:
- Podman-Support im justfile (DOCKER_HOST auto-detect)
- Verschärfte Performance-Schwellwerte basierend auf Ist-Werten
This commit is contained in:
parent
fc4faafd57
commit
72979c9537
151 changed files with 2880 additions and 1120 deletions
|
|
@ -17,6 +17,8 @@ import type {
|
|||
UpdateArticleRequest,
|
||||
AddSalesUnitRequest,
|
||||
UpdateSalesUnitPriceRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type Unit = 'PIECE_FIXED' | 'KG' | 'HUNDRED_GRAM' | 'PIECE_VARIABLE';
|
||||
|
|
@ -48,8 +50,12 @@ export type {
|
|||
|
||||
export function createArticlesResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(): Promise<ArticleDTO[]> {
|
||||
const res = await client.get<ArticleDTO[]>('/api/articles');
|
||||
async list(pagination?: PaginationParams): Promise<PagedResponse<ArticleDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<ArticleDTO>>('/api/articles', { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import type {
|
|||
CompleteBatchRequest,
|
||||
RecordConsumptionRequest,
|
||||
CancelBatchRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type BatchStatus = 'PLANNED' | 'IN_PRODUCTION' | 'COMPLETED' | 'CANCELLED';
|
||||
|
|
@ -34,10 +36,13 @@ const BASE = '/api/production/batches';
|
|||
|
||||
export function createBatchesResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(status?: BatchStatus): Promise<BatchSummaryDTO[]> {
|
||||
const params: Record<string, string> = {};
|
||||
async list(status?: BatchStatus, pagination?: PaginationParams): Promise<PagedResponse<BatchSummaryDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (status) params.status = status;
|
||||
const res = await client.get<BatchSummaryDTO[]>(BASE, { params });
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<BatchSummaryDTO>>(BASE, { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import type {
|
|||
ProductCategoryDTO,
|
||||
CreateCategoryRequest,
|
||||
UpdateCategoryRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type {
|
||||
|
|
@ -23,8 +25,12 @@ export type {
|
|||
|
||||
export function createCategoriesResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(): Promise<ProductCategoryDTO[]> {
|
||||
const res = await client.get<ProductCategoryDTO[]>('/api/categories');
|
||||
async list(pagination?: PaginationParams): Promise<PagedResponse<ProductCategoryDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<ProductCategoryDTO>>('/api/categories', { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import type { AxiosInstance } from 'axios';
|
||||
import type { CountryDTO } from '@effigenix/types';
|
||||
import type { CountryDTO, PaginationParams, PagedResponse } from '@effigenix/types';
|
||||
|
||||
export type { CountryDTO };
|
||||
|
||||
export function createCountriesResource(client: AxiosInstance) {
|
||||
return {
|
||||
async search(query?: string): Promise<CountryDTO[]> {
|
||||
const res = await client.get<CountryDTO[]>('/api/countries', {
|
||||
params: query ? { q: query } : {},
|
||||
});
|
||||
async search(query?: string, pagination?: PaginationParams): Promise<PagedResponse<CountryDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (query) params.q = query;
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<CountryDTO>>('/api/countries', { params });
|
||||
return res.data;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import type {
|
|||
UpdateCustomerRequest,
|
||||
AddDeliveryAddressRequest,
|
||||
SetFrameContractRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type CustomerType = 'B2B' | 'B2C';
|
||||
|
|
@ -68,8 +70,12 @@ export type {
|
|||
|
||||
export function createCustomersResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(): Promise<CustomerDTO[]> {
|
||||
const res = await client.get<CustomerDTO[]>('/api/customers');
|
||||
async list(pagination?: PaginationParams): Promise<PagedResponse<CustomerDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<CustomerDTO>>('/api/customers', { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import type {
|
|||
RecordCountItemRequest,
|
||||
CancelInventoryCountRequest,
|
||||
InventoryCountStatus,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type { InventoryCountDTO, CreateInventoryCountRequest, RecordCountItemRequest, CancelInventoryCountRequest, InventoryCountStatus };
|
||||
|
|
@ -27,11 +29,14 @@ const BASE = '/api/inventory/inventory-counts';
|
|||
|
||||
export function createInventoryCountsResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(filter?: InventoryCountFilter): Promise<InventoryCountDTO[]> {
|
||||
const params: Record<string, string> = {};
|
||||
async list(filter?: InventoryCountFilter, pagination?: PaginationParams): Promise<PagedResponse<InventoryCountDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (filter?.storageLocationId) params.storageLocationId = filter.storageLocationId;
|
||||
if (filter?.status) params.status = filter.status;
|
||||
const res = await client.get<InventoryCountDTO[]>(BASE, { params });
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<InventoryCountDTO>>(BASE, { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/** Production Orders resource – Production BC. */
|
||||
|
||||
import type { AxiosInstance } from 'axios';
|
||||
import type { ProductionOrderDTO, CreateProductionOrderRequest, RescheduleProductionOrderRequest } from '@effigenix/types';
|
||||
import type { ProductionOrderDTO, CreateProductionOrderRequest, RescheduleProductionOrderRequest, PaginationParams, PagedResponse } from '@effigenix/types';
|
||||
|
||||
export type Priority = 'LOW' | 'NORMAL' | 'HIGH' | 'URGENT';
|
||||
|
||||
|
|
@ -34,12 +34,15 @@ const BASE = '/api/production/production-orders';
|
|||
|
||||
export function createProductionOrdersResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(filter?: ProductionOrderFilter): Promise<ProductionOrderDTO[]> {
|
||||
const params: Record<string, string> = {};
|
||||
async list(filter?: ProductionOrderFilter, pagination?: PaginationParams): Promise<PagedResponse<ProductionOrderDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (filter?.status) params.status = filter.status;
|
||||
if (filter?.dateFrom) params.dateFrom = filter.dateFrom;
|
||||
if (filter?.dateTo) params.dateTo = filter.dateTo;
|
||||
const res = await client.get<ProductionOrderDTO[]>(BASE, { params });
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<ProductionOrderDTO>>(BASE, { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import type {
|
|||
CreateRecipeRequest,
|
||||
AddRecipeIngredientRequest,
|
||||
AddProductionStepRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type RecipeType = 'RAW_MATERIAL' | 'INTERMEDIATE' | 'FINISHED_PRODUCT';
|
||||
|
|
@ -47,10 +49,13 @@ const BASE = '/api/recipes';
|
|||
|
||||
export function createRecipesResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(status?: RecipeStatus): Promise<RecipeSummaryDTO[]> {
|
||||
const params: Record<string, string> = {};
|
||||
async list(status?: RecipeStatus, pagination?: PaginationParams): Promise<PagedResponse<RecipeSummaryDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (status) params['status'] = status;
|
||||
const res = await client.get<RecipeSummaryDTO[]>(BASE, { params });
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<RecipeSummaryDTO>>(BASE, { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -3,15 +3,19 @@
|
|||
*/
|
||||
|
||||
import type { AxiosInstance } from 'axios';
|
||||
import type { RoleDTO } from '@effigenix/types';
|
||||
import type { RoleDTO, PaginationParams, PagedResponse } from '@effigenix/types';
|
||||
import { API_PATHS } from '@effigenix/config';
|
||||
|
||||
export type { RoleDTO };
|
||||
|
||||
export function createRolesResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(): Promise<RoleDTO[]> {
|
||||
const response = await client.get<RoleDTO[]>(API_PATHS.roles.base);
|
||||
async list(pagination?: PaginationParams): Promise<PagedResponse<RoleDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const response = await client.get<PagedResponse<RoleDTO>>(API_PATHS.roles.base, { params });
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/** Stock Movements resource – Inventory BC. */
|
||||
|
||||
import type { AxiosInstance } from 'axios';
|
||||
import type { StockMovementDTO, RecordStockMovementRequest } from '@effigenix/types';
|
||||
import type { StockMovementDTO, RecordStockMovementRequest, PaginationParams, PagedResponse } from '@effigenix/types';
|
||||
|
||||
export type MovementType =
|
||||
| 'GOODS_RECEIPT'
|
||||
|
|
@ -46,15 +46,18 @@ const BASE = '/api/inventory/stock-movements';
|
|||
|
||||
export function createStockMovementsResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(filter?: StockMovementFilter): Promise<StockMovementDTO[]> {
|
||||
const params: Record<string, string> = {};
|
||||
async list(filter?: StockMovementFilter, pagination?: PaginationParams): Promise<PagedResponse<StockMovementDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (filter?.stockId) params.stockId = filter.stockId;
|
||||
if (filter?.articleId) params.articleId = filter.articleId;
|
||||
if (filter?.movementType) params.movementType = filter.movementType;
|
||||
if (filter?.batchReference) params.batchReference = filter.batchReference;
|
||||
if (filter?.from) params.from = filter.from;
|
||||
if (filter?.to) params.to = filter.to;
|
||||
const res = await client.get<StockMovementDTO[]>(BASE, { params });
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<StockMovementDTO>>(BASE, { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import type {
|
|||
BlockStockBatchRequest,
|
||||
ReservationDTO,
|
||||
ReserveStockRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type BatchType = 'PURCHASED' | 'PRODUCED';
|
||||
|
|
@ -71,11 +73,14 @@ const BASE = '/api/inventory/stocks';
|
|||
|
||||
export function createStocksResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(filter?: StockFilter): Promise<StockDTO[]> {
|
||||
const params: Record<string, string> = {};
|
||||
async list(filter?: StockFilter, pagination?: PaginationParams): Promise<PagedResponse<StockDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (filter?.storageLocationId) params.storageLocationId = filter.storageLocationId;
|
||||
if (filter?.articleId) params.articleId = filter.articleId;
|
||||
const res = await client.get<StockDTO[]>(BASE, { params });
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<StockDTO>>(BASE, { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import type {
|
|||
TemperatureRangeDTO,
|
||||
CreateStorageLocationRequest,
|
||||
UpdateStorageLocationRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type StorageType = 'COLD_ROOM' | 'FREEZER' | 'DRY_STORAGE' | 'DISPLAY_COUNTER' | 'PRODUCTION_AREA';
|
||||
|
|
@ -41,11 +43,14 @@ const BASE = '/api/inventory/storage-locations';
|
|||
|
||||
export function createStorageLocationsResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(filter?: StorageLocationFilter): Promise<StorageLocationDTO[]> {
|
||||
const params: Record<string, string> = {};
|
||||
async list(filter?: StorageLocationFilter, pagination?: PaginationParams): Promise<PagedResponse<StorageLocationDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (filter?.storageType) params['storageType'] = filter.storageType;
|
||||
if (filter?.active !== undefined) params['active'] = String(filter.active);
|
||||
const res = await client.get<StorageLocationDTO[]>(BASE, { params });
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<StorageLocationDTO>>(BASE, { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import type {
|
|||
RateSupplierRequest,
|
||||
AddCertificateRequest,
|
||||
RemoveCertificateRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type SupplierStatus = 'ACTIVE' | 'INACTIVE';
|
||||
|
|
@ -44,8 +46,12 @@ export type {
|
|||
|
||||
export function createSuppliersResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(): Promise<SupplierDTO[]> {
|
||||
const res = await client.get<SupplierDTO[]>('/api/suppliers');
|
||||
async list(pagination?: PaginationParams): Promise<PagedResponse<SupplierDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const res = await client.get<PagedResponse<SupplierDTO>>('/api/suppliers', { params });
|
||||
return res.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import type {
|
|||
UpdateUserRequest,
|
||||
ChangePasswordRequest,
|
||||
AssignRoleRequest,
|
||||
PaginationParams,
|
||||
PagedResponse,
|
||||
} from '@effigenix/types';
|
||||
|
||||
export type {
|
||||
|
|
@ -24,8 +26,12 @@ export type {
|
|||
|
||||
export function createUsersResource(client: AxiosInstance) {
|
||||
return {
|
||||
async list(): Promise<UserDTO[]> {
|
||||
const response = await client.get<UserDTO[]>(API_PATHS.users.base);
|
||||
async list(pagination?: PaginationParams): Promise<PagedResponse<UserDTO>> {
|
||||
const params: Record<string, string | string[]> = {};
|
||||
if (pagination?.page != null) params.page = String(pagination.page);
|
||||
if (pagination?.size != null) params.size = String(pagination.size);
|
||||
if (pagination?.sort) params.sort = pagination.sort;
|
||||
const response = await client.get<PagedResponse<UserDTO>>(API_PATHS.users.base, { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue