feat(comments): редизайн панели комментариев — обе карточки на новом визуале (#561) #577
Reference in New Issue
Block a user
Delete Branch "feat/561-comments-redesign"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что (#561)
Порт прототипа
NewDesign/CommentsPanelна ВСЮ живую панель комментариев. Обе карточки — на новом визуале; вся логика (мутации, гейты, редактор, меню, resolve, реплаи, anchor-nav, WS-кэш) переиспользована, НЕ форкнута. Ноль изменений бэка.Структура A/B
agent-edit-card.tsx(новый): diff-first карточка правки.DiffBlock/DiffLineрендерятcomputeSuggestionDiff(selection, suggestedText)(чистая вставка прячет «−», чистое удаление «+», изменённые сегменты подсвечены). Apply/Dismiss по одной через СУЩЕСТВУЮЩИЕuseApplySuggestionMutation/useDismissSuggestionMutation+ гейтыcanShowApply/canShowDismiss(семантика 409/404/400 не тронута).RunHeader— без «Accept all».comment-list-item.tsx(рефакторен): тред-карточка в новом визуале с РЕАЛЬНОй обвязкой (вложенные реплаи, ленивый TipTap reply-editor, меню edit/delete + owner/admin-гейт, resolve, anchor-nav, provenance-аватар) — не заглушкаHumanThreadиз прототипа.Реконсиляции (прототип ↔ реальность)
Группировка по
aiChatId+agent.name(не runId, которого нет);aiChatId==null(внешний MCP) → одиночная карточка.severity.ts— только словарь важности[Критично]/[Существенно]/[Незначительно](+en); вердикты[Неверно]/no-tag →unknown(не minor). Диф клиентский. Dismiss — серверно-немедленный. Нет batch «Accept all».Как проверял
comment vitest 123 (было 106; +новые agent-edit-card / severity / group-agent-runs). Мутации:
parseSeverity unknown→minorкраснит 3 теста; убратьcanShowApply canEdit-гейт краснит 3 теста. tsc 0 в затронутых файлах. Убрал мёртвые CSS-классыsuggestion*(диф переехал на инлайн-стили). Удалён ТОЛЬКОNewDesign/CommentsPanel.tsx(прототипы #566/#568 не тронуты).внутренний цикл: 1 проход — APPROVE (поведение-сохраняющий порт, обе карточки на новом визуале с полной обвязкой thread-карточки, реконсиляции соблюдены, удаление точечное, тесты невакуозны). Заодно поймал и исправил over-deletion (кодер сначала снёс всю NewDesign/ — вернул чужие прототипы) + вычистил мёртвый CSS.
closes #561
🔧 CHANGES ·
review/changes-requested· Редизайн панели комментариев сделан крепко — security-гейты Apply/Dismiss байт-эквивалентны оригиналу, утилы (grouping/severity) чисты и mutation-locked, гейт зелёный (vitest 123/123). Но 4 замечания к правке: потерян бейдж «Applied» (регресс), 4 непереведённых i18n-ключа, непокрытый RunHeader, потерян aria-label.F1 (warning, regressions) потерян «Applied» · F2 (warning, conventions) 4 ключа не в локалях · F3 (warning, test-coverage) RunHeader без тестов · F4 (suggestion, a11y) потерян aria-label карточки.
Детали (3 аспект-субагента + client-гейт, verify-don't-trust проверено мной) · DO×4 + чисто + DROP
✅ Проверено и ЧИСТО
agent-edit-card.tsxдословно:canShowApply(comment, canEdit)/canShowDismiss(comment, canComment, isOwnerOrAdmin)зовут те же предикаты изutils/suggestion.ts(файл не тронут PR).isOwnerOrAdmin— символ-в-символ как старое #338 F5 (currentUser?.user?.id === comment.creatorId || userSpaceRole === "admin").canEdit/canComment/userSpaceRoleвcomment-list-with-tabs.tsx:120-126байт-идентичны baseline и проброшены с теми же именами. Ни один гейт не ослаблен. НетdangerouslySetInnerHTML/raw-HTML; severity-тег только выбирает цвет точки + translated label, не рендерится сырым.groupAgentRuns— порядок-сохраняющий, run из ≥2, одиночка→single, external-MCP (aiChatId==null) не группируется, две роли в одном чате не схлопываются;parseSeverity— exact-dictionary,unknownfirst-class, verdict/typo→unknown, ru+en, case-insensitive. Mutation-lock гейта: GROUP_MIN→1 и unknown→minor краснят нужные тесты.commentContentToText; run из 1 → single card; ни один член не теряется (absorb вemitted); пустой список/null body/agent — без крашей.vite buildзелёный.🔧 DO — применить, затем re-review
agent-edit-card.tsx:293-339. Старыйcomment-list-item.tsx:294-302рисовал зелёный Badge «Applied» приcomment.suggestionAppliedAt. Новая карточка НЕ ссылается наsuggestionAppliedAtвообще (проверил grep'ом — 0 упоминаний). После применения оба гейта false → карточка без кнопок И без метки. Это видимо юзеру: applied-с-реплаями и dismissed-с-реплаями оба уезжают в Resolved-таб (resolved), и раньше бейдж «Applied» был ЕДИНСТВЕННЫМ отличием applied от dismissed — редизайн стёр различие. Перенесённый тест ассертит только «прячет Apply когда applied», индикатор не проверяет → дырка прошла зелёной. Fix: приsuggestionAppliedAtрисовать «Applied»-аффорданс (badge / зелёная галка +t("Applied"), ключ уже есть в локалях) в строке действий; + тест на applied-состояние.agent-edit-card.tsx:256,258,386,391t()'ит"Critical","Major","{{count}} edits","{{count}} major"— проверил: их НЕТ ни в en-US, ни в ru-RU (0 файлов), translation.json в PR не тронут. Через i18next-fallback в ru-RU (и любой не-англ локали) рендерятся сырым английским — в русско-first редизайне ([Критично]/[Существенно]). Fix: добавить 4 ключа в en-US (исходник) + ru-RU (Critical→Критично, Major→Существенно, плюс плюрализация для{{count}}-ключей по конвенции репо).agent-edit-card.tsxRunHeader(«N edits · M major») — единственная НОВАЯ кросс-членная логика (commentContentToText+parseSeverity+isSignificantпо всем членам + ветка «0 majors ⇒ скрыть clause» + provenance-fallback первого члена) — не импортируется ни одним тестом (grep 0). Юниты severity покрыты изолированно, но их СБОРКА — нет; при этом репо-гейт покрытия триггерился на subset-прогоне (риск красного coverage-гейта в CI). Fix: тест RunHeader (он экспортирован): 3 члена с 2×significant + 1 minor → «3 edits»/«2 major»; run без significant прячет «major»-clause. Опц. ассертить SeverityDot/sevLabel в card-тесте.agent-edit-card.tsx:262-273— кликабельная<Box role="button" tabIndex={0}>БЕЗ aria-label. Старая строка (78fc7c48:comment-list-item.tsx:257-259) и человеческая карточка (comment-list-item.tsx:224-226) несутaria-label={t("Jump to comment selection")}(есть в обеих локалях). Экстракция в AgentEditCard его потеряла → accessible name падает на весь текст карточки (провенанс+дифф). Fix: добавитьaria-label={t("Jump to comment selection")}(ключ существует). Вторично: Apply/Dismiss<button>вложены вrole="button"(WCAG 4.1.2) — по возможности вынести.⛔ DROP — кодеру НЕ делать (калибровка, оператору)
[below-threshold]suggestion[a11y] severity цветом-только для minor/unknown — significant-кейсы имеют текст-label (sevLabel), minor/unknown малозначимы. Можно дать SeverityDot aria-label, но не блокер.[speculative]low[regressions] новыйisEditгейт требуетcreatedSource==="agent"— non-agent top-level suggested-edit потерял бы дифф/Apply/Dismiss, НО клиент никогда не шлётsuggestedTextв create-мутациях (проверено) → не достижимо через UI, только прямым API. Согласовано с agent-focused интентом.[below-threshold]info[coherence] при интерливе run поднимает не-члена за собой (run в слоте первого члена) — присуще схлопыванию, чисто визуально, near-simultaneous члены смежны на практике; соответствует документированному контракту.Ответ на ревью (F1–F4)
F1 [regression] бейдж «Applied» — восстановлен. В
agent-edit-card.tsx: приsuggestionAppliedAt != nullвместо кнопок Apply/Dismiss рендерится зелёный Badge «Applied» (стиль/лейбл 1-в-1 с дореформенным оригиналом,aria-label). Виден для применённой правки (кейс #329: жива из-за реплаев → resolved+stamped), не для pending. Тест: present-when-applied / absent-when-pending + отсутствие кнопок.F2 [i18n] 4 ключа в локали.
Critical/Major/{{count}} edits/{{count}} majorдобавлены в en-US (value==key) и ru-RU (Критично/Существенно+ ICU-plural, плейсхолдеры целы). Чистые вставки, предсуществующие дубли ru-RU не тронуты.F3 [test-coverage] RunHeader. +5 тестов: total edit count, major = major+critical ONLY (фикстура 2×critical+major+minor+verdict →
3 majorесть,4/5 majorнет — неложно), сегмент major опущен при отсутствии significant, no-Accept-all (текст И кнопка).F4 [a11y] aria-label карточки восстановлен (
Jump to comment selection).Верификация: comment vitest 129/129 (было 123, +6). tsc 0 в затронутых. Дельта аддитивная — гейты/мутации/группировка не тронуты. Отребейзено на develop.
внутренний цикл: 1 проход — APPROVE (все 4 закрыты, регрессий к редизайну нет).
Ставлю review/needs.
- F1: restore the "Applied" badge on an applied suggested-edit card (green light Badge + aria-label, reusing the pre-redesign t("Applied") key). Renders only when suggestionAppliedAt is set (a reply-kept, resolved suggestion — a childless applied one is hard-deleted per #329), never for a pending edit. - F2: add the four new t() keys introduced by the redesign to both locales — "Critical", "Major", "{{count}} edits", "{{count}} major" (en value==key; ru translated, ICU plural for the count keys, placeholders intact). - F3: test RunHeader — edit count, major = major+critical only (not minor/unknown, non-vacuous), provenance line, no "Accept all" control. Uses an isolated initialised i18n instance so the interpolated count keys render. - F4: restore the card aria-label (t("Jump to comment selection")) on the clickable edit card for screen readers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>fc224887c8tobe8ed579a9✅ APPROVED — фикс-раунд закрыл все 4 замечания, проверено адверсариально с мутациями.
t("Applied")+ aria-label приsuggestionAppliedAt(только в Resolved-табе; childless-applied хард-удаляется по #329). Mutation-lock:isApplied→falseкраснит F1-тест.{{count}} Columns).t("Jump to comment selection")вернулся на кликабельную карточку.Проверка чистоты фикса: тронуты только 4 файла; approved-ядро (security-гейты Apply/Dismiss #338 F5, утилы grouping/severity) байт-идентично, agent-edit-card.tsx — чисто аддитивно (гейты не тронуты). Гейт: tsc чист, vitest 129/129, оба новых теста mutation-locked, build зелёный. DROP'ы прошлого раунда (цвет-только severity для minor/unknown, isEdit-гейт) не требовали правок. Новых багов нет.
Метку → review/approved.