Skip to content

feat(task-trackers): автокомплит карточки в модале «Приложить карточку»#245

Merged
gently-whitesnow merged 2 commits into
masterfrom
feat/attach-card-autocomplete
Jul 10, 2026
Merged

feat(task-trackers): автокомплит карточки в модале «Приложить карточку»#245
gently-whitesnow merged 2 commits into
masterfrom
feat/attach-card-autocomplete

Conversation

@gently-whitesnow

Copy link
Copy Markdown
Owner

Цель

Ушли от ввода card_id числом на глаз: теперь оператор вводит имя карточки — combobox с server-side автокомплитом (scope = выбранная доска) отдаёт релевантные подсказки, пустой фокус показывает недавно обновлённые карточки. Чистый числовой ввод остаётся коротким путём для «уже скопировал id».

Существенные изменения

  • Backend
    • Провайдер-нейтральный порт ITaskTrackerConnectionProvider.SearchCardsAsync(connection, boardId, query, limit, ct).
    • Kaiten-адаптер: GET /cards с condition=Live, board_id=<id>; при пустом query — order_by=updated, order_direction=desc + страхующая in-memory сортировка. Ошибки через ту же health-таксономию (Auth→409, Blocked→402, Offline→502).
    • BoardCardBrowserService.SearchBoardCardsAsync симметрично ListBoardCardsAsync (resolve → провайдер → health-tracking).
    • Новый эндпоинт GET /api/v1/task-trackers/{tracker}/boards/{board}/cards/search?query=&limit= (default 10, max 25). Ответ — тот же TaskTrackerBoardCardsResponse.
  • Frontend
    • useBoardCardSearchQuery(tracker, boardId, query, {limit, enabled}) — React Query поверх нового эндпоинта с staleTime: 30s, ретраи только на транзиентах.
    • CardSearchCombobox — ARIA combobox+listbox, useDebouncedValue(250ms), numeric fallback (/^\d+$/) без запросов, строка #{card_id} · {title} + column_title.
    • AttachCardModal подключает combobox под лейблом «ID карточки» через aria-labelledby (существующие e2e/RTL тесты продолжают ловить поле по getByLabelText).

Принятые решения

  • Live-proxy без локального кэша (MVP; TTL добавим при явной нагрузке).
  • Клиентский sort как страховка только для empty-query — Kaiten query ранжирует по релевантности сам.
  • Тесты search-эндпоинта вынесены в отдельный класс BoardCardSearchEndpointTests, чтобы уложиться в бюджет публичных членов на тип (12).

Ограничения

  • Клавиатурная навигация по списку (arrow-up/down/enter) не реализована — MVP держит фокус мыши/touch.
  • Мульти-бордовый поиск, фильтр «мои активные», фильтры по колонке/статусу — вне scope, в бэклог.

Как проверить

  • /settings → подключить Kaiten и выбрать доску.
  • Открыть интент → «Приложить карточку»: фокус на пустом поле → появляется топ карточек по updated_at.
  • Ввести текст (например, «bug») → через ~250ms обновляется список server-side.
  • Ввести чистое число (например, 777) → сетевого запроса нет, вместо списка — хинт «Приложить карточку по id #777», submit кладёт card_id=777.
  • pnpm --filter web test, dotnet test, python3 scripts/quality/verify.py --fast — зелёные (проверено локально).

liapota added 2 commits July 10, 2026 14:22
Решения:
- Новый эндпоинт GET /task-trackers/{tracker}/boards/{board}/cards/search
  (провайдер-нейтральный порт SearchCardsAsync на ITaskTrackerConnectionProvider).
  Пустой query → топ по updated_at desc, ввод текста → live-proxy в трекер.
  Лимит клампится на бэке (default 10, max 25).
- Kaiten-адаптер прокидывает order_by=updated + order_direction=desc и condition=Live,
  плюс страхующая in-memory сортировка на случай, если трекер отдаст не в том
  порядке. Ошибки маппятся через тот же health-классификатор, что и list.
- Фронт: CardSearchCombobox с ARIA-паттерном (combobox+listbox), debounce 250ms,
  fallback на чисто числовой ввод (клавиатурный short-path без запросов).
- Тесты эндпоинта вынесены в отдельный класс BoardCardSearchEndpointTests,
  чтобы вписаться в бюджет публичных членов на тип (12).

Отброшено:
- TTL-кэш поиска на бэке — MVP live-proxy, ускорим при явной нагрузке.
- Клиентская фильтрация «мои активные» — требует /users/current и меняет UX,
  вне scope этого прохода.
- Мульти-бордовый поиск и фильтры по колонке/статусу — отложено в бэклог.

Ограничения:
- Kaiten `query`-фильтр без явного контракта по сортировке при непустом query —
  полагаемся на серверный ранжир, доп. клиентский sort включаем только для
  пустого запроса.
- Combobox без клавиатурной навигации по списку (arrow-up/down) — MVP ставит
  фокус мыши/touch, добавим при UX-доработке.
Решения:
- boxClassName: max-w-md → w-full max-w-xl overflow-visible, чтобы список
  подсказок не резался краем modal-box и вмещал длинные заголовки карточек.
- Дропдаун combobox поднят до z-[60] и max-h-80, чтобы стабильно всплывал над
  панелью и оставался прокручиваемым при полном топ-10.

Отброшено:
- Портал списка в document.body — оверлей модалки уже z-50, а modal-box с
  overflow-visible пускает absolute-элемент наружу; лишний портал добавил бы
  синхронизацию позиции при ресайзе.

Ограничения:
- max-h-80 (20rem) — визуально комфортно на десктопе; на мобильном модал уже
  прижат к низу экрана, доп. адаптация не в скоупе прохода.
@gently-whitesnow
gently-whitesnow force-pushed the feat/attach-card-autocomplete branch from d21b60e to 1dd9e0c Compare July 10, 2026 11:26
@gently-whitesnow
gently-whitesnow merged commit 1bcb22a into master Jul 10, 2026
1 check passed
@gently-whitesnow
gently-whitesnow deleted the feat/attach-card-autocomplete branch July 10, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants