feat(admin-ui): D-pack — history, breaking-change detection, x-unique, x-id-source, datetime

History:
- Drawer на детальной странице записи (timeline всех версий через GET /records/{key}/history)
- Иконка ClockCounterClockwise в actions колонке таблицы записей
- Каждая версия показывает v(version), validFrom/To, updatedBy + expand JSON

Schema diff (breaking detection):
- Util diffSchemas() сравнивает старую/новую схему и классифицирует изменения:
  breaking (removed/typeChanged/becameRequired/enumRemoved/maxLengthTightened/
  patternChanged/newRequiredField), compatible (added optional/enumAdded/
  becameOptional), metadata (description)
- В DictionaryEditorDialog при breaking → Alert с детальным списком + Save заблокирован
- При compatible → Alert info со списком
- suggestVersionBump: major для breaking, minor для compatible field changes,
  patch для metadata-only

x-unique:
- Чекбокс «Уникальное» на PropertyEditor → emit x-unique: true в schema
- Backend enforcement позже — отдельный PR с partial unique index

x-id-source:
- SingleSelect в Метаданных «Использовать как ID» → emit x-id-source на schema root
- В SchemaDrivenForm если установлен — businessKey input скрывается, на submit
  derived из data[idSource]
- Подсказка с именем поля

DateTime для validFrom/validTo:
- Заменил DatePicker (date-only) на DateTimeField компонент: DatePicker + TextInput
  type=time рядом
- Default time: validFrom=00:00, validTo=23:59 (запись действует до конца дня
  иначе зануляется в полночь)
- Поддерживает 2-часовые интервалы (запуск КА в 14:30 → сход в 02:15 etc.)

Bug fix:
- parseSchemaJson изменил сигнатуру с PropertyDef[] на {properties, idSource},
  старый код в DictionaryEditorDialog падал "{} is not iterable". Поправлено
  через destructuring const parsed = parseSchemaJson(...).

i18n: 25+ новых ключей (RU/EN) — schema.unique, schema.idSource, schema.diff.*,
history.*, form.idSourceNote.
This commit is contained in:
Zimin A.N.
2026-05-04 03:38:21 +03:00
parent 0289cf5ff2
commit baf76ac6e0
5 changed files with 221 additions and 35 deletions
@@ -87,11 +87,19 @@ export const PropertyEditor = ({
/>
</div>
<Checkbox
label={t('schema.required')}
checked={prop.required}
onChange={(e) => update({ required: e.target.checked })}
/>
<div className="flex flex-wrap gap-4">
<Checkbox
label={t('schema.required')}
checked={prop.required}
onChange={(e) => update({ required: e.target.checked })}
/>
<Checkbox
label={t('schema.unique')}
description={t('schema.uniqueHint')}
checked={prop.unique}
onChange={(e) => update({ unique: e.target.checked })}
/>
</div>
<TextArea
label={t('schema.description')}