Commit Graph

343 Commits

Author SHA1 Message Date
Александр Зимин b39e0500de Merge branch 'feat/editor-tabs-redesign' into 'main'
feat(editor): Fields / Events / History tabs match redesign prototype

See merge request 2-6/2-6-4/terravault/ordinis!77
2026-05-11 16:21:17 +00:00
Zimin A.N. cbe21dbc52 feat(editor): Fields / Events / History tabs match redesign prototype
Per redesign/screens/{05-fields,07-events,08-history}.png:

Fields tab (Поля):
- # numbered col (01, 02, ...) — mono mute, tabular-nums
- ПОЛЕ — bold accent (was plain mono)
- ТИП — inline FK render: `fk → target_dict`, array as `string[]`,
  date/date-time format names, enum, native types
- REQUIRED / UNIQUE / I18N / INDEX — checkmark (green) or — dash
- INDEX heuristic: x-unique || x-references → indexed (backend doesn't
  expose explicit flag yet)
- ОПИСАНИЕ truncate с max-w-[320px]

Events tab (События):
- Filter chips above table: все N / webhooks / publish / review / edit /
  export (только показываем те которые есть, кроме «все»)
- "Полный лог →" link справа в chips row
- Table cols: Время (5 sec precision) / Тип (colored chip) / Статус
  (● dot + ok/fail) / Куда·Кто (user) / Сообщение (businessKey · action)
- Type chips colored: webhook=accent, publish=green, review=warn,
  export=surface-2, edit=accent-bg/50

History tab (История):
- HEAD row: ● filled dot + v{version} + HEAD chip (dark) + change summary
  (+N ~0 −0 placeholder until backend changelog endpoint появится)
- Description + updatedAt date
- Backend-pending notice card: "/api/v1/dictionaries/{name}/changelog pending"

Plus: + import { cn } from '@/lib/utils' для новых tabs
2026-05-11 19:20:57 +03:00
Александр Зимин a0b10e50ec Merge branch 'feat/conflict-diff-modal' into 'main'
feat(record): conflict diff modal на 409 save

See merge request 2-6/2-6-4/terravault/ordinis!76
2026-05-11 16:13:57 +00:00
Zimin A.N. 16da694d8c feat(record): conflict diff modal на 409 save (handoff line 444)
Когда PUT /records/{key} возвращает 409 (optimistic-lock fail — другой
пользователь сохранил тот же record между нашим load и submit'ом),
открываем ConflictDiffModal.

Component:
- Header: 'Конфликт сохранения · {DICT}' + business key
- Diff body: refetch server state via useRecordRaw, иди по union ключей
  local + server, оставь только отличающиеся. Per-row: field name (mono)
  + ваше значение (accent-bg) + серверное (surface-2)
- Footer 3 actions:
  - Отмена: close, оставить editor open
  - Загрузить серверное: discard local, refetch records, close editor
  - Перезаписать: re-submit current payload (если опять 409 → новый diff)
- Backend-friendly: не требует server diff endpoint, client считает diff
  client-side через JSON.stringify equality

Route wiring:
- onError handler distinguishes generic 409 (open diff modal) от
  специальных кодов: x_references_blocked_by_dependents,
  x_references_cascade_required, draft_required — те идут в свои dialogs
- Conflict state ({payload, businessKey}) capture'ит local data чтобы
  показать в diff даже после reset формы
2026-05-11 19:13:30 +03:00
semantic-release-bot 258ba50d3e chore(release): v1.3.0 [skip ci]
## [1.3.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v1.2.2...v1.3.0) (2026-05-11)

###  Features

* **admin-ui:** editor 6-tab layout (Stage 3.4) ([640c890](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/640c890d0bb35117ee32420f11d4960c24aeabb8))
* **admin-ui:** editor 6-tab layout (Stage 3.4) ([0ddba87](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/0ddba871f7cbc62ac49a72144cfc9c98dfc861d4))
* **catalog:** row-based table per handoff prototype design/compact.html ([f43ce55](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/f43ce5563a7f6ddffb494b1879247c4c582b4567)), closes [#2](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/2)
* **drawer:** all-sections layout с chips strip per handoff prototype ([155c70e](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/155c70e23cc0e38deb10953c176ff3835712f415)), closes [#5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/5)
* **drawer:** sticky toolbar API per handoff Screen 3 line 279 ([d4000dd](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/d4000ddd3d93facfeb4f61270f132cf5fe16974c)), closes [#5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/5)
* **editor:** + Экспорт button в InfoPanel per redesign dark theme screenshot ([e15a391](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/e15a3916bfcd89f61cc63ea5f5472474bad98f9b))
* **editor:** ExportModal + TimeTravelModal + InfoPanel merge + fixes ([5a2220d](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/5a2220d77966efff26ddac12b2d408cdf5696f5f)), closes [#fbf8ee](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/fbf8ee) [#faf9f5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/faf9f5)
* **editor:** keyboard shortcuts j/k/Enter/n per handoff Screen 2 ([a09c411](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/a09c4113c1b8331590cc2e368dec680bcb4d1e04))
* **editor:** left info panel + 3-col layout per handoff prototype ([a57cf52](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/a57cf520a428b5d72966818967327fa714f05728))
* **editor:** match redesign prototype layout — TopBar title + tab counts + InfoPanel actions ([ec99010](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/ec99010697e8a2687d99ee01e2dc4751a62a8346))
* **editor:** Stage 3.4 polish — Events embedded + JSON syntax highlight ([f0392af](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/f0392af0e37a06f784cb18558f8fb79c1b8bce24))
* **handoff:** WorkflowBanner + table a11y + responsive + toast styling ([0acba4c](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/0acba4c073507951b9dbdd191ff0a4ad0ed8252a))
* **mobile:** Sidebar drawer <1024px + Modal/Sheet fullscreen <880px ([7a3b31b](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/7a3b31b9578ef280e25c88f2657a62bf7272f216))
* **record:** RecordDrawer slide-over per Stage 3.5 handoff (Phase A) ([750395d](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/750395da09dc11a4048744417933864df147708d)), closes [#5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/5)
* **sidebar:** desktop collapse mode 220px → 56px per handoff prototype ([69a86b2](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/69a86b238c3baa2c6cf44f8d6b9a15bcc59664b5))
* **theme:** sync color tokens с redesign ui-kit + add claude-light theme ([42dab24](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/42dab24d964533d6ce600e5d5c73f6ff2b8e87ce)), closes [#fbf8ee](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/fbf8ee) [#d4a07a](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/d4a07a) [#faf9f5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/faf9f5) [#d97757](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/d97757)
* **ui:** drop @nstart/ui dependency (Stage 3.9) ([5007e0f](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/5007e0f4eb730454c9883942fa3c59c6416f0637))
* wire drawer toolbar filters + records table responsive hiding ([889207f](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/889207f62901820fcb3e908fd576cd0878013945))

### 🐛 Fixes

* **admin-ui:** sidebar font sizes per handoff spec ([f72aac6](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/f72aac63986e3ba30717139f852ebbf5fe26bc23))
* **admin-ui:** sidebar fonts per handoff ([0297745](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/0297745d139ae7ebb9076c61e83d6a2d53a6e275))
* **admin-ui:** UpdateBanner generic message ([dc0002f](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/dc0002f379f96e7d22746f3fc2b87e7b456475f5))
* **fonts:** align all text sizes to handoff spec via Tailwind theme overrides ([71432e9](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/71432e9ae7006bad3bc38cf89ce82c6596e07c81))
* **fonts:** explicit font-family on title utilities + cascade conflicts ([f0dbc20](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/f0dbc20f62c7b3b0c9f0150247fb3b14007f267d))
* **fonts:** semantic typography utilities per handoff (7 roles) ([b949127](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/b94912789f7d7be93def334aeb3377dd0dad409d))
* **release:** drop invalid tarballDir: [secure] config ([090bff5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/090bff56ce2aa9153617dc11a623005fa0c88918))
* **table+layout:** TableHead alias to THEAD wrapper + kill horizontal scroll ([787cea9](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/787cea9db172b3f111c357129af45183ce461efa))
* **theme:** de-saturate light bg — убрать жёлтый Earth-cream tone ([e5572d5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/e5572d534640953f86fed7eecefe0210d49c3925)), closes [#fbf8ee](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/fbf8ee) [#fbf8ee](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/fbf8ee) [#fafaf8](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/fafaf8) [#f4eedc](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/f4eedc) [#f2f1ee](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/f2f1ee) [#e3dccb](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/e3dccb) [#e4e1dc](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/e4e1dc) [#efe9d8](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/efe9d8) [#ecebe7](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/ecebe7) [#b05a2e](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/b05a2e) [#3a2818](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/3a2818)
* **ui:** 3 user-reported issues ([abdfaa8](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/abdfaa8fcc2da6fba8bab6d73f43498e4f77f5a5))
* **ui:** tailwind-merge стрипал text-body — buttons ушли в 16px inherited ([9e2d985](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/9e2d985485f60f8333ed5d81de7cd6bcd5009bad))
* **version:** bump to 1.3.1 and show 8-char commit hash ([780de70](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/780de70fc5cf91c3904a8dc417a09514e3ddf584))
* **version:** channel-based label, no semver fallback for branch builds ([3223a5c](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/3223a5ced74956efa85cf1a9d4be0d51a17b2297))
* **version:** detect CI build via CI_COMMIT_SHORT_SHA, not process.env.CI ([b6af155](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/b6af155da256a395db6757c911e1e3e3c50cac9a))
* **version:** read CI_COMMIT_TAG as source of truth, package.json as fallback ([e62633d](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/e62633d903c063540d521c4b063795aade1b6a14))

###  Reverts

* **timetravel:** keep 'Time-travel…' label ([36fb70f](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/36fb70fc00a62f93687142293c318b231b915a07))
2026-05-11 16:11:52 +00:00
Zimin A.N. ad7c51d93f feat(catalog): toolbar layout per redesign prototype
Match handoff screenshot:
- Title "Справочники" + inline "N шт." count caption (no description text)
- Remove page-level SearchInput (TopBar already has global search ⌘K)
- Reorder toolbar to single row:
  [scope pills PUBLIC|INTERNAL|RESTRICTED]
  | divider |
  [bundle pills все|cuod|geo|i18n|core]
  | spacer |
  N/M counter
  [Граф ⇄] (→ /graph)
  [+ Создать] (moved here from PageHeader actions)
- Scope/bundle pills are bordered chips с ring-1 для active state
- Drop deps-only toggle (not in redesign)
- Drop scopeCounts useMemo (counts moved out of chip labels per design)
2026-05-11 19:09:39 +03:00
Александр Зимин 38ca8b7f65 Merge branch 'feat/info-panel-export-button' into 'main'
feat(editor): ExportModal + TimeTravelModal + InfoPanel merge + critical fixes

See merge request 2-6/2-6-4/terravault/ordinis!74
2026-05-11 16:02:34 +00:00
Zimin A.N. 5a2220d779 feat(editor): ExportModal + TimeTravelModal + InfoPanel merge + fixes
UI redesign matching prototype (Ordinis (3) dump):
- ExportModal: format (CSV/JSON/Excel/SQL) + scope (all/filtered/selected) +
  column toggles + encoding/delimiter + preview filename per redesign line
  1059-1092. CSV uses backend mutation, JSON client-side from filtered rows,
  Excel/SQL disabled (backend pending).
- TimeTravelModal: full-page compare СЕЙЧАС vs ТОЧКА ВО ВРЕМЕНИ + quick
  presets (сейчас/неделя/месяц/год/при создании) + step toggle версия/день
  + slider + tabs (Что изменилось / Записи на момент / Структура и поля) +
  "Открыть как readonly" CTA. Replaces inline TimeTravelPicker.
- InfoPanel ← используют merge: rich rows с field path + active records
  count + onClose policy chip (BLOCK/WARN/CASCADE). Inline
  DictionaryDependentsPanel above records table removed (one source of truth).
- Sidebar logo: match redesign/ui-kit.html .brand SVG (outer ring + inner
  faded ring + orbit dot offset right cx=22.5). ORDINIS Tektur tracking 0.22em
  + MDM smaller mute 0.32em.
- Bg neutralized: #fbf8ee Earth cream → #faf9f5 warm neutral default
  (per user preference, Earth cream still described in comment как opt-in).
- WorkflowBanner: Case 1 Live (approvalRequired=false) returns null —
  permanent "Опубликовано" banner = noise, status already visible в
  InfoPanel scope/version/updatedAt. Banner показывается только когда
  есть actionable state.

Critical bug fixes:
- fix(CascadeConfirmDialog): infinite render loop "Maximum update depth
  exceeded". useEffect had cascadeMut (TanStack Query mutation wrapper) в
  deps — wrapper identity changes every render → effect fires → reset() →
  store update → render → loop. Extract stable `reset` reference перед
  useEffect. Симптомы у user: создание/редактирование записи не работали.
- fix(semantic-release): add missing peer dep
  conventional-changelog-conventionalcommits (9.3.1). semantic-release 22+
  больше не bundles preset. Без неё release job падал с
  "Cannot find module 'conventional-changelog-conventionalcommits'".
2026-05-11 19:01:57 +03:00
Александр Зимин ac6812225b Merge branch 'feat/info-panel-export-button' into 'main'
feat(editor): Export button в InfoPanel per redesign

See merge request 2-6/2-6-4/terravault/ordinis!73
2026-05-11 15:04:01 +00:00
Zimin A.N. e15a3916bf feat(editor): + Экспорт button в InfoPanel per redesign dark theme screenshot
User dropped /Users/zimin/Downloads/Ordinis (3) — full project dump.
Dark theme editor screenshot (uploads/draw-4b771386...png) показывает
INFO PANEL c двумя buttons:
  - ↓ Экспорт…
  - ⟲ Time-travel…

У нас был Time-travel + AOI — добавил Экспорт как third button.

Implementation:
  - EditorInfoPanel.actions.onExport + exportPending props
  - DownloadSimpleIcon кнопка 'Экспорт…'
  - Wired к useBulkExportRecords mutation:
    * Selection не empty -> export selected
    * Selection empty -> export all filtered records
  - disabled когда mutation pending, label 'Экспорт…'

Project dump reviewed:
  - design_handoff_dictionary_catalog — старый handoff, всё уже реализовано
    (List view MR !62, Hub MR earlier, Graph earlier)
  - patches/ — @nstart/ui patches, moot (мы dropped @nstart/ui MR !52)
  - redesign/ — уже синхронизированы colors MR !71, layout MR !69
  - uploads/ — user-provided screenshots, main delta = Export button
2026-05-11 18:03:52 +03:00
Александр Зимин c3dcbcfbb7 Merge branch 'fix/timetravel-label-revert' into 'main'
revert(timetravel): keep 'Time-travel…' label

See merge request 2-6/2-6-4/terravault/ordinis!72
2026-05-11 14:56:46 +00:00
Zimin A.N. 36fb70fc00 revert(timetravel): keep 'Time-travel…' label
User feedback: 'Time-travel label такое себе Time-travel… оставь'.
Reverting MR !70 part of rename ('Таймлайн' → 'Time-travel…').

Per handoff prototype line 299 это и был 'Time-travel…' изначально —
надо было не трогать.
2026-05-11 17:56:38 +03:00
Александр Зимин 8bc7eef703 Merge branch 'feat/colors-sync-redesign' into 'main'
feat(theme): sync color tokens с redesign + claude-light theme

See merge request 2-6/2-6-4/terravault/ordinis!71
2026-05-11 14:53:54 +00:00
Zimin A.N. 42dab24d96 feat(theme): sync color tokens с redesign ui-kit + add claude-light theme
Reverted MR !66 de-yellow — turns out redesign prototype intentionally
использует жёлтый Earth cream (#fbf8ee) как primary bg. User confusion
was с предыдущим build'ом до MR !66, в ui-kit все таки cream.

Added tokens per redesign/ui-kit.html prototype:

Scope tints:
  --bg-public, --bg-internal, --bg-tenant (для scope chip backgrounds)
Workflow states:
  --bg-draft, --bg-live, --bg-deprec (для workflow banner backgrounds)
Alert variants:
  --al-info-bg/bd, --al-warn-bg/bd, --al-err-bg/bd, --al-ok-bg/bd
Shadows:
  --shadow-l, --shadow-m, --shadow-toast, --shadow-drawer (consistent)
Toast cap color:
  --toast-cap #d4a07a (orange-cream per handoff Screen 4)
Avatars:
  --avt-pink-bg, --avt-green-bg (semantic state avatar backgrounds)
Purple:
  --color-purple для future use

New theme '[data-theme=claude-light]':
  Warm cream neutral (#faf9f5) — для users которые не любят saturated Earth.
  Accent navy → coral orange (#d97757) per Claude branding.
  Full token set включая scope/workflow/alert variants.

Dark theme получил те же дополнительные tokens (bg-public/internal/tenant,
al-info-bg/bd, shadows, toast-cap, avt-bg) — consistency с light tier.

User может через ThemeSwitch / manual data-theme attr выбрать:
  default     — Earth cream (handoff design intent)
  claude-light — neutral warm
  dark        — Claude-style dark

Bundle: +~1KB CSS. Tests: 116 pass.
2026-05-11 17:53:45 +03:00
Александр Зимин c7d2c0cc29 Merge branch 'fix/dialog-position-logo-timeline' into 'main'
fix(ui): dialog off-screen + logo MDM + timeline label

See merge request 2-6/2-6-4/terravault/ordinis!70
2026-05-11 14:50:05 +00:00
Zimin A.N. abdfaa8fcc fix(ui): 3 user-reported issues
1) MODAL OFF-SCREEN (Schema/AOI/Confirm dialogs)
DialogContent had `inset-0 w-full h-full` + `min-[880px]:inset-auto`
конфликтовал — inset-0 winning по CSS specificity, modal приклеивался
к левому краю viewport вместо центра. User screenshot показал Schema edit
выходящим за левую границу экрана.

Fix: remove inset-0 fullscreen pattern. Use simple centered modal —
left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 + w-[95vw] max-h-[95vh]
overflow-y-auto. На mobile <880px max-w из size variant даёт ширину 95vw
(natural fit). На desktop max-w ограничивает до 440/560/720/880/920px.

2) LOGO 'ORDINIS MDM' С CIRCLE ICON (per redesign prototype)
Sidebar logo: 'ORDINIS' → circle icon (accent orbit ring + dot) +
'ORDINIS' bold + 'MDM' mute subtitle (Tektur). SVG inline — нет external
dep.

Collapsed mode: только circle icon, no text (uses Tektur ORDINIS dropped).

3) TIMELINE BUTTON LABEL
InfoPanel button 'Time-travel…' → 'Таймлайн' (per user feedback). Behaviour
не меняется — клик открывает picker. Inline таймлайн visualization
отложен (большой refactor, нужен product decision).

Verified:
  - Dialog modal центрируется на десктоп
  - Logo рендерится с svg + text
  - Tests: 116 pass
2026-05-11 17:49:57 +03:00
Александр Зимин 6b277a78a5 Merge branch 'feat/editor-topbar-redesign' into 'main'
feat(editor): match redesign — TopBar title + tab counts + InfoPanel actions

See merge request 2-6/2-6-4/terravault/ordinis!69
2026-05-11 14:45:14 +00:00
Zimin A.N. ec99010697 feat(editor): match redesign prototype layout — TopBar title + tab counts + InfoPanel actions
Per /Users/zimin/Downloads/redesign/screens/03-editor-records.png редизайн
prototype editor layout отличается от current MVP:

1. TopBar absorbs editor title + version (was в PageHeader)
2. PageHeader удалён — title и breadcrumb теперь только в TopBar
3. Tab labels получили counts (Записи 127, Связи 6, Поля 12)
4. Action buttons распределены per role:
   - Time-travel + AOI → InfoPanel bottom (close к data context)
   - Schema edit + +Запись → tab toolbar right (close к tab actions)

Changes:

src/components/layout/TopBar.tsx
  - Breadcrumb получил subtitle slot — mono '<name> · v<version>'
  - useBreadcrumb fetches dict detail для editor route '/dictionaries/$name'
  - Render: '← Справочники / Космические аппараты satellites · v1.0.0'

src/api/queries.ts
  - useDictionaryDetail принимает name: string | undefined + enabled flag
  - Guard для editor breadcrumb когда route не matches dict

src/routes/dictionaries.$name.tsx
  - Removed <PageHeader> — title/breadcrumb теперь в TopBar
  - EditorInfoPanel получает actions prop:
    onTimeTravel + timeTravelActive + onAoi + aoiActive
  - EditorTabBar получает counts (per-tab badge) + actions slot
    (right-aligned Schema + +Запись buttons)
  - extractOutgoingFkCount helper для relations count

src/components/editor/EditorInfoPanel.tsx
  - actions prop с Time-travel + AOI buttons
  - Rendered в panel выше Relations section, между metadata и FK list
  - aria-pressed когда active (time-travel или AOI с filter)

src/components/editor/EditorTabBar (inline in route)
  - counts prop: Partial<Record<EditorTab, number>>
  - actions prop: ReactNode для right-aligned cluster
  - inline count badge — text-mono text-mute next to label

Tests: 116 pass. TS strict clean.
2026-05-11 17:45:06 +03:00
Александр Зимин ac80c3f4a1 Merge branch 'feat/sidebar-collapse' into 'main'
feat(sidebar): desktop collapse 220px → 56px per handoff

See merge request 2-6/2-6-4/terravault/ordinis!68
2026-05-11 14:22:36 +00:00
Zimin A.N. 69a86b238c feat(sidebar): desktop collapse mode 220px → 56px per handoff prototype
Handoff prototype показывает «‹ Свернуть» button внизу sidebar — toggle
desktop rail в icon-only 56px. Persists в localStorage ord-sidebar-collapsed.

Sidebar component:
  - State collapsed (localStorage 'ord-sidebar-collapsed' = '1')
  - <aside width> transitions между w-[220px] и w-[56px] (200ms ease)

SidebarContent (DRY с MobileSidebar) получил props:
  - collapsed?: boolean (default false)
  - onToggleCollapsed?: () => void (undefined hides button — mobile drawer)

Когда collapsed:
  - Logo: 'ORDINIS' → 'O' (single char, centered)
  - Section labels (text-cap headers) — hidden
  - Nav links: icon-only, centered, icon size 18px (vs 15px expanded);
    title attribute с label для hover tooltip
  - Badges (records count, pending) — hidden (нет места)
  - User block: avatar only, name/email hidden; title attribute с full name
  - Toggle button bottom: '‹ Свернуть' → '›' (icon-only)

Mobile (MobileSidebar Sheet) НЕ получает collapse — там Sheet даёт full
nav text всегда, close через × header.

A11y: aria-label / title для всех collapsed buttons. Click handler
sets localStorage + state — survives F5.

Tests: 116 pass. TS strict clean.
2026-05-11 17:13:06 +03:00
Александр Зимин 0eb86bf592 Merge branch 'feat/drawer-filters-wired-plus-table-responsive' into 'main'
feat: wire drawer toolbar filters + records table responsive hiding

See merge request 2-6/2-6-4/terravault/ordinis!67
2026-05-11 14:10:34 +00:00
Zimin A.N. 889207f629 feat: wire drawer toolbar filters + records table responsive hiding
Closing 2 handoff gaps:

1) DRAWER TOOLBAR FILTERS (handoff Screen 3 line 279)
SchemaDrivenForm получил три new optional props:
  - searchFilter (string) — case-insensitive substring против field key + label
  - onlyFilled (boolean) — hide fields с empty data[key]
    (null/undefined/''/false/0/empty-array/empty-object)
  - onCounterChange (visible, total) — surface field counter parent'у

Filter применяется поверх bucketing — все три buckets (identity/description/
extra) фильтруются. UI рендерит filteredBuckets.X.map(...) вместо raw bucket'ов.

В sections layout (drawer use case) если section после filter empty —
sticky header не рендерится. Tabs layout backward-compat (filter применяется
но visually invisible если user в другом tab'е).

dictionaries.$name.tsx callsite:
  - State: drawerSearch, drawerOnlyFilled, drawerCount {visible, total}
  - Reset on drawer close
  - RecordDrawer.toolbar prop wired только в edit mode (create — все поля
    empty, 'только заполненные' даст 0/0)
  - SchemaDrivenForm receives все три filter props

Result: user может typing 'mass' в drawer search → видит только mass_kg /
data_mass / etc.; toggle 'только заполненные' → hide unused optional fields.

2) RECORDS TABLE RESPONSIVE COLUMN HIDING (handoff line 466)
Records table в dictionaries.$name.tsx применяет hideBelow API из MR !59:
  - businessKey: всегда visible
  - name/code: hideBelow='md' (768px)
  - extra schema columns: hideBelow='lg' (1024px)
  - scope badge: hideBelow='sm' (640px)
  - validFrom: hideBelow='lg'
  - actions: всегда visible

На mobile 375px только businessKey + actions visible — chrome остаётся
usable. Tablet 768+ adds name/scope. Desktop 1024+ adds schema columns.

Tests: 116 pass.
2026-05-11 17:10:26 +03:00
Александр Зимин e654a3e341 Merge branch 'fix/bg-de-yellow' into 'main'
fix(theme): de-saturate light bg — убрать жёлтый Earth-cream

See merge request 2-6/2-6-4/terravault/ordinis!66
2026-05-11 14:02:02 +00:00
Zimin A.N. e5572d5346 fix(theme): de-saturate light bg — убрать жёлтый Earth-cream tone
Пользователь: 'этот желтый фон давай уберем'. Светлый bg #fbf8ee
выглядел слишком cream/yellow на staging — особенно на больших areas
страницы (список справочников, hover states).

Color token changes (light theme только; dark не трогаем):
  --color-bg:        #fbf8ee → #fafaf8  (off-white neutral)
  --color-surface-2: #f4eedc → #f2f1ee  (subtle warm grey hover/stripe)
  --color-line:      #e3dccb → #e4e1dc  (de-saturated border)
  --color-line-2:    #efe9d8 → #ecebe7  (subtle inner border)

Brand accents preserved:
  --color-accent: #b05a2e (warm orange-brown) — unchanged
  --color-navy:   #3a2818 (deep brown) — unchanged
  --color-warn / pink / green BG — unchanged (semantic states)

Result: cleaner light theme, professional reading surface. Accent
color по-прежнему даёт warmth для brand identity, но page bg
больше не tints всё жёлтым.
2026-05-11 17:01:54 +03:00
Александр Зимин a163202076 Merge branch 'fix/semantic-release-tarball-dir' into 'main'
fix(release): drop invalid tarballDir: false

See merge request 2-6/2-6-4/terravault/ordinis!65
2026-05-11 13:57:28 +00:00
Zimin A.N. 090bff56ce fix(release): drop invalid tarballDir: false config
@semantic-release/npm падал с EINVALIDTARBALLDIR — tarballDir option
должен быть String OR omitted. У нас был false (boolean), что invalid.

Поскольку npmPublish: false (мы НЕ публикуем pkg в npm registry —
private repo), tarballDir не нужен вовсе. Удалили — default behavior
(npm pack идёт в temp dir после bump, но не used при npmPublish:false).

После этого fix semantic-release должен пройти normally:
  - analyze conventional commits с момента v1.2.2
  - bump version в admin-ui/package.json
  - generate CHANGELOG.md
  - commit + tag vX.Y.Z [skip ci]
  - create GitLab Release object

Минимум tag будет v1.3.0 (мы накопили 10+ feat: с момента v1.2.2).
2026-05-11 16:57:19 +03:00
Александр Зимин f3aad503f1 Merge branch 'feat/drawer-sections-layout' into 'main'
feat(drawer): all-sections layout + chips strip per handoff

See merge request 2-6/2-6-4/terravault/ordinis!64
2026-05-11 13:37:47 +00:00
Zimin A.N. 155c70e23c feat(drawer): all-sections layout с chips strip per handoff prototype
Handoff Screen 3 RecordDrawer показывает sections подряд с chips strip
для quick jump, не tabs (currently SchemaDrivenForm has 3 tabs).

SchemaDrivenForm:
  - New optional prop layout: 'tabs' (default, legacy) | 'sections'
  - В sections mode:
    * Section chips strip на верху (sticky top-0) вместо Tabs
    * Chip = bucket name + field count в Mono
    * Click chip → scrollIntoView к section
    * Все 3 buckets рендерятся подряд (visible одновременно)
    * Каждая section получает sticky h3 cap header + scroll-mt-12
    * z-indexed sticky: chips strip = 10, section headers = 5
  - В tabs mode: backward-compat без изменений

RecordDrawer callsite (dictionaries.$name.tsx):
  - Передаёт layout='sections' в SchemaDrivenForm (create + edit)
  - Существующий tabs API остаётся для test'ов которые используют default

Layout matches handoff Screen 3 prototype:
  [chips strip sticky]
  [section: Основное]
   field grid 2-col
  [section: Описание (i18n)]
   localized fields
  [section: Дополнительно]
   optional fields grid

Future Phase B refactor: backend x-section schema metadata (open question
#5) разблокирует per-property sections (вместо bucketing). Текущий
fallback bucketing (identity/description/extra) достаточен для MVP.

Tests: 116 pass (test использует default 'tabs' layout, не разломан).
2026-05-11 16:37:38 +03:00
Александр Зимин 4201cd3155 Merge branch 'feat/editor-info-panel' into 'main'
feat(editor): info panel + 3-col layout per handoff prototype

See merge request 2-6/2-6-4/terravault/ordinis!63
2026-05-11 13:33:48 +00:00
Zimin A.N. a57cf520a4 feat(editor): left info panel + 3-col layout per handoff prototype
Handoff prototype design/compact.html показывает editor как 3-col layout:
[Sidebar 220 (global nav)] [InfoPanel 220 (dict metadata)] [main content].
Текущая implementation была 2-col (nav + everything).

NEW src/components/editor/EditorInfoPanel.tsx:
  - Scope badge (PUBLIC/INTERNAL/RESTRICTED) — top
  - ОПИСАНИЕ section — caption + dict.description body
  - Metadata 2x2 grid: Bundle / Версия / Записей / Локали
    (mono text-ink-2, cap labels)
  - СВЯЗИ section с двумя группами:
    → ссылается  outgoing FK list (name links к /dictionaries/$name)
    ← используют incoming refBy list (deduplicated sourceDict names)
  - sticky lg:top-2 self-start чтобы panel оставалась видна при scroll
  - lg:max-h-[calc(100vh-7rem)] overflow-y-auto если metadata высокий

src/routes/dictionaries.$name.tsx:
  - Обернул содержимое (banner + tabs + tab content) в:
    <div className='grid grid-cols-1 lg:grid-cols-[220px_1fr] gap-4 lg:gap-6'>
      <EditorInfoPanel ... />
      <div>{banner + tabs + content}</div>
    </div>
  - На <lg переключается в stacked (info above content) — single column
    благодаря grid-cols-1.

PageHeader остаётся выше grid (full-width breadcrumb + title + actions).
Action buttons (AOI / Time-travel / Schema edit / Создать) живут в
PageHeader.actions slot — handoff prototype показывает их в info panel,
но рядом с title лучше discoverable. Может уйти в info panel в future
refactor.

Tests: 116 pass. TS strict clean.
2026-05-11 16:33:40 +03:00
Zimin A.N. f43ce5563a feat(catalog): row-based table per handoff prototype design/compact.html
Refactor каталога с card grid → compact row table. Handoff README line
46 явно говорит 'clicking any dictionary row in the catalog' — наша cards
implementation diverged от прототипа.

What's new:
- DictionaryListTable — single flat table (bundle стал column, не группа)
- DictRow — compact tr с scope dot prefix + title + truncated desc
- 8 columns per prototype: name / id / bundle / scope / records / → / ← / updated
- Responsive column hiding via hideBelow-style breakpoints:
  - id: hidden <md
  - bundle: hidden <lg
  - scope: hidden <sm
  - records: hidden <md
  - → ←: hidden <lg
  - updated: hidden <xl
- На mobile <640px показано только name column (с inline scope dot и desc)
- Row click → navigate к editor; Enter/Space keyboard accessible (role=link)

Removed:
- DictCard component (card layout)
- FkChip component (FK chips на cards — теперь just counts)
- SCOPE_STRIP (vertical 3px strip — заменён на inline scope dot)
- groupByBundle usage (bundle стал column, не group section)
- MAX_REFBY_CHIPS const

Note: outgoing FK count (→) пока показывает '—' — требует schemaJson per-dict
fetch (40+ requests). Batch endpoint GET /dictionaries/graph (handoff open
question #2) разблокирует это. Текущий incoming refBy через useDictionary-
Dependents работает per row.

Tests: 116 pass. TS strict clean.
2026-05-11 16:30:31 +03:00
Zimin A.N. d4000ddd3d feat(drawer): sticky toolbar API per handoff Screen 3 line 279
RecordDrawer теперь принимает optional toolbar prop:
  - search (string) — field name filter
  - onlyFilled (boolean) — show only filled fields toggle
  - counterVisible/Total (number) — 'N / M полей' caption

Sticky position между header и body, h=44 per handoff style. Toolbar
rendered только если caller передал. SchemaDrivenForm callsite (записать
filter в каждое FieldRenderer) — separate follow-up, требует refactor
form internals (currently 3 buckets identity/description/extra).

Section anchor chips + wide-mode ToC rail — deferred до backend
x-section schema metadata (CEO open question #5 в handoff).
2026-05-11 16:02:11 +03:00
Александр Зимин 90dd7f8c5d Merge branch 'feat/keyboard-shortcuts' into 'main'
feat(editor): keyboard shortcuts j/k/Enter/n per handoff

See merge request 2-6/2-6-4/terravault/ordinis!60
2026-05-11 13:00:50 +00:00
Zimin A.N. a09c4113c1 feat(editor): keyboard shortcuts j/k/Enter/n per handoff Screen 2
Handoff line 438: 'Pressing j/k moves selected row; Enter opens drawer;
Esc closes; n opens new-record drawer; / focuses search.'

Implementation:
  - rowCursor state — index в visibleRecords (-1 = no focus)
  - j или ArrowDown → cursor++ (clamped)
  - k или ArrowUp → cursor-- (clamped)
  - Enter → setEdit({kind:'edit', record}) когда cursor valid
  - n → setEdit({kind:'create'}) когда canMutate
  - Esc — handled Radix Dialog natively через RecordDrawer
  - / — handled TopBar (⌘K equivalent, focuses global search input)

Guards:
  - Skip когда target inside input/textarea/contentEditable (no conflict с typing)
  - Skip когда drawer/modal open (edit.kind !== 'closed' — focus в portal)
  - Cursor reset на page/filter change (stale index безопасности)

Visual: active row получает bg-accent-bg/40 outline accent для clarity.
2026-05-11 16:00:42 +03:00
Александр Зимин e52a42ab14 Merge branch 'feat/workflow-banner-table-a11y' into 'main'
feat(handoff): WorkflowBanner + table a11y/responsive + toast styling

See merge request 2-6/2-6-4/terravault/ordinis!59
2026-05-11 12:58:20 +00:00
Zimin A.N. 0acba4c073 feat(handoff): WorkflowBanner + table a11y + responsive + toast styling
Closing handoff gaps выявленных при полном audit'е README.md vs current
implementation. См. screen-by-screen mapping ниже.

== Screen 2 — Editor: WorkflowBanner (NEW) ==
Required by handoff (line 238-242) но не существовал. Inline status row выше
tab bar — live/review/info variants. Backend не имеет explicit dict-level
workflow state (draft → review → live transition), используем proxy:
  - approvalRequired=false      → 'Live' (green-bg + green left edge)
  - approvalRequired=true + 0   → 'Approval enabled' (accent-bg + accent edge)
  - approvalRequired=true + N   → 'На ревью N' (warn-bg + warn edge), link к /reviews

Backend extension future: добавить explicit workflowState к DictionaryDetail
+ buttons для transitions (request-review / approve / publish). Сейчас banner
дает минимум — visual workflow signal без UI mutation buttons.

== Table accessibility per handoff line 476 ==
TableHeaderCell:
  - scope='col' (a11y screen reader requirement)
  - aria-sort='ascending|descending|none' когда sortable prop true
  - New sortable + sortDirection props (API ready, не используется пока)

== 560px responsive per handoff line 466 ==
TableHeaderCell + TableCell получили optional hideBelow='sm|md|lg' prop:
  hideBelow='sm' → hidden <640px (table-cell ≥sm)
  hideBelow='md' → hidden <768px
  hideBelow='lg' → hidden <1024px

Callsites могут пометить secondary columns (created_by, updated_at, etc.)
hideBelow='md' для clean mobile experience. Текущие routes ещё не используют
prop — API ready для incremental adoption.

== Toast styling per handoff line 302-305 ==
Sonner toast — раньше surface bg + ink text. Handoff:
  - Navy bg + on-accent text (warm cream-orange feeling)
  - 4s auto-dismiss
  - Variant accent через left border 4px:
    success → green / error → pink / info → accent / warning → warn
  - cap-style title (но используем text-body для нативности, не overkill)
  - 13px font-sans

richColors disabled — наши tokens вместо sonner defaults.

Files:
  - NEW src/components/editor/WorkflowBanner.tsx
  - src/routes/dictionaries.$name.tsx (wire banner above tab bar)
  - src/ui/components/table.tsx (a11y + hideBelow API)
  - src/ui/components/toaster.tsx (navy variant + variant borders)
  - src/ui/index.ts (TableCellProps export)

Tests: 116 pass. TS strict clean.
2026-05-11 15:58:12 +03:00
Александр Зимин 5883adc05d Merge branch 'fix/table-thead-and-horizontal-overflow' into 'main'
fix(table+layout): TableHead = THEAD wrapper + kill horizontal scroll

See merge request 2-6/2-6-4/terravault/ordinis!58
2026-05-11 12:49:35 +00:00
Zimin A.N. 787cea9db1 fix(table+layout): TableHead alias to THEAD wrapper + kill horizontal scroll
CRITICAL bugs reported by user — table выглядела кривой, контент уезжал
за экран с горизонтальным скроллом.

Bug 1 — invalid HTML в Table:
  Callsites используют <TableHead><TableRow><TableHeaderCell>... ожидая
  нstart-style THEAD wrapper. Но мой alias делал TableHead = TableHeaderCell
  (TH cell). Получалось <th><tr><th>...</th></tr></th> — invalid nested,
  browser parser hoist'ил TableRow наружу, создавая phantom 509px column
  слева от данных. Колонки выглядели misaligned, content смещён вправо.

  Fix: TableHead → THEAD wrapper (alias TableHeader). TableHeaderCell
  остаётся отдельным TH cell. Source semantically correct, browser parses
  валидно, phantom column исчез.

Bug 2 — horizontal overflow:
  Scope strip border на верху detail-страницы использовал
  '-mt-6 -mx-4 sm:-mx-6 lg:-mx-8'. На lg viewport main padding только
  sm:px-6 (24px), strip negative margins -mx-8 (32px) → 8px overflow each
  side → body.scrollWidth > viewport → horizontal scrollbar.

  Fix:
  - Strip negative margins только до -mx-6 (соответствует main padding)
  - main получил overflow-x-clip + max-w-7xl wrapper получил min-w-0
    (защита от любых future overflow children)

Verified в preview viewport 1440 + 375: body.scrollWidth === viewport,
no h-scroll.
2026-05-11 15:49:27 +03:00
Александр Зимин d9670a9cae Merge branch 'fix/tailwind-merge-custom-utilities' into 'main'
fix(ui): tailwind-merge config + CI image mirror

See merge request 2-6/2-6-4/terravault/ordinis!57
2026-05-11 12:47:50 +00:00
Zimin A.N. 9e2d985485 fix(ui): tailwind-merge стрипал text-body — buttons ушли в 16px inherited
CRITICAL bug — на staging buttons рендерились в 16px вместо handoff
workhorse 13px. UpdateBanner secondary buttons показывали invisible
текст (text-ink overrode by inherited text-on-accent от parent banner).

Root cause:
  buttonVariants base = 'rounded-md text-body font-medium ...'
  primary variant     = 'bg-navy text-on-accent ...'

tailwind-merge default config pattern-matches `text-*` как ОДНУ группу
(color). Видя `text-body text-on-accent` он считал это конфликтом двух
colors → keep last → text-on-accent остаётся, text-body стрипается.
Result: button теряет font-size → inherit body 16px.

Fix: extendTailwindMerge регистрирует наши custom semantic typography
utilities (text-body/cell/mono/cap/title-*) в группе font-size (отдельной
от colors). twMerge теперь знает `text-body text-on-accent` это size +
color, обе сохраняются.

Also: text-mono/text-cap в font-family группе (они baked Mono/Tektur)
— fix конфликт с font-mono/font-display tokens если кто-то их случайно
combined.

Verified в preview: 'Sign in' button class теперь содержит text-body,
computed fontSize: 13px (вместо 16px).

Plus CI: release job image node:22-alpine → repo.nstart.cloud/library/
node:22-alpine (Docker Hub rate-limited, mirror используется во всех
других jobs).
2026-05-11 15:45:27 +03:00
Александр Зимин 1d978d2be8 Merge branch 'feat/mobile-responsive' into 'main'
feat(mobile): Sidebar drawer <1024px + Modal/Sheet fullscreen <880px

See merge request 2-6/2-6-4/terravault/ordinis!56
2026-05-11 12:39:31 +00:00
Zimin A.N. 7a3b31b957 feat(mobile): Sidebar drawer <1024px + Modal/Sheet fullscreen <880px
Per design_handoff_ordinis_mdm/README.md responsive table (line 464-465):
- ≤1024px: Sidebar becomes overlay drawer (hamburger в TopBar)
- ≤880px:  Drawers и modals fullscreen (100vw × 100dvh, no border-radius)

Implementation:

src/components/layout/Sidebar.tsx
  - Extracted SidebarContent (logo + nav + user block) для DRY
  - Desktop <Sidebar /> wraps SidebarContent в hidden lg:flex aside
  - New <MobileSidebar open onClose /> — Sheet с тем же содержимым,
    260px wide, slides from left
  - SidebarLink принимает onClick → drawer auto-close при navigate

src/components/layout/TopBar.tsx
  - Optional onMenuClick prop — рендерит hamburger button (Menu icon
    из lucide-react) с lg:hidden
  - VersionBadge скрыт <md (768px) — diagnostic info, не critical UX

src/routes/__root.tsx
  - useState mobileNavOpen, передаём в MobileSidebar + TopBar

src/ui/components/dialog.tsx
  - SIZE_CLASSES получили  prefix (arbitrary Tailwind v4
    breakpoint per handoff exact 880px). На mobile <880px modal становится
    fullscreen (inset-0 w-full h-full no rounded), ≥880px — centered с
    translate + max-w из SIZE_CLASSES.

src/ui/components/sheet.tsx
  - size variants: sm:max-w-* → min-[880px]:max-w-*. На mobile <880px
    sheet берёт w-full (fullscreen drawer per handoff).

src/components/record/RecordDrawer.tsx
  - max-width переключатель 520/880 теперь применяется только ≥880px.
    На mobile drawer всегда fullscreen.

src/ui/components/language-switch.tsx
  - Display fallback: opt.short → opt.label → uppercase id.
    Previously показывал id ('ru-RU', 'en-US') когда short не был задан —
    теперь использует label ('RU', 'EN') как fallback.

Browser-verified в preview viewport 375×812:
  - Hamburger ☰ visible, click открывает Sheet с nav items
  - Backdrop fade + slide-from-left animation
  - TopBar fits в 375px (RU/EN compact, Sign in visible)
  - LoadingBlock + Alert text-wrap correctly
2026-05-11 15:39:23 +03:00
Александр Зимин 706c31b2d7 Merge branch 'fix/ci-detection-via-short-sha' into 'main'
fix(version): CI detect via CI_COMMIT_SHORT_SHA

See merge request 2-6/2-6-4/terravault/ordinis!55
2026-05-11 12:30:06 +00:00
Zimin A.N. b6af155da2 fix(version): detect CI build via CI_COMMIT_SHORT_SHA, not process.env.CI
Staging показывал badge 'local · {commit}' вместо ожидаемого 'dev'.
Причина: Dockerfile не пробрасывает process.env.CI через ARG. Vite
видит только что было передано через --build-arg в .gitlab-ci.yml
(GIT_COMMIT/GIT_TAG → CI_COMMIT_SHORT_SHA/CI_COMMIT_TAG).

Fix: использовать CI_COMMIT_SHORT_SHA как primary CI detect — он всегда
проходит через Dockerfile ARG (см. ordinis-admin-ui/Dockerfile). Это
canonical GitLab CI signal — always set в любом pipeline.

process.env.CI остаётся как secondary check для других CI систем
(local CI runners, GitHub Actions если когда-то) где CI_COMMIT_SHORT_SHA
не set но CI=true.
2026-05-11 15:29:58 +03:00
Александр Зимин 24e621ced4 Merge branch 'feat/stage-3.4-events-json-polish' into 'main'
feat(editor): Stage 3.4 polish — Events embedded + JSON highlight

See merge request 2-6/2-6-4/terravault/ordinis!54
2026-05-11 12:28:37 +00:00
Zimin A.N. f0392af0e3 feat(editor): Stage 3.4 polish — Events embedded + JSON syntax highlight
Per handoff Stage 3.4 polish list (Records/Relations/Fields/JSON/Events/
History tabs).

Events tab — раньше был redirect к /audit?dict=name. Теперь embedded:
- useAudit({dictionaryName, size: 20}) → last 20 entries
- 4-col compact table: time / action / businessKey / user
- Empty state когда нет событий
- Bottom link → /audit с filter для full diff view

JSON tab — раньше был plain <pre>. Теперь:
- Regex-based syntax highlight (keys=accent, strings=green, numbers=warn,
  booleans=pink, null=mute italic)
- Copy-to-clipboard button с visual feedback
- Bundle cost: 0 (нет Monaco). Если потребуется EDIT — Monaco lazy
  через React.lazy в Stage 3.x followup.

Fields tab — пока read-only table остаётся. Inline edit требует backend
PATCH /dictionaries/{name}/schema endpoint; deferred.

History tab — placeholder remains. Требует backend changelog endpoint;
deferred.

TS strict + 116 tests pass.
2026-05-11 15:28:29 +03:00
Александр Зимин 27bcdf5ca0 Merge branch 'ci/semantic-release-auth-fix' into 'main'
ci(release): fix git auth + fail-fast on missing GITLAB_TOKEN

See merge request 2-6/2-6-4/terravault/ordinis!53
2026-05-11 12:22:05 +00:00
Zimin A.N. 1e93d74420 ci(release): fix git auth + fail-fast when GITLAB_TOKEN missing
semantic-release провалился с 'HTTP Basic: Access denied' потому что:

1. CI default git remote использует CI_JOB_TOKEN scope — не может push'ить
   tags/commits в protected refs (main branch).
2. GITLAB_TOKEN ещё не настроен в Settings → CI/CD → Variables.
3. Без explicit git remote rewrite semantic-release/git plugin падает
   с cryptic 'Authentication failed' вместо понятного 'token missing'.

Fixes:
- before_script: fail-fast если GITLAB_TOKEN пустой — печатает setup
  инструкцию (write_repository + api scopes, Masked + Protected flags)
  и exit 0. Pipeline не краснеет (allow_failure: true).
- git remote set-url origin https://gitlab-ci-token:${GITLAB_TOKEN}@... —
  переопределяет default remote чтобы git push мог работать с
  Project Access Token'ом.
- git config user.email/name — semantic-release commit author.

После настройки GITLAB_TOKEN в GitLab UI следующий push в main создаст
первый авто-tag (v1.3.0 minimum по conventional commits с момента v1.2.2).
2026-05-11 15:19:22 +03:00
Александр Зимин 73d8fa585a Merge branch 'feat/stage-3.9-drop-nstart-ui' into 'main'
feat(ui): drop @nstart/ui dependency (Stage 3.9)

See merge request 2-6/2-6-4/terravault/ordinis!52
2026-05-11 12:17:56 +00:00
Zimin A.N. 5007e0f4eb feat(ui): drop @nstart/ui dependency (Stage 3.9)
Все font cascade bugs из последних MR были вызваны @nstart/ui pollution
(Tektur inheritance от Card parent'ов, Onest font в Button, font-primary
class overrides). Решили обрезать раньше plan'а.

What changed:

New primitives (8 файлов в src/ui/components/):
  - panel.tsx           — container с border/surface
  - field.tsx           — FieldLabel/Hint/Error typography helpers
  - text-input.tsx      — Input + label/hint/error composite
  - table.tsx           — Table/TableHeader/Body/Row/HeaderCell/Cell/Empty
  - date-picker.tsx     — native <input type=date> wrapper с label/hint/error
  - multi-select.tsx    — Radix Popover + inline checkboxes
  - single-select.tsx   — native <select> с label/hint/error chrome
  - language-switch.tsx — segmented control в Tektur uppercase

Compatibility shims (existing components extended):
  - checkbox.tsx        — + label/description/error/onChange (nstart-compat
                          synthetic event), wrap в <label> когда есть chrome
  - modal.tsx           — + panelClassName / bodyClassName props
  - form-actions.tsx    — + align prop (start/end/between)
  - tabs-simple.tsx     — TabItem.count alias for .trailing (nstart-compat)
  - table TableHead     — alias TableHeaderCell с align prop

Barrel rewrite (src/ui/index.ts):
  - Удалён 'export * from @nstart/ui'
  - Explicit exports для всех 45+ нужных символов
  - SelectOption / MultiSelectOption / LanguageOption теперь {id, label}
    с optional 'value' alias — nstart-compat без массового codemod call-sites

styles.css cleanup:
  - Removed @import @nstart/ui/styles/{fonts,theme}.css
  - Removed @source nstart/dist directive (Tailwind v4 scan)
  - Removed --text-sm: 13px override (был костыль для @nstart/ui dist)
  - Legacy color tokens (--color-carbon/ultramarain/orbit/regolith/asteroid)
    sсодержали fallback mappings — оставлены, но callsites больше не используют

Codemod: 9 файлов конвертированы legacy colors → handoff tokens
  carbon → ink, ultramarain → accent, orbit → warn, regolith → line, asteroid → mute

main.tsx:
  - NStartUiProvider → TooltipProvider (Radix)
  - DatePickerProvider убран (наш DatePicker native, no provider needed)

routes/dictionaries.$name.tsx:
  - Removed useRef-based <input>.indeterminate hack
  - Radix Checkbox принимает checked='indeterminate' declaratively

package.json: -@nstart/ui (was 0.1.3)

Bundle impact:
  before: vendor-nstart-ui chunk = 1228 KB
  after:  no nstart chunk, всё в vendor-misc (+~70 KB Radix wrappers)
  net savings: ~1.15 MB minified, ~440 KB gzip

Tests: 116 pass (1 fixed: tab role from 'button' → 'tab', Radix semantically correct).
TS strict: clean.
Browser-verified (preview): 7 utilities computed correctly, nstart bundle absent.
2026-05-11 15:17:37 +03:00