Вики: история правок — лента и дифф в MCP и вебе (#140) #141

Merged
aep merged 13 commits from feat/140-wiki-history into main 2026-10-28 13:01:47 +03:00
5 changed files with 23 additions and 1 deletions
Showing only changes of commit 1de07a4b96 - Show all commits

View File

@ -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 }

View File

@ -81,6 +81,7 @@ function VersionBody({ project, code, version, onClose, onNavigate }: Props) {
{first && (
<div className="wiki-version__diff" data-testid="wiki-version-diff">
{lines.length === 0 && <p className="wiki-version__hint">В правке нет изменений текста.</p>}
<div className="wiki-version__lines">
{lines.map((l, i) => (
<div key={i} className={`wiki-version-line wiki-version-line--${l.kind}`}>
{l.kind === "add" && <span className="visually-hidden">добавлено: </span>}
@ -88,6 +89,7 @@ function VersionBody({ project, code, version, onClose, onNavigate }: Props) {
{l.text}
</div>
))}
</div>
{diff.hasNextPage && (
<Button loading={diff.isFetchingNextPage} onClick={() => void diff.fetchNextPage()}>Показать дальше</Button>
)}

View File

@ -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)}

View File

@ -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()] });

View File

@ -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 (
<div data-testid="page-feed" className="feed-page">