update generated validation UX and AID integration flow
Improve generated validation behavior and backend error mapping so UI shows user-friendly Russian messages, while keeping filtering/sorting and exporter updates aligned with current app generation flow.
This commit is contained in:
@@ -1,7 +1,96 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
BadRequestException,
|
||||
ValidationError,
|
||||
ValidationPipe,
|
||||
} from '@nestjs/common';
|
||||
import { AppModule } from './app.module';
|
||||
import { RuntimeEnvironment } from './config/env.validation';
|
||||
import { ApiExceptionFilter } from './common/filters/api-exception.filter';
|
||||
|
||||
const FIELD_LABELS: Record<string, string> = {
|
||||
code: 'Код',
|
||||
name: 'Название',
|
||||
manufacturer: 'Производитель',
|
||||
maintenanceIntervalHours: 'Интервал ТО (часы)',
|
||||
overhaulIntervalHours: 'Интервал капремонта (часы)',
|
||||
inventoryNumber: 'Инвентарный номер',
|
||||
serialNumber: 'Серийный номер',
|
||||
equipmentTypeCode: 'Тип оборудования',
|
||||
equipmentId: 'Оборудование',
|
||||
status: 'Статус',
|
||||
location: 'Местоположение',
|
||||
commissionedAt: 'Дата ввода в эксплуатацию',
|
||||
totalEngineHours: 'Наработка общая',
|
||||
engineHoursSinceLastRepair: 'Наработка после ремонта',
|
||||
lastRepairAt: 'Дата последнего ремонта',
|
||||
notes: 'Примечание',
|
||||
number: 'Номер',
|
||||
repairKind: 'Вид ремонта',
|
||||
plannedAt: 'Плановая дата',
|
||||
startedAt: 'Дата начала',
|
||||
completedAt: 'Дата завершения',
|
||||
contractor: 'Подрядчик',
|
||||
engineHoursAtRepair: 'Наработка на момент ремонта',
|
||||
description: 'Описание',
|
||||
id: 'Идентификатор',
|
||||
};
|
||||
|
||||
function prettifyFieldName(field: string): string {
|
||||
if (FIELD_LABELS[field]) return FIELD_LABELS[field];
|
||||
const withSpaces = field
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
||||
.replace(/_/g, ' ')
|
||||
.trim();
|
||||
if (!withSpaces) return field;
|
||||
return withSpaces[0].toUpperCase() + withSpaces.slice(1);
|
||||
}
|
||||
|
||||
function constraintToRuMessage(field: string, constraint: string): string {
|
||||
const label = prettifyFieldName(field);
|
||||
switch (constraint) {
|
||||
case 'isNotEmpty':
|
||||
return `Поле "${label}" обязательно`;
|
||||
case 'isString':
|
||||
return `Поле "${label}" должно быть строкой`;
|
||||
case 'isInt':
|
||||
return `Поле "${label}" должно быть целым числом`;
|
||||
case 'isUUID':
|
||||
return `Поле "${label}" должно быть UUID`;
|
||||
case 'isNumberString':
|
||||
return `Поле "${label}" должно быть числом`;
|
||||
case 'isIso8601':
|
||||
return `Поле "${label}" должно содержать корректную дату`;
|
||||
case 'isEnum':
|
||||
return `Поле "${label}" содержит недопустимое значение`;
|
||||
default:
|
||||
return `Поле "${label}" заполнено некорректно`;
|
||||
}
|
||||
}
|
||||
|
||||
function buildValidationMessages(errors: ValidationError[]): string[] {
|
||||
const messages: string[] = [];
|
||||
|
||||
const walk = (errorList: ValidationError[]) => {
|
||||
for (const error of errorList) {
|
||||
if (error.constraints) {
|
||||
const constraints = Object.keys(error.constraints);
|
||||
// If field is empty, "required" is enough; skip type noise.
|
||||
const filtered = constraints.includes('isNotEmpty')
|
||||
? ['isNotEmpty']
|
||||
: constraints;
|
||||
filtered.forEach((constraint) =>
|
||||
messages.push(constraintToRuMessage(error.property, constraint)),
|
||||
);
|
||||
}
|
||||
if (error.children?.length) walk(error.children);
|
||||
}
|
||||
};
|
||||
|
||||
walk(errors);
|
||||
return Array.from(new Set(messages));
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
@@ -29,6 +118,17 @@ async function bootstrap() {
|
||||
credentials: false,
|
||||
});
|
||||
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
transform: true,
|
||||
whitelist: true,
|
||||
forbidUnknownValues: false,
|
||||
exceptionFactory: (errors) =>
|
||||
new BadRequestException(buildValidationMessages(errors)),
|
||||
}),
|
||||
);
|
||||
app.useGlobalFilters(new ApiExceptionFilter());
|
||||
|
||||
const port = configService.get('PORT', 3000);
|
||||
await app.listen(port);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user