mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
paginate wagons, locomotives and routes lists server-side
This commit is contained in:
@@ -72,16 +72,7 @@ export class ListWagonsQueryDto {
|
|||||||
@Min(1)
|
@Min(1)
|
||||||
page?: number;
|
page?: number;
|
||||||
|
|
||||||
@ApiPropertyOptional({ minimum: 1, maximum: 500 })
|
@ApiPropertyOptional({ default: 10, minimum: 1, maximum: 100 })
|
||||||
@IsOptional()
|
|
||||||
@Type(() => Number)
|
|
||||||
@IsInt()
|
|
||||||
@Min(1)
|
|
||||||
@Max(500)
|
|
||||||
limit?: number;
|
|
||||||
|
|
||||||
/** Page size for `GET /wagons/paged`; the legacy `limit` still drives `GET /wagons`. */
|
|
||||||
@ApiPropertyOptional({ default: 20, minimum: 1, maximum: 100 })
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Type(() => Number)
|
@Type(() => Number)
|
||||||
@IsInt()
|
@IsInt()
|
||||||
|
|||||||
@@ -39,19 +39,13 @@ export class WagonsController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@StaffReference()
|
@StaffReference()
|
||||||
@ApiOperation({ summary: 'List all wagons' })
|
@ApiOperation({
|
||||||
|
summary: 'List wagons, paginated ({items, meta}) — 10 per page by default',
|
||||||
|
})
|
||||||
findAll(@Query() query: ListWagonsQueryDto) {
|
findAll(@Query() query: ListWagonsQueryDto) {
|
||||||
return this.wagonsService.findAll(query);
|
return this.wagonsService.findAll(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be declared before @Get(':id') so the path isn't captured as an id.
|
|
||||||
@Get('paged')
|
|
||||||
@StaffReference()
|
|
||||||
@ApiOperation({ summary: 'List wagons, paginated ({items, meta})' })
|
|
||||||
findAllPaged(@Query() query: ListWagonsQueryDto) {
|
|
||||||
return this.wagonsService.findAllPaged(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
@StaffReference()
|
@StaffReference()
|
||||||
@ApiOperation({ summary: 'Get a wagon by ID' })
|
@ApiOperation({ summary: 'Get a wagon by ID' })
|
||||||
|
|||||||
@@ -115,20 +115,13 @@ export class WagonsService {
|
|||||||
return qb;
|
return qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(query: ListWagonsQueryDto = {}): Promise<Wagon[]> {
|
/**
|
||||||
const qb = this.buildListQuery(query);
|
* The wagon list is always a page. Callers that genuinely need every row
|
||||||
|
* (yard workspace, coupling pickers) walk the pages client-side — see
|
||||||
if (query.page && query.limit) {
|
* `wagonService.listAll` in the backoffice.
|
||||||
qb.skip((Number(query.page) - 1) * Number(query.limit));
|
*/
|
||||||
}
|
findAll(query: ListWagonsQueryDto = {}): Promise<PaginatedResponse<Wagon>> {
|
||||||
if (query.limit) qb.take(Number(query.limit));
|
return paginateQuery(this.buildListQuery(query), query, { defaultPageSize: 10 });
|
||||||
|
|
||||||
return qb.getMany();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Same filters as `findAll`, on the shared `{items, meta}` list envelope. */
|
|
||||||
findAllPaged(query: ListWagonsQueryDto = {}): Promise<PaginatedResponse<Wagon>> {
|
|
||||||
return paginateQuery(this.buildListQuery(query), query);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findById(id: string): Promise<Wagon> {
|
async findById(id: string): Promise<Wagon> {
|
||||||
|
|||||||
@@ -155,9 +155,15 @@ const FleetResourcePage = () => {
|
|||||||
const { data: cargoTypes = [], isLoading: cargoTypesLoading } = useQuery(
|
const { data: cargoTypes = [], isLoading: cargoTypesLoading } = useQuery(
|
||||||
api.cargoTypes.list.queryOptions({ staleTime: Infinity }),
|
api.cargoTypes.list.queryOptions({ staleTime: Infinity }),
|
||||||
);
|
);
|
||||||
const { data: wagons = [], isLoading: wagonsLoading } = useQuery(
|
// Whole-fleet list for the "Wagon" form select — page-walked, so only fetch it
|
||||||
api.wagons.list.queryOptions({ input: {} }),
|
// where a form actually offers that select (containers), not on every slug.
|
||||||
|
const needsWagonOptions = Boolean(
|
||||||
|
config?.formFields.some((field) => field.dynamicOptions === "wagons"),
|
||||||
);
|
);
|
||||||
|
const { data: wagons = [], isLoading: wagonsLoading } = useQuery({
|
||||||
|
...api.wagons.list.queryOptions({ input: {} }),
|
||||||
|
enabled: needsWagonOptions,
|
||||||
|
});
|
||||||
const { data: containers = [], isLoading: containersLoading } = useQuery(
|
const { data: containers = [], isLoading: containersLoading } = useQuery(
|
||||||
api.containers.list.queryOptions(),
|
api.containers.list.queryOptions(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1632,17 +1632,25 @@ export const api = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
wagons: {
|
wagons: {
|
||||||
|
/** Every match, page-walked — for pickers and yard views. Lists use `listPaged`. */
|
||||||
list: endpoint<{ filters?: WagonListFilters }, Wagon[]>(
|
list: endpoint<{ filters?: WagonListFilters }, Wagon[]>(
|
||||||
"wagons",
|
"wagons",
|
||||||
"list",
|
"list",
|
||||||
({ filters }) => wagonService.getAll(filters ?? {}).then((r) => r.data),
|
({ filters }) => wagonService.listAll(filters ?? {}),
|
||||||
({ filters }) => ["wagons", "list", filters ?? {}],
|
({ filters }) => ["wagons", "list", filters ?? {}],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
listPaged: endpoint<{ filters?: WagonListFilters }, PaginatedResponse<Wagon>>(
|
||||||
|
"wagons",
|
||||||
|
"listPaged",
|
||||||
|
({ filters }) => wagonService.getAll(filters ?? {}).then((r) => r.data),
|
||||||
|
({ filters }) => ["wagons", "listPaged", filters ?? {}],
|
||||||
|
),
|
||||||
|
|
||||||
listByTrain: endpoint<{ trainId: string }, Wagon[]>(
|
listByTrain: endpoint<{ trainId: string }, Wagon[]>(
|
||||||
"wagons",
|
"wagons",
|
||||||
"listByTrain",
|
"listByTrain",
|
||||||
({ trainId }) => wagonService.getByTrain(trainId).then((r) => r.data),
|
({ trainId }) => wagonService.getByTrain(trainId),
|
||||||
({ trainId }) => ["wagons", "train", trainId],
|
({ trainId }) => ["wagons", "train", trainId],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const listHandlers: Record<
|
|||||||
> = {
|
> = {
|
||||||
locomotives: (filters) => locomotivesService.getAll(filters ?? {}).then((r) => r.data),
|
locomotives: (filters) => locomotivesService.getAll(filters ?? {}).then((r) => r.data),
|
||||||
trains: () => trainService.getAll().then((r) => r.data),
|
trains: () => trainService.getAll().then((r) => r.data),
|
||||||
wagons: (filters) => wagonService.getAll(filters ?? {}).then((r) => r.data),
|
wagons: (filters) => wagonService.listAll(filters ?? {}),
|
||||||
containers: () => containerService.getAll().then((r) => r.data),
|
containers: () => containerService.getAll().then((r) => r.data),
|
||||||
cargoes: () => cargoService.getAll().then((r) => r.data),
|
cargoes: () => cargoService.getAll().then((r) => r.data),
|
||||||
vehicles: (filters) => vehiclesService.getAll(filters ?? {}).then((r) => r.data),
|
vehicles: (filters) => vehiclesService.getAll(filters ?? {}).then((r) => r.data),
|
||||||
@@ -38,7 +38,7 @@ const pagedHandlers: Partial<
|
|||||||
Record<FleetResourceSlug, (filters: FleetListFilters) => Promise<PaginatedResponse<FleetRecord>>>
|
Record<FleetResourceSlug, (filters: FleetListFilters) => Promise<PaginatedResponse<FleetRecord>>>
|
||||||
> = {
|
> = {
|
||||||
locomotives: (filters) => locomotivesService.getPaged(filters).then((r) => r.data),
|
locomotives: (filters) => locomotivesService.getPaged(filters).then((r) => r.data),
|
||||||
wagons: (filters) => wagonService.getPaged(filters).then((r) => r.data),
|
wagons: (filters) => wagonService.getAll(filters).then((r) => r.data),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isFleetServerPaginated = (slug: FleetResourceSlug): boolean =>
|
export const isFleetServerPaginated = (slug: FleetResourceSlug): boolean =>
|
||||||
|
|||||||
@@ -95,15 +95,28 @@ export interface WagonMovementRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const wagonService = {
|
export const wagonService = {
|
||||||
|
/** One page ({items, meta}); 10 rows unless `pageSize` says otherwise. */
|
||||||
getAll: (filters: WagonListFilters = {}) =>
|
getAll: (filters: WagonListFilters = {}) =>
|
||||||
apiClient.get<Wagon[]>(`/wagons${wagonListQuery(filters)}`),
|
apiClient.get<PaginatedResponse<Wagon>>(`/wagons${wagonListQuery(filters)}`),
|
||||||
/** Same filters as `getAll`, server-paginated ({items, meta}). */
|
/**
|
||||||
getPaged: (filters: WagonListFilters = {}) =>
|
* Every matching wagon, page-walked at the API's 100-row cap. For the pickers
|
||||||
apiClient.get<PaginatedResponse<Wagon>>(`/wagons/paged${wagonListQuery(filters)}`),
|
* and yard views that filter the whole fleet in the browser — a list page
|
||||||
|
* should use `getAll` and show the real page controls instead.
|
||||||
|
*/
|
||||||
|
listAll: async (filters: WagonListFilters = {}): Promise<Wagon[]> => {
|
||||||
|
const pageSize = 100;
|
||||||
|
const first = await wagonService.getAll({ ...filters, page: 1, pageSize });
|
||||||
|
const items = [...first.data.items];
|
||||||
|
for (let page = 2; page <= (first.data.meta.totalPages ?? 1); page += 1) {
|
||||||
|
const next = await wagonService.getAll({ ...filters, page, pageSize });
|
||||||
|
items.push(...next.data.items);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
},
|
||||||
getById: (id: string) => apiClient.get<Wagon>(`/wagons/${id}`),
|
getById: (id: string) => apiClient.get<Wagon>(`/wagons/${id}`),
|
||||||
getMovements: (id: string) =>
|
getMovements: (id: string) =>
|
||||||
apiClient.get<WagonMovementRecord[]>(`/wagons/${id}/movements`),
|
apiClient.get<WagonMovementRecord[]>(`/wagons/${id}/movements`),
|
||||||
getByTrain: (trainId: string) => apiClient.get<Wagon[]>(`/wagons?trainId=${trainId}`),
|
getByTrain: (trainId: string) => wagonService.listAll({ trainId }),
|
||||||
assignToTrain: (wagonId: string, trainId: string, sequenceNumber?: number) =>
|
assignToTrain: (wagonId: string, trainId: string, sequenceNumber?: number) =>
|
||||||
apiClient.post(`/wagons/${wagonId}/assign-train`, { trainId, sequenceNumber }),
|
apiClient.post(`/wagons/${wagonId}/assign-train`, { trainId, sequenceNumber }),
|
||||||
unassign: (wagonId: string) => apiClient.post(`/wagons/${wagonId}/unassign-train`),
|
unassign: (wagonId: string) => apiClient.post(`/wagons/${wagonId}/unassign-train`),
|
||||||
|
|||||||
Reference in New Issue
Block a user