Commit Graph

445 Commits

Author SHA1 Message Date
Александр Зимин 8621687a60 feat(dict): 7-day retention auto-purge + inline restore UI 2026-06-09 13:40:23 +00:00
semantic-release-bot 05d2093273 chore(release): v2.53.0
## [2.53.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.52.0...v2.53.0) (2026-06-08)

###  Features

* **dict:** soft-delete с recovery (Phase 1) ([0ccdff9](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/0ccdff95d2610bd31968708fb820ca2acb284bb1))
2026-06-08 14:37:34 +00:00
semantic-release-bot 4516559e21 chore(release): v2.52.0
## [2.52.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.51.1...v2.52.0) (2026-06-08)

###  Features

* **dict:** delete dictionary endpoint + UI button с cascade safety ([5c6801f](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/5c6801f993a34cfa43e71419807250973ce376ac))

### 🐛 Fixes

* **ci:** release не зависит от deploy-staging — unblock tag chain ([1a420b4](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/1a420b428f333034e75d8980cf2e59e015466adc))
* **schema:** FK target field — select из реальной схемы вместо free-form ([bfe5142](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/bfe5142bbae19f2d537eb2f2c62e5c29e666d173))
* **ui:** delete dict modal — destructive вместо invalid mars/danger ([6392621](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/6392621199fd58546893c611a15b32613137246e))

### 📝 Docs

* **changelog:** public release notes v2.45.3 → v2.52.0 ([082eb88](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/082eb88e7e164630b226a5a23f5ec9594ca485a8))
2026-06-08 11:08:15 +00:00
Александр Зимин 6392621199 fix(ui): delete dict modal — destructive вместо invalid mars/danger 2026-06-08 10:08:53 +00:00
Александр Зимин 5c6801f993 feat(dict): delete dictionary endpoint + UI button с cascade safety 2026-06-05 09:47:05 +00:00
Александр Зимин bfe5142bba fix(schema): FK target field — select из реальной схемы вместо free-form 2026-06-04 15:24:55 +00:00
semantic-release-bot 48a1fd5f48 chore(release): v2.51.1
## [2.51.1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.51.0...v2.51.1) (2026-06-02)

### 🐛 Fixes

* **reviews:** admin может self-approve record draft через UI ([308c910](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/308c9104e9636d0b13342f3e4611005589e1e002))
2026-06-02 13:18:24 +00:00
Александр Зимин 308c9104e9 fix(reviews): admin может self-approve record draft через UI 2026-06-02 13:02:13 +00:00
semantic-release-bot 039b6ef039 chore(release): v2.51.0
## [2.51.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.50.0...v2.51.0) (2026-06-02)

###  Features

* **layout:** убрать max-w-7xl на root — full width на больших экранах ([ff18a3a](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/ff18a3aa720824314bc2354d36acfd8220df58a8))
2026-06-02 12:55:05 +00:00
Александр Зимин ff18a3aa72 feat(layout): убрать max-w-7xl на root — full width на больших экранах 2026-06-02 12:38:10 +00:00
semantic-release-bot 4f16669f2b chore(release): v2.50.0
## [2.50.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.49.0...v2.50.0) (2026-06-02)

###  Features

* **dict:** таблица справочника — hide tail columns по умолчанию (без H-scroll) ([b619071](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/b6190713e4e472b0aa1a9f26592b537920b8df8b))

### 🐛 Fixes

* **dict:** default-hide для existing users (v=2 storage) + sticky header/pagination ([fece673](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/fece673017b5fbae0035f275cabba14f3d06879c))
2026-06-02 12:35:11 +00:00
Александр Зимин fece673017 fix(dict): default-hide для existing users (v=2 storage) + sticky header/pagination 2026-06-02 12:22:19 +00:00
Александр Зимин b6190713e4 feat(dict): таблица справочника — hide tail columns по умолчанию (без H-scroll) 2026-06-02 12:14:00 +00:00
semantic-release-bot 071315b058 chore(release): v2.49.0
## [2.49.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.48.0...v2.49.0) (2026-06-02)

###  Features

* **dict:** таблица справочника — все scalar поля схемы в pool колонок ([65f5dbd](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/65f5dbd48b5be5df612a74e834a5ae482bcced7e))

### 🐛 Fixes

* **approve:** retry на Postgres SERIALIZABLE 40001 (массовый approve drafts) ([30506b0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/30506b0cc4f7c52ddbcd47a8960c720117115098))
2026-06-02 12:08:28 +00:00
Александр Зимин 65f5dbd48b feat(dict): таблица справочника — все scalar поля схемы в pool колонок 2026-06-02 11:50:16 +00:00
semantic-release-bot 4510d7cc6f chore(release): v2.48.0
## [2.48.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.47.0...v2.48.0) (2026-06-02)

###  Features

* **ui:** RecordDrawer wide-mode default по viewport ([010f71e](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/010f71e44d0caf9768c295bde3afa45593767bb3))

### 🐛 Fixes

* **bundle:** semver-aware schema update — не откатывать user-published ([39e24a6](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/39e24a6d0130fc29019d3347c92f0b431a7ca0e9))
2026-06-02 11:26:08 +00:00
Александр Зимин 010f71e44d feat(ui): RecordDrawer wide-mode default по viewport 2026-06-02 11:14:48 +00:00
semantic-release-bot c892f30b3e chore(release): v2.47.0
## [2.47.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.46.1...v2.47.0) (2026-06-02)

###  Features

* **ui:** dict table column sort + visibility toggle (localStorage) ([c2e7dd0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/c2e7dd0c87113868f4b4b8c02936ae5cd894c450))
2026-06-02 11:04:14 +00:00
Александр Зимин c2e7dd0c87 feat(ui): dict table column sort + visibility toggle (localStorage) 2026-06-02 10:58:59 +00:00
semantic-release-bot c20ffb6dee chore(release): v2.46.1
## [2.46.1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.46.0...v2.46.1) (2026-06-02)

### 🐛 Fixes

* **workflow:** drop DB self-approve constraints (unblock admin override) ([ba76704](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/ba767045a494837c5aa95439db2fc9e3573ed592))
2026-06-02 09:27:23 +00:00
semantic-release-bot ff0fd1e3e9 chore(release): v2.46.0
## [2.46.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.45.3...v2.46.0) (2026-06-01)

###  Features

* **workflow:** admin self-approve override (D3 relaxation для small teams) ([ba49854](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/ba49854a612aae10e9a1dacb1f020dfe36eefed7))
2026-06-01 18:55:37 +00:00
semantic-release-bot 41466123cd chore(release): v2.45.3
## [2.45.3](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.45.2...v2.45.3) (2026-05-27)

### 🐛 Fixes

* **security:** CSO findings — non-root containers + .env gitignore + actuator hardening ([7abff8f](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/7abff8f73ff9a042a5d03b81654827eb427fa981)), closes [#1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/1) [#2](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/2) [#3](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/3)
2026-05-27 16:15:25 +00:00
Александр Зимин c1a006765f chore(ui): a11y touch-targets sweep + useUserDisplay JSDoc refresh 2026-05-27 15:49:17 +00:00
semantic-release-bot 2868e8635a chore(release): v2.45.2
## [2.45.2](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.45.1...v2.45.2) (2026-05-26)

### 🐛 Fixes

* **auth:** зачистить остатки auth.nstart.space → altum.nstart.cloud ([c1aaf6a](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/c1aaf6a696050678d7b2edacde1f1150647b1a00))
2026-05-26 13:26:20 +00:00
Александр Зимин 9144b2d1d1 Merge branch 'chore/cleanup-tokensync-jsdoc' into 'main'
chore(ui): убрать упоминание TokenSync из RequireAuth JSDoc

See merge request 2-6/2-6-4/terravault/ordinis!275
2026-05-26 12:37:17 +00:00
semantic-release-bot 16559a8488 chore(release): v2.45.1
## [2.45.1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.45.0...v2.45.1) (2026-05-26)

### 🐛 Fixes

* **auth:** иерархическое расширение scope set в ScopeContext ([6977ba1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/6977ba106dbb81e9a735edafb1224f8799c47c35))
2026-05-26 12:33:43 +00:00
Zimin A.N. 03973a943e chore(ui): убрать упоминание TokenSync из RequireAuth JSDoc
TokenSync.tsx был удалён в Phase 1a (keycloak-js migration, MR !270).
В JSDoc на RequireAuth.tsx осталась ссылка на его поведение —
обновляем описание под текущую модель: apiClient request interceptor
+ ensureFreshToken на 401 (см. api/client.ts:64).

Минор-долг из checkpoint'а keycloak-js-altum-migration.
2026-05-26 15:28:24 +03:00
semantic-release-bot 90a6c1185e chore(release): v2.45.0
## [2.45.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.44.1...v2.45.0) (2026-05-26)

###  Features

* **auth:** Phase 2 — audited-users UserPicker + Tier-3 Keycloak Admin lookup ([a4ba873](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/a4ba8735d0e03b1e867c648bc8fb9ee059aa5c8f))
2026-05-26 12:09:48 +00:00
Александр Зимин f38b2b668d Merge branch 'feat/phase2-direct-kc-admin' into 'main'
feat(auth): Phase 2 — audited-users UserPicker + Tier-3 Keycloak Admin lookup

See merge request 2-6/2-6-4/terravault/ordinis!272
2026-05-26 12:01:10 +00:00
Александр Зимин a4ba8735d0 feat(auth): Phase 2 — audited-users UserPicker + Tier-3 Keycloak Admin lookup 2026-05-26 12:01:09 +00:00
semantic-release-bot bd3798ffa8 chore(release): v2.44.1
## [2.44.1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.44.0...v2.44.1) (2026-05-26)

### 🐛 Fixes

* **ui:** TS2345 в DictionaryEditorDialog[#449](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/issues/449) — narrow unknown ([8337561](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/83375610b25b2f194f1e12fc6c0b1f1cfd1c2561))
2026-05-26 11:54:07 +00:00
Александр Зимин 83375610b2 fix(ui): TS2345 в DictionaryEditorDialog#449 — narrow unknown 2026-05-26 11:48:24 +00:00
semantic-release-bot f1fcabc9da chore(release): v2.44.0
## [2.44.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.43.0...v2.44.0) (2026-05-26)

###  Features

* **auth:** Phase 1b — swap default Keycloak realm на altum ([da0f894](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/da0f8943426ae96ef483ebd65c591fbb00ddd9b5))
2026-05-26 10:21:28 +00:00
Zimin A.N. da0f894342 feat(auth): Phase 1b — swap default Keycloak realm на altum
Frontend default: https://auth.nstart.space/realms/nstarthttps://altum.nstart.cloud/auth/realms/altum. Shared SSO с altum portal.

Keycloak setup (Keycloak admin actions требуются ДО merge):
- В realm `altum` создать client `ordinis` (тип: public, standard flow)
- Redirect URIs:
    https://ordinis.nstart.cloud/*
    https://ordinis.k8s.265.nstart.cloud/*
    http://localhost:5173/*
- Web origins: те же
- Client-roles: ordinis-public, ordinis-internal, ordinis-restricted,
  admin (admin даёт RESTRICTED через ScopeContext.isAdminRole)

Backend issuerUri меняется отдельным MR в ordinis-infra
(charts/ordinis/values.yaml).

После настройки Keycloak + деплоя — старый realm auth.nstart.space/nstart
больше не используется. Все юзеры должны иметь учётки в realm altum
(вероятно brokered к nstart-id если SSO с New Start ID настроен).

171/171 tests, TSC чистый.
2026-05-26 13:11:49 +03:00
semantic-release-bot 6e5e64d558 chore(release): v2.43.0
## [2.43.0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.42.6...v2.43.0) (2026-05-26)

###  Features

* **auth:** миграция oidc-client-ts → keycloak-js (altum-pattern) ([7e435e0](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/7e435e07b7eb532dd99c03e02d9e76ecbcf9f451))
2026-05-26 08:37:11 +00:00
Александр Зимин aaae04b4ca Merge branch 'feat/keycloak-js-altum-style-auth' into 'main'
feat(auth): миграция oidc-client-ts → keycloak-js (altum-pattern, Phase 1a)

See merge request 2-6/2-6-4/terravault/ordinis!270
2026-05-26 08:31:42 +00:00
Zimin A.N. 7e435e07b7 feat(auth): миграция oidc-client-ts → keycloak-js (altum-pattern)
Phase 1a из плана: только swap библиотеки, realm/URL остаются на
auth.nstart.space/realms/nstart. Phase 2 (intgr с altum auth-service)
— отдельный эпик.

Зачем. oidc-client-ts с automaticSilentRenew триггерил бесконечный
POST /token loop когда refresh_token истекал (см. MR !269 revert,
~30+ 400'к в console, страница залипала на 403). Altum давно ушёл
с oidc-client-ts на keycloak-js по той же причине.

Новая модель.
- src/lib/keycloak.ts — singleton + initKeycloak(check-sso, PKCE) +
  ensureFreshToken(N) wrapper над kc.updateToken(). Зеркало
  altum/src/lib/keycloak.ts.
- src/stores/authStore.ts — Zustand store: {user, isAuthenticated,
  isLoading, error}. checkAuth() ждёт initKeycloak, wireKeycloakEvents()
  → onAuthSuccess/Refresh/Logout/TokenExpired re-снэпшотят store.
- src/auth/useAuth.ts — compat shim для react-oidc-context API
  (auth.user.profile, isAuthenticated, signinSilent, signinRedirect,
  signoutRedirect, removeUser, error). Все 11 callsites продолжают
  работать без правок (только сменили путь import'а).
- src/api/client.ts — request interceptor дёргает ensureFreshToken(30)
  ПЕРЕД каждым запросом + attaches Bearer ${getToken()}. 401 interceptor
  делает ensureFreshToken(0) + retry один раз. Никаких таймеров, никаких
  setAccessToken/setUnauthorizedHandler holder'ов — keycloak-js сам source
  of truth.
- src/main.tsx — убран <AuthProvider>, <TokenSync />. Просто
  useAuthStore.getState().checkAuth() на старте, потом обычный render.
- public/silent-check-sso.html — endpoint для silentCheckSsoRedirectUri.

Удалены.
- src/auth/TokenSync.tsx — не нужен, ensureFreshToken на запросах.
- src/auth/oidcConfig.ts — не нужен, конфиг внутри lib/keycloak.ts.
- npm deps: react-oidc-context, oidc-client-ts.

Добавлены deps: keycloak-js@26.2.4, zustand@5.0.13.

Tests: 171/171 passed, TSC чистый.

Migration callsites — все unchanged по семантике благодаря compat shim.
2026-05-26 11:18:30 +03:00
semantic-release-bot 273393cc7e chore(release): v2.42.6
## [2.42.6](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.42.5...v2.42.6) (2026-05-26)

###  Reverts

* уберу proactive re-auth и 403→reauth — спам Keycloak /token ([0aaae9c](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/0aaae9cb2b53c00d6c7e7cae08f8904c97f118e0))
2026-05-26 08:03:18 +00:00
Zimin A.N. 0aaae9cb2b revert: уберу proactive re-auth и 403→reauth — спам Keycloak /token
Симптом: пользователь видел ~30+ POST на Keycloak /token endpoint
с 400 Bad Request, страница залипала.

Корень. MR !267 добавил useEffect в TokenSync который на
auth.user?.expired === true делал signinSilent → catch → signinRedirect.
MR !268 добавил interceptor триггер на 403 + !accessToken.

Цикл:
1. token expires, refresh_token тоже (Keycloak SSO Session Idle прошёл)
2. useEffect видит expired=true → signinSilent → POST /token с refresh
3. Keycloak возвращает 400 invalid_grant (refresh expired)
4. catch → signinRedirect, но oidc-client-ts automaticSilentRenew=true
   параллельно тоже пытается → ещё POST /token → ещё 400
5. signinRedirect не успевает редиректнуть до следующего render'а
6. reauthing.current=false → useEffect fire'ит снова → новый signinSilent
7. → ещё 400, и так в loop ~30 раз пока что-то не разрулит

Откатываю обе ветки. Возвращаемся к v2.42.3 поведению: silent renew
автоматически пробует один раз, на failure пользователь видит 403
(или stale data из cache) и делает relogin вручную. Не идеально, но
не спамит Keycloak и не залипает на endlessly.

Backend ScopeContext admin → RESTRICTED (MR !267 backend часть)
остаётся — это безвредная правка, помогает юзерам с admin ролью
без явного INTERNAL.
2026-05-26 10:56:11 +03:00
semantic-release-bot 465a37836c chore(release): v2.42.5
## [2.42.5](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.42.4...v2.42.5) (2026-05-25)

### 🐛 Fixes

* **admin-ui:** 403 + отсутствует accessToken → trigger reauth handler ([a1e83a8](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/a1e83a86bc22988e66443b81f011f6359754053a))
2026-05-25 16:26:05 +00:00
Zimin A.N. a1e83a86bc fix(admin-ui): 403 + отсутствует accessToken → trigger reauth handler
Симптом: после ~30 мин админ видит 403 на /admin/*, перелогин чинит.

Цепочка событий:
1. access_token истекает
2. oidc-client-ts автоматический silent renew падает (refresh_token expired
   за 30 мин SSO Session Idle / iframe заблокирован)
3. auth.user становится undefined (oidc убирает после full expiry)
4. TokenSync setAccessToken(null) — accessToken в apiClient зануляется
5. Следующий запрос идёт БЕЗ Authorization header
6. Backend (ORDINIS_AUTH_REQUIRED=false) пропускает как anonymous →
   ScopeContext = PUBLIC → controller с requireInternal() кидает 403

401-handler не срабатывает на 403 → юзер залипает.

Также мой предыдущий useEffect в TokenSync (MR !267) триггерит на
auth.user?.expired === true, но если user удалён полностью —
optional-chaining вернёт undefined и useEffect не сработает.

Fix: расширил interceptor чтобы на (status === 403 && accessToken == null)
тоже вызывать unauthorizedHandler. Этот handler — single source of
truth, делает signinSilent → fallback signinRedirect.

Не цепляет legitimate 403 (когда у юзера ЕСТЬ токен но scope недостаточно —
например viewer пытается dropить INTERNAL dict). accessToken != null
в таких случаях → ветка не сработает.
2026-05-25 19:19:39 +03:00
semantic-release-bot 172a6bd9cc chore(release): v2.42.4
## [2.42.4](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.42.3...v2.42.4) (2026-05-25)

### 🐛 Fixes

* **auth:** TokenSync — проактивная re-auth при expired user ([4cd92ae](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/4cd92aeb60fcdd509e9aeedd3024cb3638949559))
* **auth:** роль admin даёт RESTRICTED scope (видит всё) ([c5adbdf](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/c5adbdf39c3e44b76028b37173ef97d0123fb7be))
2026-05-25 16:06:18 +00:00
Zimin A.N. 4cd92aeb60 fix(auth): TokenSync — проактивная re-auth при expired user
Симптом: после ~30 мин неактивности пользователь видит 403 на /admin/audit
и /admin/users. Перелогин решает.

Корень. automaticSilentRenew: true в oidcConfig должен обновлять
access_token, но падает молча когда:
- refresh_token истёк (Keycloak SSO Session Idle = 30 мин)
- silent renew iframe заблокирован 3rd-party cookies
- silentRenewError не подцеплен глобально

В этих случаях user.expired=true, accessToken=null. Дальнейшие запросы идут
БЕЗ Authorization header → backend с ORDINIS_AUTH_REQUIRED=false пропускает
как anonymous → requireInternal() видит PUBLIC scope → 403 (не 401).
401-handler в interceptor'е не срабатывает (статус не тот) → юзер залипает.

Fix. Новый useEffect в TokenSync watches auth.user?.expired. На transition
в true: signinSilent (вдруг refresh ещё жив), на failure signinRedirect.
Anti-loop ref предотвращает повторные попытки пока expired=true.

Бонусом — за компанию с MR !267 (admin → RESTRICTED) — после v2.42.4 деплоя
админ может работать сессией дольше 30 мин без 403'ов.
2026-05-25 18:54:37 +03:00
semantic-release-bot 42dede1e2b chore(release): v2.42.3
## [2.42.3](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.42.2...v2.42.3) (2026-05-25)

### 🐛 Fixes

* **admin-ui:** не резолвить «anonymous» через /admin/users/{sub}/display ([8c0b74c](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/8c0b74cbf86b936d64af8c03434af3b9c8386bfe))
2026-05-25 15:41:03 +00:00
Zimin A.N. 8c0b74cbf8 fix(admin-ui): не резолвить «anonymous» через /admin/users/{sub}/display
Backend currentUserId() возвращает литерал "anonymous" когда JWT отсутствует
(ORDINIS_AUTH_REQUIRED=false fallback). Audit / draft entries сохраняют
этот sub в БД. Frontend UserCell дёргал /admin/users/anonymous/display
→ 404 → catch → display "—". Логически ок, но в консоли DevTools мусорный
404 на каждом рендере таблицы.

Skip endpoint когда uuid === "anonymous":
- useResolveUserDisplay: enabled = uuid && uuid !== 'anonymous'
- useUserDisplay: short-circuit ветка возвращает display: 'anonymous'

UX без изменений (раньше показывал «—» с full UUID в tooltip; теперь
показывает «anonymous» без 404 в консоли).
2026-05-25 18:34:20 +03:00
semantic-release-bot 936231c8e3 chore(release): v2.42.2
## [2.42.2](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.42.1...v2.42.2) (2026-05-25)

### 🐛 Fixes

* **admin-ui:** UserPicker — порядок хуков (rules-of-hooks) ([cc85b3b](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/cc85b3b337e5beed1686cbd4728ec2ddef37cd99))
2026-05-25 15:20:41 +00:00
Zimin A.N. cc85b3b337 fix(admin-ui): UserPicker — порядок хуков (rules-of-hooks)
Early-return на TextInput-fallback стоял ДО useMemo(triggerLabel) и
useMemo(selected). React падает «rendered fewer hooks than expected»
когда количество вызовов хуков меняется между рендерами.

Reproduce: loading=true первый рендер → ВСЕ хуки выполнились (включая
triggerLabel). loading=false с data=[] второй рендер → fallback
возвращается до triggerLabel useMemo → меньше хуков → error boundary
ловит → юзер видит «Что-то пошло не так».

Перенёс все useMemo выше early-return. Логика рендера без изменений.
2026-05-25 18:13:56 +03:00
semantic-release-bot 5268df0653 chore(release): v2.42.1
## [2.42.1](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/compare/v2.42.0...v2.42.1) (2026-05-25)

### 🐛 Fixes

* **admin-ui:** UserPicker — TextInput fallback когда cache пустой ([838138a](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/838138af5eec4cafdade630fec0f3e5d1704d0b1))
* **admin-ui:** полноценные стили DayPicker'а + 1 месяц в PeriodFilter ([07a748b](https://git.nstart.cloud/2-6/2-6-4/terravault/ordinis/commit/07a748be53b592903191445e3075efefe544db82))
2026-05-25 14:56:31 +00:00
Zimin A.N. 838138af5e fix(admin-ui): UserPicker — TextInput fallback когда cache пустой
Если /api/v1/admin/users возвращает [] (cache пустой / writer только-что
рестартован / у юзера нет INTERNAL scope → 403 → catch → []), picker
показывал «Пользователи не найдены» и фильтр становился недоступен. До
MR !263 здесь был обычный TextInput, не лишаем юзера возможности вписать
UUID руками.

При isLoading=false, isError=false, data.length===0 — рендерим TextInput
с подсказкой «Список юзеров пуст — введите вручную». Backend cache
прогреется по мере того как юзеры будут делать authenticated requests
(JwtUserCaptureFilter перепишет user_display_cache); тогда picker
включится автоматически.
2026-05-25 17:50:23 +03:00
Zimin A.N. 07a748be53 fix(admin-ui): полноценные стили DayPicker'а + 1 месяц в PeriodFilter
PeriodFilter рендерил DayPicker numberOfMonths={2} со стандартными
rdp-* стилями — `.rdp-months` имеет `flex-wrap: wrap`, при недостатке
ширины два месяца стакались вертикально, ячейки большие/разреженные,
selected/hover состояний под наш accent не было. Выглядело rough.

Два фикса:

1. PeriodFilter → numberOfMonths={1}. Для audit-фильтрации одного
   месяца достаточно (presets покрывают «7д/30д/Этот месяц»; календарь
   нужен для arbitrary range). Простой layout, не зависит от ширины
   popover'а.

2. Полноценные стили `.ord-day-picker` в styles.css (~80 строк):
   - tight cells (2rem × 2rem)
   - hover state на surface-2
   - selected day → accent bg + on-accent text
   - range_middle → accent-bg, обнулённый radius
   - range_start/end → polo'асn'ое closure radius
   - today → 1px outline
   - outside-month days → mute opacity
   - nav buttons → accent цвет + hover
   - mono font на числа (JetBrains Mono), Inter на caption/weekday

Бенефит распространяется и на DateRangePicker (использует тот же класс).
flex-wrap: nowrap override — на случай если когда-то понадобится
numberOfMonths={2} в другом контексте, не будет вертикального стека.
2026-05-25 17:45:39 +03:00