feat(records): bulk close — multi-select toolbar + per-record транзакция

Backend POST /api/v1/dictionaries/{name}/records/bulk-close принимает
businessKeys[] (1..500) + reason. BulkRecordService крутит цикл через
inject'ed DictionaryRecordService — каждый close в своей транзакции
(SERIALIZABLE), partial success возможен. Result: closed[] / skipped[]
(already_closed, not_found) / errors[].

Frontend: checkbox column + sticky toolbar когда selection.size > 0.
Header checkbox с indeterminate state для partial select. selectAll
включает все ВИДИМЫЕ ключи (не игнорирует фильтры). При изменении
фильтра — useEffect выкидывает невидимые ключи из selection (WYSIWYG).

Bulk close dialog: count + reason input → confirm → результат панель
"Закрыто N, пропущено M, ошибок K" с детальным списком skipped/errors.
После успеха selection остаётся для skipped/errors — юзер видит что
ещё не сделано.

Лимит 500: защита от случайного огромного селекта или бага UI.
Дедупликация внутри batch'а silent skip — не error.
This commit is contained in:
Zimin A.N.
2026-05-07 11:19:57 +03:00
parent 92507ab0a1
commit 5941207955
8 changed files with 526 additions and 23 deletions
+12
View File
@@ -113,6 +113,18 @@ export type CreateRecordRequest = {
validTo?: string
}
export type BulkCloseRequest = {
businessKeys: string[]
at?: string
reason?: string
}
export type BulkCloseResponse = {
closed: string[]
skipped: { businessKey: string; reason: string }[]
errors: { businessKey: string; reason: string }[]
}
export type AuditAction = 'CREATE' | 'UPDATE' | 'CLOSE'
export type AuditEntry = {