From 1de07a4b96028f8eeffd3178800a16a0007ef508 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 28 Oct 2026 13:47:10 +0400 Subject: [PATCH] =?UTF-8?q?=D0=92=D0=B5=D0=B1:=20=C2=AB=D0=B7=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B8=D0=BE=D0=B4=20=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BD=D0=B5=D1=82=C2=BB=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=9F-11,=20=D1=81=D1=82=D1=80=D0=BE=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B4=D0=B8=D1=84=D1=84=D0=B0=20=D0=B1=D0=B5=D0=B7=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B7=D0=BE=D1=80=D0=B0=20(#140,=20=D1=84=D0=B8?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D0=B5=20=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D1=8C=D1=8E=20I-1,=20I-2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- web/src/modules/wiki/versions/VersionModal.test.tsx | 12 ++++++++++++ web/src/modules/wiki/versions/VersionModal.tsx | 2 ++ web/src/modules/wiki/versions/versions.css | 1 + web/src/shell/feed/FeedPage.test.tsx | 7 +++++++ web/src/shell/feed/FeedPage.tsx | 2 +- 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/web/src/modules/wiki/versions/VersionModal.test.tsx b/web/src/modules/wiki/versions/VersionModal.test.tsx index 44f6c9c..fa6a1db 100644 --- a/web/src/modules/wiki/versions/VersionModal.test.tsx +++ b/web/src/modules/wiki/versions/VersionModal.test.tsx @@ -152,6 +152,18 @@ describe("окно правки вики", () => { expect(within(d).queryByRole("button", { name: "Показать дальше" })).toBeNull(); }); + it("I-2: строки диффа — дети одного контейнера строк, «Показать дальше» вне него", async () => { + hub(() => ({ diff: "--- a\n+++ b\n+первая\n+вторая\n", next_offset: 20000 })); + await openFromFeed(); + const d = dialog(); + const l1 = await within(d).findByText("+первая"); + const l2 = within(d).getByText("+вторая"); + const box = l1.parentElement!; + expect(box).toHaveClass("wiki-version__lines"); + expect(l2.parentElement).toBe(box); + expect(box.contains(within(d).getByRole("button", { name: "Показать дальше" }))).toBe(false); + }); + it("«Показать дальше»: часть рвёт строку — строка целая и одна", async () => { hub((_v, offset) => offset === 0 ? { diff: "--- a\n+++ b\n+строка дл", next_offset: 20000 } diff --git a/web/src/modules/wiki/versions/VersionModal.tsx b/web/src/modules/wiki/versions/VersionModal.tsx index ada6e91..9613a7c 100644 --- a/web/src/modules/wiki/versions/VersionModal.tsx +++ b/web/src/modules/wiki/versions/VersionModal.tsx @@ -81,6 +81,7 @@ function VersionBody({ project, code, version, onClose, onNavigate }: Props) { {first && (
{lines.length === 0 &&

В правке нет изменений текста.

} +
{lines.map((l, i) => (
{l.kind === "add" && добавлено: } @@ -88,6 +89,7 @@ function VersionBody({ project, code, version, onClose, onNavigate }: Props) { {l.text}
))} +
{diff.hasNextPage && ( )} diff --git a/web/src/modules/wiki/versions/versions.css b/web/src/modules/wiki/versions/versions.css index 2614a3c..406a1b1 100644 --- a/web/src/modules/wiki/versions/versions.css +++ b/web/src/modules/wiki/versions/versions.css @@ -12,6 +12,7 @@ .wiki-version__page{color:var(--color-action-primary)} .wiki-version__hint{margin:0;color:var(--color-text-secondary)} .wiki-version__diff{display:flex;flex-direction:column;gap:var(--space-3);align-items:flex-start;min-width:0} +.wiki-version__lines{display:flex;flex-direction:column;align-self:stretch;min-width:0} .wiki-version-line{font-family:var(--font-mono);font-size:13px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere;min-width:0;max-width:100%;align-self:stretch} .wiki-version-line--add{color:var(--color-status-success);background:var(--color-status-success-bg)} .wiki-version-line--del{color:var(--color-status-error);background:var(--color-status-error-bg)} diff --git a/web/src/shell/feed/FeedPage.test.tsx b/web/src/shell/feed/FeedPage.test.tsx index 26b9bbe..b3d6e46 100644 --- a/web/src/shell/feed/FeedPage.test.tsx +++ b/web/src/shell/feed/FeedPage.test.tsx @@ -159,6 +159,13 @@ describe("лента изменений", () => { expect(await screen.findAllByTestId("feed-group")).toHaveLength(1); }); + it("I-1 (П-11): у вики сообщение, у Jira за период пусто — и сообщение вики, и «за период изменений нет»", async () => { + hub(() => ({ changes: [] }), () => ({ history_at: null })); + open("/app/feed?project=AWPCA"); + expect(await screen.findByText("история вики ещё не загружена — нужен eva-agent v2")).toBeInTheDocument(); + expect(await screen.findByText("за период изменений нет")).toBeInTheDocument(); + }); + it("«Ошибка одного источника»: /wiki/changes 500 — события Jira показаны, «Вики: …» и «Повторить» перезапрашивает только вики", async () => { let fail = true; const calls = hub(() => ({ changes: [ev({})] }), () => fail ? json(500, { error: "boom", detail: "сбой" }) : { changes: [wc()] }); diff --git a/web/src/shell/feed/FeedPage.tsx b/web/src/shell/feed/FeedPage.tsx index 69e525a..17d0c38 100644 --- a/web/src/shell/feed/FeedPage.tsx +++ b/web/src/shell/feed/FeedPage.tsx @@ -52,7 +52,7 @@ export function FeedPage({ project }: { project: Project }) { // группы всех выбранных источников одним списком по времени, новые сверху; при равенстве — порядок модулей (сортировка устойчива) const groups = shown.flatMap(({ m, r }) => r.groups.map((g) => ({ ...g, key: `${m.name}:${g.key}` }))) .sort((a, b) => time(b.at) - time(a.at)); - const settled = shown.length > 0 && shown.every(({ r }) => !r.pending && !r.error && !r.notice); + const settled = shown.length > 0 && shown.every(({ r }) => !r.pending && !r.error) && shown.some(({ r }) => !r.notice); // П-11 return (