From ef9ec9f46d8952e56774c90b1030ab0730cc7fca Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sat, 24 Oct 2026 11:56:58 +0400 Subject: [PATCH] =?UTF-8?q?feat(sdlc-rename):=20=D0=B1=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B4=20SDLC=20Hub=20=D0=B8=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B8?= =?UTF-8?q?=20=D1=85=D1=80=D0=B0=D0=BD=D0=B8=D0=BB=D0=B8=D1=89=D0=B0=20sdl?= =?UTF-8?q?c-hub-*=20=D1=81=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- web/e2e/screens.spec.ts | 2 +- web/index.html | 2 +- web/package-lock.json | 4 +-- web/package.json | 2 +- web/src/api/legacyStorage.test.ts | 31 +++++++++++++++++++ web/src/api/legacyStorage.ts | 18 +++++++++++ web/src/auth/LoginScreen.test.tsx | 6 ++-- web/src/auth/LoginScreen.tsx | 8 ++--- web/src/auth/token.test.ts | 6 ++-- web/src/auth/token.ts | 8 +++-- web/src/modules/jira/board/BoardPage.test.tsx | 2 +- web/src/modules/jira/board/BoardPage.tsx | 2 +- web/src/modules/jira/board/legendPref.ts | 6 ++-- web/src/modules/jira/board/status.ts | 2 +- web/src/modules/jira/board/useBoardSource.ts | 2 +- .../modules/jira/issues/IssueCard.test.tsx | 2 +- web/src/modules/jira/issues/IssueFilters.tsx | 2 +- .../modules/jira/issues/IssueModal.test.tsx | 2 +- .../modules/jira/issues/IssuesPage.test.tsx | 6 ++-- web/src/modules/jira/issues/commentsPref.ts | 5 +-- .../modules/jira/refresh/RefreshProvider.tsx | 2 +- web/src/shell/Sidebar.test.tsx | 12 +++---- web/src/shell/Sidebar.tsx | 4 +-- web/src/shell/sidebarPref.test.ts | 13 ++++++++ web/src/shell/sidebarPref.ts | 6 ++-- 25 files changed, 112 insertions(+), 43 deletions(-) create mode 100644 web/src/api/legacyStorage.test.ts create mode 100644 web/src/api/legacyStorage.ts create mode 100644 web/src/shell/sidebarPref.test.ts diff --git a/web/e2e/screens.spec.ts b/web/e2e/screens.spec.ts index a3aa7f3..f76c21c 100644 --- a/web/e2e/screens.spec.ts +++ b/web/e2e/screens.spec.ts @@ -89,7 +89,7 @@ for (const theme of ["light", "dark"] as const) { test("board-collapsed", async ({ page }) => { test.skip(w < 640, "свёртка — только на широком экране"); - await page.addInitScript(() => { localStorage.setItem("jira-hub-sidebar", "collapsed"); }); + await page.addInitScript(() => { localStorage.setItem("sdlc-hub-sidebar", "collapsed"); }); await login(page); await expect(page.locator(".board .card[data-key]").first()).toBeVisible(); await settle(page); diff --git a/web/index.html b/web/index.html index 5f2db89..9168549 100644 --- a/web/index.html +++ b/web/index.html @@ -3,7 +3,7 @@ - Хаб Jira + SDLC Hub diff --git a/web/package-lock.json b/web/package-lock.json index aed0e23..2f43358 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,10 +1,10 @@ { - "name": "jira-hub-web", + "name": "sdlc-hub-web", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "jira-hub-web", + "name": "sdlc-hub-web", "dependencies": { "@fontsource/ibm-plex-mono": "5.3.0", "@fontsource/mulish": "5.3.0", diff --git a/web/package.json b/web/package.json index 45396bb..503e2a1 100644 --- a/web/package.json +++ b/web/package.json @@ -1,5 +1,5 @@ { - "name": "jira-hub-web", + "name": "sdlc-hub-web", "private": true, "type": "module", "scripts": { diff --git a/web/src/api/legacyStorage.test.ts b/web/src/api/legacyStorage.test.ts new file mode 100644 index 0000000..84efa64 --- /dev/null +++ b/web/src/api/legacyStorage.test.ts @@ -0,0 +1,31 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { readMigrated } from "./legacyStorage"; + +describe("readMigrated", () => { + beforeEach(() => localStorage.clear()); + afterEach(() => vi.restoreAllMocks()); + + it("переносит старый ключ jira-hub-* в sdlc-hub-*", () => { + localStorage.setItem("jira-hub-token", "abc"); + expect(readMigrated("sdlc-hub-token")).toBe("abc"); + expect(localStorage.getItem("sdlc-hub-token")).toBe("abc"); + expect(localStorage.getItem("jira-hub-token")).toBeNull(); + }); + + it("при наличии обоих возвращает новое и не трогает старое", () => { + localStorage.setItem("jira-hub-token", "old"); + localStorage.setItem("sdlc-hub-token", "new"); + expect(readMigrated("sdlc-hub-token")).toBe("new"); + expect(localStorage.getItem("jira-hub-token")).toBe("old"); + }); + + it("без обоих ключей возвращает null и ничего не пишет", () => { + expect(readMigrated("sdlc-hub-token")).toBeNull(); + expect(localStorage.length).toBe(0); + }); + + it("исключение хранилища даёт null", () => { + vi.spyOn(Storage.prototype, "getItem").mockImplementation(() => { throw new Error("closed"); }); + expect(readMigrated("sdlc-hub-token")).toBeNull(); + }); +}); diff --git a/web/src/api/legacyStorage.ts b/web/src/api/legacyStorage.ts new file mode 100644 index 0000000..76d19ae --- /dev/null +++ b/web/src/api/legacyStorage.ts @@ -0,0 +1,18 @@ +// разовый перенос ключей localStorage после переименования jira-hub -> sdlc-hub: читает новый ключ, +// а если его нет — старый "jira-hub-*", переписывая значение под новым именем. Ошибки хранилища глотаем. +const NEW = "sdlc-hub-"; +const OLD = "jira-hub-"; + +export function readMigrated(key: string): string | null { + try { + const cur = localStorage.getItem(key); + if (cur !== null) return cur; + if (!key.startsWith(NEW)) return null; + const oldKey = OLD + key.slice(NEW.length); + const v = localStorage.getItem(oldKey); + if (v === null) return null; + localStorage.setItem(key, v); + localStorage.removeItem(oldKey); + return v; + } catch { return null; } +} diff --git a/web/src/auth/LoginScreen.test.tsx b/web/src/auth/LoginScreen.test.tsx index 863ccd6..9e7a954 100644 --- a/web/src/auth/LoginScreen.test.tsx +++ b/web/src/auth/LoginScreen.test.tsx @@ -18,7 +18,7 @@ describe("вход", () => { renderWithProviders(app); expect(screen.getByRole("heading", { name: "Вход в хаб" })).toBeInTheDocument(); expect(screen.queryByText("страница приложения")).not.toBeInTheDocument(); - expect(screen.getByText(/uv run jira-hub tokens/)).toBeInTheDocument(); + expect(screen.getByText(/uv run sdlc-hub tokens/)).toBeInTheDocument(); expect(screen.getByLabelText("Клиентский токен хаба")).toHaveAttribute("type", "password"); }); @@ -28,7 +28,7 @@ describe("вход", () => { await userEvent.type(screen.getByLabelText("Клиентский токен хаба"), "good-token"); await userEvent.click(screen.getByRole("button", { name: "Войти" })); expect(await screen.findByText("страница приложения")).toBeInTheDocument(); - expect(localStorage.getItem("jira-hub-token")).toBe("good-token"); + expect(localStorage.getItem("sdlc-hub-token")).toBe("good-token"); expect(fetch.mock.calls[0][0]).toBe("/settings"); }); @@ -40,7 +40,7 @@ describe("вход", () => { await userEvent.click(screen.getByRole("button", { name: "Войти" })); expect(await screen.findByRole("alert")).toHaveTextContent(/Токен не подошёл/); expect(input).toHaveValue("wrong"); - expect(localStorage.getItem("jira-hub-token")).toBeNull(); + expect(localStorage.getItem("sdlc-hub-token")).toBeNull(); }); it("кириллица или пробел — «недопустимые символы», запроса нет", async () => { diff --git a/web/src/auth/LoginScreen.tsx b/web/src/auth/LoginScreen.tsx index eb1c29a..bf85df8 100644 --- a/web/src/auth/LoginScreen.tsx +++ b/web/src/auth/LoginScreen.tsx @@ -6,9 +6,9 @@ import { setToken, TOKEN_RE } from "./token.ts"; import { useAuth } from "./useAuth.ts"; import "./login.css"; -const BAD_TOKEN = "Токен не подошёл. Проверьте его по uv run jira-hub tokens: токен могли пересоздать."; +const BAD_TOKEN = "Токен не подошёл. Проверьте его по uv run sdlc-hub tokens: токен могли пересоздать."; const BAD_CHARS = "В токене недопустимые символы: скопируйте строку после «клиентский токен:» целиком, без пробелов и кириллицы."; -const HUB_DOWN = "Хаб не отвечает: проверьте, что jira-hub запущен, и попробуйте снова."; +const HUB_DOWN = "Хаб не отвечает: проверьте, что sdlc-hub запущен, и попробуйте снова."; export function LoginScreen() { const { reason } = useAuth(); @@ -40,8 +40,8 @@ export function LoginScreen() {

Вход в хаб

-

Приложению нужен клиентский токен хаба. Его показывает команда uv run jira-hub tokens в каталоге - jira-hub на этом Mac. Токен сохранится в этом браузере.

+

Приложению нужен клиентский токен хаба. Его показывает команда uv run sdlc-hub tokens в каталоге + sdlc-hub на этом Mac. Токен сохранится в этом браузере.

{error && {error}}
diff --git a/web/src/auth/token.test.ts b/web/src/auth/token.test.ts index 574ade9..7c4d25c 100644 --- a/web/src/auth/token.test.ts +++ b/web/src/auth/token.test.ts @@ -5,7 +5,7 @@ describe("token", () => { afterEach(() => { vi.restoreAllMocks(); }); it("читает токен, сохранённый прежней доской", async () => { - localStorage.setItem("jira-hub-token", "abc"); + localStorage.setItem("sdlc-hub-token", "abc"); const t = await import("./token.ts"); expect(t.getToken()).toBe("abc"); }); @@ -15,10 +15,10 @@ describe("token", () => { const fn = vi.fn(); t.subscribe(fn); t.setToken("xyz"); - expect(localStorage.getItem("jira-hub-token")).toBe("xyz"); + expect(localStorage.getItem("sdlc-hub-token")).toBe("xyz"); t.clearToken("bad"); expect(t.getAuth()).toEqual({ token: "", reason: "bad" }); - expect(localStorage.getItem("jira-hub-token")).toBeNull(); + expect(localStorage.getItem("sdlc-hub-token")).toBeNull(); expect(fn).toHaveBeenCalledTimes(2); }); diff --git a/web/src/auth/token.ts b/web/src/auth/token.ts index bc67247..b09f8fb 100644 --- a/web/src/auth/token.ts +++ b/web/src/auth/token.ts @@ -1,13 +1,15 @@ -// клиентский токен хаба: localStorage["jira-hub-token"] (тот же ключ, что у прежней доски) и копия в памяти на случай +// клиентский токен хаба: localStorage["sdlc-hub-token"] (со старого "sdlc-hub-token" переносится при чтении) и копия в памяти на случай // закрытого хранилища. reason — почему показан экран входа: "bad" — токен не подошёл (ответ 401) -export const TOKEN_KEY = "jira-hub-token"; +import { readMigrated } from "../api/legacyStorage"; + +export const TOKEN_KEY = "sdlc-hub-token"; export const TOKEN_RE = /^[\x21-\x7e]+$/; // печатный ASCII без пробелов: иначе fetch бросит TypeError на заголовке export type LoginReason = "none" | "bad"; export interface AuthSnapshot { token: string; reason: LoginReason } const readStored = (): string => { - try { return localStorage.getItem(TOKEN_KEY) ?? ""; } catch { return ""; } + return readMigrated(TOKEN_KEY) ?? ""; }; let state: AuthSnapshot = { token: readStored(), reason: "none" }; diff --git a/web/src/modules/jira/board/BoardPage.test.tsx b/web/src/modules/jira/board/BoardPage.test.tsx index e10494c..6ab56f2 100644 --- a/web/src/modules/jira/board/BoardPage.test.tsx +++ b/web/src/modules/jira/board/BoardPage.test.tsx @@ -147,7 +147,7 @@ describe("страница доски", () => { await userEvent.click(toggle); expect(toggle).toHaveAttribute("aria-expanded", "false"); expect(legend()).toBeNull(); - expect(localStorage.getItem("jira-hub-legend")).toBe("0"); + expect(localStorage.getItem("sdlc-hub-legend")).toBe("0"); r.unmount(); page(); await screen.findByText(/задач из 9/); diff --git a/web/src/modules/jira/board/BoardPage.tsx b/web/src/modules/jira/board/BoardPage.tsx index 1abfdaf..3bbf874 100644 --- a/web/src/modules/jira/board/BoardPage.tsx +++ b/web/src/modules/jira/board/BoardPage.tsx @@ -47,7 +47,7 @@ export function BoardPage({ project }: { project: string }) { return (
В настройках хаба нет {d.missing.join(" и ")} — доска не может перевести виды работ и типы связей Jira. Задайте - словари в config.example.json и выполните uv run jira-hub init --config … или запишите их через PUT /settings. + словари в config.example.json и выполните uv run sdlc-hub init --config … или запишите их через PUT /settings.
); } diff --git a/web/src/modules/jira/board/legendPref.ts b/web/src/modules/jira/board/legendPref.ts index ca90125..09df9e0 100644 --- a/web/src/modules/jira/board/legendPref.ts +++ b/web/src/modules/jira/board/legendPref.ts @@ -1,8 +1,10 @@ // свёрнутость легенды доски: "0" — свёрнута, иначе развёрнута; ошибки хранилища глотаем -const KEY = "jira-hub-legend"; +import { readMigrated } from "../../../api/legacyStorage"; + +const KEY = "sdlc-hub-legend"; export function readLegendOpen(): boolean { - try { return localStorage.getItem(KEY) !== "0"; } catch { return true; } + return readMigrated(KEY) !== "0"; } export function saveLegendOpen(open: boolean): void { diff --git a/web/src/modules/jira/board/status.ts b/web/src/modules/jira/board/status.ts index 2537f3c..7c84ed5 100644 --- a/web/src/modules/jira/board/status.ts +++ b/web/src/modules/jira/board/status.ts @@ -12,7 +12,7 @@ export function statusText(s: BoardStatus): { text: string; warn: boolean } { case "loading": return { text: "загрузка данных хаба…", warn: false }; case "hub-down": return { text: s.fromFile ? "хаб не отвечает — на доске снимок из файла" - : s.hasData ? "хаб не отвечает — показаны прежние данные" : "хаб не отвечает: запустите хаб (jira-hub serve) и нажмите «Перечитать»", + : s.hasData ? "хаб не отвечает — показаны прежние данные" : "хаб не отвечает: запустите хаб (sdlc-hub serve) и нажмите «Перечитать»", warn: true, }; case "file-error": return { text: `файл не разобран: ${s.reason}`, warn: true }; diff --git a/web/src/modules/jira/board/useBoardSource.ts b/web/src/modules/jira/board/useBoardSource.ts index 9a3e1d3..f4edb9f 100644 --- a/web/src/modules/jira/board/useBoardSource.ts +++ b/web/src/modules/jira/board/useBoardSource.ts @@ -83,7 +83,7 @@ export function useBoardSource(dicts: Dicts | null, project: string): BoardSourc const pending = board.isPending; const emptyHub = useMemo(() => emptyModel(pending ? "Загрузка данных хаба…" - : "Нет данных: хаб не отвечает. Запустите хаб (jira-hub serve) и нажмите «Перечитать» или загрузите файл CSV из фильтра Jira."), [pending]); + : "Нет данных: хаб не отвечает. Запустите хаб (sdlc-hub serve) и нажмите «Перечитать» или загрузите файл CSV из фильтра Jira."), [pending]); const model = source.kind === "file" ? source.model : hubModel ?? emptyHub; const label = source.kind === "file" ? `${source.model.fileName} (из файла)` : board.data ? (ls ? `Хаб · данные на ${fmtStamp(ls.finished_at)}` : "Хаб · полного обновления не было") diff --git a/web/src/modules/jira/issues/IssueCard.test.tsx b/web/src/modules/jira/issues/IssueCard.test.tsx index afb82f2..0bb4390 100644 --- a/web/src/modules/jira/issues/IssueCard.test.tsx +++ b/web/src/modules/jira/issues/IssueCard.test.tsx @@ -207,7 +207,7 @@ describe("карточка задачи", () => { expect(items[0].querySelector(".body br")).not.toBeNull(); await userEvent.click(screen.getByRole("button", { name: "Скрыть" })); expect(screen.queryByText("старый")).toBeNull(); - expect(localStorage.getItem("jira-hub-comments-hidden")).toBe("1"); + expect(localStorage.getItem("sdlc-hub-comments-hidden")).toBe("1"); cleanup(); open("/issues/AURORA-9001"); expect(await screen.findByRole("button", { name: "Показать" })).toBeInTheDocument(); diff --git a/web/src/modules/jira/issues/IssueFilters.tsx b/web/src/modules/jira/issues/IssueFilters.tsx index 945de93..8cf9913 100644 --- a/web/src/modules/jira/issues/IssueFilters.tsx +++ b/web/src/modules/jira/issues/IssueFilters.tsx @@ -10,7 +10,7 @@ export const SELECTS = [ type Name = (typeof SELECTS)[number][0]; // раскрыта ли панель «Фильтры» — на время сессии вкладки; ошибки хранилища глотаем -const KEY = "jira-hub-issue-filters"; +const KEY = "sdlc-hub-issue-filters"; const readOpen = () => { try { return sessionStorage.getItem(KEY) === "1"; } catch { return false; } }; const saveOpen = (open: boolean) => { try { sessionStorage.setItem(KEY, open ? "1" : "0"); } catch { /* только в памяти */ } }; diff --git a/web/src/modules/jira/issues/IssueModal.test.tsx b/web/src/modules/jira/issues/IssueModal.test.tsx index efacdfd..02f9f15 100644 --- a/web/src/modules/jira/issues/IssueModal.test.tsx +++ b/web/src/modules/jira/issues/IssueModal.test.tsx @@ -32,7 +32,7 @@ describe("карточка окном", () => { beforeEach(() => { setToken("tok"); hub(); }); it("из списка: окно поверх списка, фон не пересоздаётся, ✕ возвращает со старым фильтром, «назад» не открывает карточку", async () => { - sessionStorage.setItem("jira-hub-issue-filters", "1"); // панель «Фильтры» раскрыта + sessionStorage.setItem("sdlc-hub-issue-filters", "1"); // панель «Фильтры» раскрыта const router = at(["/app/board", "/app/issues?sprint=AWPCA_Спринт 2"]); render(); const table = await screen.findByRole("table"); diff --git a/web/src/modules/jira/issues/IssuesPage.test.tsx b/web/src/modules/jira/issues/IssuesPage.test.tsx index ab97916..ed371f5 100644 --- a/web/src/modules/jira/issues/IssuesPage.test.tsx +++ b/web/src/modules/jira/issues/IssuesPage.test.tsx @@ -27,7 +27,7 @@ const issuesCalls = (fetch: ReturnType) => describe("список задач", () => { beforeEach(() => { setToken("tok"); sessionStorage.clear(); }); - const expanded = () => sessionStorage.setItem("jira-hub-issue-filters", "1"); + const expanded = () => sessionStorage.setItem("sdlc-hub-issue-filters", "1"); it("фильтры из адреса уходят в GET /issues; ключ ведёт на карточку", async () => { const fetch = hub(() => [row(1)]); @@ -266,11 +266,11 @@ describe("список задач", () => { await userEvent.click(screen.getByRole("button", { name: /Фильтры/ })); expect(screen.getByRole("button", { name: /Фильтры/ })).toHaveAttribute("aria-expanded", "true"); for (const n of ["Спринт", "Исполнитель", "Вид работы", "Статус Jira", "Метка", "Эпик"]) expect(screen.getByLabelText(n)).toBeInTheDocument(); - expect(sessionStorage.getItem("jira-hub-issue-filters")).toBe("1"); + expect(sessionStorage.getItem("sdlc-hub-issue-filters")).toBe("1"); }); it("панель раскрыта по sessionStorage", async () => { - sessionStorage.setItem("jira-hub-issue-filters", "1"); + sessionStorage.setItem("sdlc-hub-issue-filters", "1"); hub(() => [row(1)]); renderWithProviders(, { route: "/issues", path: "/issues" }); expect(await screen.findByLabelText("Спринт")).toBeInTheDocument(); diff --git a/web/src/modules/jira/issues/commentsPref.ts b/web/src/modules/jira/issues/commentsPref.ts index 16c0647..aab8fe4 100644 --- a/web/src/modules/jira/issues/commentsPref.ts +++ b/web/src/modules/jira/issues/commentsPref.ts @@ -1,8 +1,9 @@ import { useState } from "react"; +import { readMigrated } from "../../../api/legacyStorage"; // выбор «комментарии скрыты» — один на все карточки, в браузере (design 19); без localStorage — показаны -export const COMMENTS_HIDDEN_KEY = "jira-hub-comments-hidden"; -const read = (): boolean => { try { return localStorage.getItem(COMMENTS_HIDDEN_KEY) === "1"; } catch { return false; } }; +export const COMMENTS_HIDDEN_KEY = "sdlc-hub-comments-hidden"; +const read = (): boolean => readMigrated(COMMENTS_HIDDEN_KEY) === "1"; export function useCommentsHidden(): [boolean, (hidden: boolean) => void] { const [hidden, setHidden] = useState(read); diff --git a/web/src/modules/jira/refresh/RefreshProvider.tsx b/web/src/modules/jira/refresh/RefreshProvider.tsx index 56c8bba7..d7be62b 100644 --- a/web/src/modules/jira/refresh/RefreshProvider.tsx +++ b/web/src/modules/jira/refresh/RefreshProvider.tsx @@ -1,4 +1,4 @@ -// владелец состояния «Обновить из Jira»: один опрос пакета на всё приложение. Правила — прежние (jira-hub#20): +// владелец состояния «Обновить из Jira»: один опрос пакета на всё приложение. Правила — прежние (hub#20): // одна кнопка и один опрос (M-2), подхват незавершённого пакета после любой загрузки снимка (M-3), остановка опроса // (M-4, T10.2), только пакеты с первой командой refresh (T10.6) import { useQuery, useQueryClient } from "@tanstack/react-query"; diff --git a/web/src/shell/Sidebar.test.tsx b/web/src/shell/Sidebar.test.tsx index 6a1a216..b96e5ee 100644 --- a/web/src/shell/Sidebar.test.tsx +++ b/web/src/shell/Sidebar.test.tsx @@ -149,13 +149,13 @@ describe("боковая панель", () => { expect(await within(nav).findByRole("link", { name: "Доска связей" })).toHaveAttribute("aria-current", "page"); }); - it("«Свернуть панель» сворачивает и запоминает в jira-hub-sidebar; после перезапуска свёрнута, разделы доступны", async () => { + it("«Свернуть панель» сворачивает и запоминает в sdlc-hub-sidebar; после перезапуска свёрнута, разделы доступны", async () => { hub(); open("/app/board?project=AWPCA"); const btn = await within(bar()).findByRole("button", { name: "Свернуть панель" }); expect(btn).toHaveAttribute("aria-expanded", "true"); await userEvent.click(btn); - expect(localStorage.getItem("jira-hub-sidebar")).toBe("collapsed"); + expect(localStorage.getItem("sdlc-hub-sidebar")).toBe("collapsed"); expect(bar()).toHaveClass("is-collapsed"); cleanup(); open("/app/board?project=AWPCA"); @@ -163,12 +163,12 @@ describe("боковая панель", () => { expect(within(bar()).getByRole("button", { name: "Развернуть панель" })).toHaveAttribute("aria-expanded", "false"); expect(within(bar()).getByRole("link", { name: "Задачи" })).toHaveAttribute("title", "Задачи"); await userEvent.click(within(bar()).getByRole("button", { name: "Развернуть панель" })); - expect(localStorage.getItem("jira-hub-sidebar")).toBeNull(); + expect(localStorage.getItem("sdlc-hub-sidebar")).toBeNull(); expect(bar()).not.toHaveClass("is-collapsed"); }); it("свёрнутая: «Обновить из Jira» значком ставит пакет, событие — в role=status и подсказке", async () => { - localStorage.setItem("jira-hub-sidebar", "collapsed"); + localStorage.setItem("sdlc-hub-sidebar", "collapsed"); const h = hub(); open("/app/issues?project=AWPCA"); const btn = await within(bar()).findByRole("button", { name: "Обновить из Jira" }); @@ -180,7 +180,7 @@ describe("боковая панель", () => { }); it("свёрнутая: метка проекта видна, щелчок по ней разворачивает панель", async () => { - localStorage.setItem("jira-hub-sidebar", "collapsed"); + localStorage.setItem("sdlc-hub-sidebar", "collapsed"); hub(); open("/app/board?project=AWPCA"); const tag = await within(bar()).findByRole("button", { name: "Проект AWPCA — развернуть панель" }); @@ -201,7 +201,7 @@ describe("боковая панель на узком экране", () => { open("/app/board?project=AWPCA"); const top = await screen.findByRole("banner", { name: "Строка приложения" }); expect(within(top).getByRole("button", { name: "Меню" })).toHaveAttribute("aria-expanded", "false"); - expect(within(top).getByText("Хаб Jira")).toBeInTheDocument(); + expect(within(top).getByText("SDLC Hub")).toBeInTheDocument(); expect(within(top).getByRole("button", { name: "Обновить из Jira" })).toBeInTheDocument(); expect(screen.queryByRole("complementary", { name: "Панель приложения" })).toBeNull(); }); diff --git a/web/src/shell/Sidebar.tsx b/web/src/shell/Sidebar.tsx index c8079af..6cfdb7b 100644 --- a/web/src/shell/Sidebar.tsx +++ b/web/src/shell/Sidebar.tsx @@ -40,7 +40,7 @@ function NarrowShell(p: Props) {
- Хаб Jira + SDLC Hub {MODULES.map((m) => m.SidebarStatus && )}
@@ -71,7 +71,7 @@ function Panel({ section, project, drawer }: Props & { drawer?: { close(): void; return (