33 KiB
Доработки «Бэклога» и «Спринта» (#112) — план реализации
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: фильтры, свёртка, панель эпиков, выбор спринтов, скрытие колонок, значки типов и доска во всю высоту окна на страницах «Бэклог», «Спринт», «Kanban» веб-приложения sdlc-hub — только просмотр.
Architecture: только фронт (web/src/modules/jira/agile/), данные — прежний GET /agile. Фильтры — чистая
модель filters.ts + запоминание agilePref.ts + хук useAgileView; страницы и компоненты только рисуют. Общие
части — панель фильтров AgileToolbar, меню ColumnsMenu, BoardColumns.
Tech Stack: React 19 + TypeScript + Vite, TanStack Query, Vitest + Testing Library, Playwright; UI-кит
web/src/ui, токены дизайн-системы AURA.
Ветка: feat/112-agile-web-polish (worktree .wt/agile-polish).
Spec: openspec/changes/agile-web-polish/ (требование «Спринты и бэклог» в specs/web-app/spec.md, решения —
design.md, рулинги дизайна R-1…R-13; рулинги контроллера — с R-14).
Global Constraints
- Веб только смотрит: MUST NOT появляться действий, меняющих Jira; ни одна кнопка не ставит команд.
- Сервер, API, схема, агент, MCP — не меняются (никаких правок вне
web/иopenspec//docs/, кроме сидаweb/scripts/seed-hub.py). - Ключ хранилища — ровно
sdlc-hub-agile; JSON{ "<метка>": { "backlog"|"sprint"|"kanban": AgileView } }; поиск (q) и выбор спринтов не хранятся; любая ошибка хранилища — значения по умолчанию, без исключения наружу. - Тексты интерфейса — дословно из спеки: «Ключ или тема», «Исполнитель», «все», «Без исполнителя», «Скрыть выполненные», «Сбросить фильтры», «Эпики», «Все задачи», «Без эпика», «Эпик», «Колонки», «Спринты», «показано K», «Нет задач», «Нет задач по фильтрам», «Нет активного спринта», «Без колонки».
- Стили — только токены дизайн-системы (как в
agile.css), без новых цветов-литералов. - Работа только в worktree
/Users/andrey.epifancev/projects/jira-bridge/sdlc-hub/.wt/agile-polish: никаких записей в основной checkout и в другие репозитории (O-6 #108); никаких команд, ждущих stdin (cat > файлбез heredoc и т.п.). - Зелёный =
make checkцеликом (pytest +npm run lint+npm test) иcd web && npm run e2eцеликом.
Review Focus
- Задача в двух выбранных спринтах (перенос из активного в будущий) — на доске одна карточка, не две → тест в Task 2
(
sprintIssues) и Task 6. - Сохранённое значение, которого больше нет (исполнитель ушёл, эпик закрыт и пропал, колонку переименовали в
Jira) — значение остаётся видимым и снимаемым, страница не пустеет молча → тесты в Task 2 (
assigneeOptions), Task 5, Task 7. - Испорченное хранилище (
sdlc-hub-agile="oops",{"AWPCA": 5}, полеcollapsed: "x",setItemбросает) — страница открывается со значениями по умолчанию → тесты в Task 2. - Проект сменён на открытой странице — фильтры другого проекта не протекают (страница пересоздаётся по
keyпроекта, состояние читается по метке) → тест в Task 4. - Длинная колонка и узкое окно — 900 px: страница без горизонтальной прокрутки, доска прокручивается внутри, полоса прокрутки доски в окне; 2560 px — колонки используют ширину окна → e2e в Task 8.
Task 0: Окружение worktree (без коммита)
cd /Users/andrey.epifancev/projects/jira-bridge/sdlc-hub/.wt/agile-polish && uv sync && (cd web && npm ci)make check— зелёный (база до правок; запомнить число тестов в ledger).
Task 1: Формат SP и значки типов
Files:
- Modify:
web/src/modules/jira/agile/model.ts(fmtSp, новоеtypeKind) - Modify:
web/src/modules/jira/agile/TypeIcon.tsx,web/src/modules/jira/agile/agile.css - Modify:
web/src/ui/icons.tsx(новые символы) - Test:
web/src/modules/jira/agile/model.test.ts, новыйweb/src/modules/jira/agile/TypeIcon.test.tsx
Interfaces:
-
Produces:
fmtSp(n: number | null): string;type TypeKind = "epic" | "story" | "task" | "bug" | "subtask" | "other";typeKind(type: string | null): TypeKind;isEpic(i: { issue_type: string | null }): boolean— всё вmodel.ts. Значки:IconBookmark,IconCircle,IconSquares,IconDotвweb/src/ui/icons.tsx. -
Step 1: тесты.
model.test.ts:fmtSp(null) === "—",fmtSp(3) === "3",fmtSp(0.1 + 0.2) === "0.3",fmtSp(2.5) === "2.5",fmtSp(1/3) === "0.33",fmtSp(0) === "0".typeKind: «Эпик», «epic», «Фича» →epic; «История», «Story» →story; «Задача», «Task» →task; «Ошибка», «BUG» →bug; «Подзадача», «Sub-task», «Subtask» →subtask;null,"", «Риск» →other.TypeIcon.test.tsx: для каждого вида —role="img"сaria-label= исходное имя типа (дляnull— «Задача» не подставлять:aria-label="Тип не указан"), классagile-type--<kind>. -
Step 2:
cd web && npx vitest run src/modules/jira/agile/model.test.ts src/modules/jira/agile/TypeIcon.test.tsx— FAIL. -
Step 3: реализация.
fmtSp:Number(n.toFixed(2))→String(M-6).typeKind— сравнение без учёта регистра со списками имён из спеки. Символы вicons.tsxтем жеmake(...): закладка, круг, два квадрата, точка; эпик — существующийIconCritical(молния), задача —IconCheck.TypeIcon:<span className="agile-type agile-type--<kind>">— квадрат 16 px сborder-radius:var(--radius-xs), фон — токен вида (эпик--k-ui, история--color-status-success, задача и подзадача--color-action-primary, ошибка--color-status-error, прочее —--color-text-secondary), символ 12 px цвета--color-text-on-primary. Контраст символа проверить в светлой и тёмной теме; не хватает — рулинг с выбранным токеном, не литерал. -
Step 4: тот же vitest — PASS;
npm run lint— PASS. -
Step 5: коммит
feat(web): значки типов по образцу Jira и формат SP (#112, M-6).
Task 2: Модель фильтров и запоминание
Files:
- Create:
web/src/modules/jira/agile/filters.ts,web/src/modules/jira/agile/agilePref.ts - Test:
web/src/modules/jira/agile/filters.test.ts,web/src/modules/jira/agile/agilePref.test.ts
Interfaces:
-
Consumes:
isEpic,typeKind(Task 1); типыAgileIssue,AgileSprint,AgileResponse(../api/types.ts). -
Produces (
filters.ts):type AgilePage = "backlog" | "sprint" | "kanban"interface AgileView { assignee: string; epic: string; hideDone: boolean; collapsed: string[]; hiddenColumns: string[]; epicsPanel: boolean }const DEFAULT_VIEW: AgileView={ assignee: "", epic: "", hideDone: false, collapsed: [], hiddenColumns: [], epicsPanel: true }const NONE = "-"— значение «Без исполнителя» / «Без эпика»interface IssueFilter { q: string; assignee: string; epic: string; hideDone: boolean }matches(i: AgileIssue, f: IssueFilter): boolean— И всех условий;q— подстрока без учёта регистра вkeyилиsummary(пробелы по краямqотбрасываются)hasFilters(f: IssueFilter): booleantype Opt = { value: string; label: string }assigneeOptions(issues: AgileIssue[], current: string): Opt[]—["", "все"],[NONE, "Без исполнителя"], затем уникальные исполнители поlocaleCompare("ru");current, которого нет, добавляется в конец с подписью = значениюinterface EpicEntry { key: string; title: string; count: number; done: boolean }epicEntries(d: AgileResponse): EpicEntry[]— по спеке: строки-эпики из всех спринтов и бэклога поrank(без повторов), затем ключи изepic_key, строк которых нет, по ключу (title= ключ,done= false);count— задачи-не-эпики с этимepic_keyв активных, будущих спринтах и бэклоге (без повторов по ключу)byRank(a: AgileIssue, b: AgileIssue): number—rankстрокой,nullв конце, затем поkeysprintIssues(sprints: AgileSprint[]): AgileIssue[]— объединение без повторов поkey, сортировкаbyRankselectableSprints(sprints: AgileSprint[]): AgileSprint[]— активные (в порядке входа), затем будущие поstart_date(черезjiraDate), без даты — в концеparseSprintIds(param: string | null, sprints: AgileSprint[]): number[]— id из"101,102", только средиselectableSprints, порядокselectableSprints; пусто → id всех активных
-
Produces (
agilePref.ts):const AGILE_KEY = "sdlc-hub-agile";readView(label: string, page: AgilePage): AgileView;saveView(label: string, page: AgilePage, v: AgileView): void(не трогает другие страницы и проекты в JSON). -
Step 1: тесты
filters.test.ts(фабрикиiss/sprint— как вBacklogPage.test.tsx):matchesпо каждому условию и их И (q: " aurora-1 "находитAURORA-1иAURORA-10;q: "тема"— по теме;assignee: NONE— толькоnull;epic: NONE— толькоepic_key === null;hideDone);hasFiltersдля пустого и каждого поля;assigneeOptions— порядок, «Без исполнителя», ушедшийcurrentв конце;epicEntriesна данных сценария «Фильтр по эпику» спеки (AURORA-10: 3 в бэклоге + 2 в активном →count5), эпик, на который ссылаются, но строки нет, — в конце сtitle= ключ, задачи прошлых спринтов не считаются;sprintIssues— задача в двух спринтах одна,rank: nullв конце;selectableSprints— закрытые отброшены, будущий без даты последним;parseSprintIds—"102,999"→[102],"abc"→ все активные,null→ все активные, будущий"103"→[103]. -
Step 2: тесты
agilePref.test.ts: нет ключа →DEFAULT_VIEW; записьAWPCA/backlogне меняетAWPCA/sprintиSTOCKS/backlog; мусор:"oops","[1]",{"AWPCA": 5},{"AWPCA":{"backlog":{"collapsed":"x","hideDone":"yes"}}}→ по полю значения по умолчанию (collapsed: [],hideDone: false), годные поля сохраняются;localStorage.setItemбросает (vi.spyOn(Storage.prototype, "setItem")) —saveViewне бросает;getItemбросает —readView→DEFAULT_VIEW. -
Step 3:
npx vitest run src/modules/jira/agile/filters.test.ts src/modules/jira/agile/agilePref.test.ts— FAIL. -
Step 4: реализация по Interfaces; разбор хранилища — поле за полем с проверкой типа (строка, булево, массив строк).
-
Step 5: тот же vitest — PASS;
npm run lint— PASS. -
Step 6: коммит
feat(web): модель фильтров экранов доски и их запоминание (#112).
Task 3: Хук состояния и панель фильтров
Files:
- Create:
web/src/modules/jira/agile/useAgileView.ts,web/src/modules/jira/agile/AgileToolbar.tsx - Modify:
web/src/modules/jira/agile/agile.css - Test:
web/src/modules/jira/agile/AgileToolbar.test.tsx
Interfaces:
-
Consumes: Task 2 целиком.
-
Produces:
useAgileView(label: string, page: AgilePage): { view: AgileView; set(patch: Partial<AgileView>): void; q: string; setQ(v: string): void; filter: IssueFilter; reset(): void }—setпишет в хранилище (saveView) вне функции-обновителя (как T8.1 #69);resetочищаетq,assignee,epic,hideDoneи сохраняет остальное.AgileToolbar({ filter, setQ, set, onReset, assignees, showHideDone, children }: { filter: IssueFilter; setQ(v: string): void; set(patch: Partial<AgileView>): void; onReset(): void; assignees: Opt[]; showHideDone: boolean; children?: ReactNode })—PanelсSearchInput label="Поиск по ключу или теме" placeholder="Ключ или тема",Select aria-label="Исполнитель", приshowHideDone—Checkbox label="Скрыть выполненные", слотchildren(кнопка «Эпики», выбор спринтов, меню «Колонки»), кнопка «Сбросить фильтры» только приhasFilters(filter). Без кнопок, ставящих команды.
-
Step 1: тесты
AgileToolbar.test.tsx(рендер с хуком в обёртке): ввод в поиск меняетfilter.q; выбор исполнителя сохраняется вlocalStorage["sdlc-hub-agile"]по метке и странице,q— нет; «Сбросить фильтры» появляется после ввода и снимает всё;showHideDone={false}— флажка нет; повторный монтаж с той же меткой и страницей — исполнитель и флажок восстановлены. -
Step 2:
npx vitest run src/modules/jira/agile/AgileToolbar.test.tsx— FAIL. -
Step 3: реализация; стили
.agile-toolbar(flex-wrap, gap--space-3, поиск растягивается) вagile.css. -
Step 4: тот же vitest — PASS;
npm run lint— PASS. -
Step 5: коммит
feat(web): панель фильтров экранов доски (#112).
Task 4: «Бэклог»: фильтры, свёртка секций, без строк эпиков
Files:
- Modify:
web/src/modules/jira/agile/BacklogPage.tsx,web/src/modules/jira/agile/agile.css - Test:
web/src/modules/jira/agile/BacklogPage.test.tsx
Interfaces:
-
Consumes:
useAgileView(label, "backlog"),AgileToolbar,matches,isEpic,assigneeOptions(Tasks 1–3). -
Produces:
SprintSection/секция «Бэклог» принимаютcollapsed: boolean; onToggle(): void; shown: AgileIssue[]— Task 5 добавляет фильтр эпика через тот жеfilter. -
Step 1: тесты (дописать в
BacklogPage.test.tsx, существующие оставить зелёными):- заголовок секции — кнопка с
aria-expanded="true"; щелчок —false, задач секции нет, итоги видны; после повторного монтажа (unmount+open) секция свёрнута (сценарий «Свёрнутый активный спринт»); свернуть можно и будущий, и «Бэклог»; - эпик (
issue_type: "Фича") в бэклоге и в спринте — строкой не показан; «N задач» секции «Бэклог» его не считает; - «Скрыть выполненные» на спринте из 10 задач (4 выполнены,
count: 10): 6 строк, «10 задач» и «показано 6»; прошлый спринт раскрыт — все его задачи (сценарий «Скрыть выполненные»); - поиск «AURORA-50» — в «Бэклоге» одна строка, в секции спринта «Нет задач по фильтрам»;
- смена проекта (Review Focus 4): исполнитель выбран у
AWPCA, открыт тот же адрес с другим scrum-проектом — исполнитель «все». - «Бэклог только смотрит»: на странице нет элементов с
draggable, все кнопки — свёртка, панель фильтров или раскрытие (перечислить поgetAllByRole("button")и их именам).
- заголовок секции — кнопка с
-
Step 2:
npx vitest run src/modules/jira/agile/BacklogPage.test.tsx— новые FAIL. -
Step 3: реализация. Видимые задачи секции =
issues.filter(i => !isEpic(i) && matches(i, f)); для прошлых спринтовhideDoneне применяется ({...f, hideDone: false}). «показано K» — когдаshown.lengthменьше числа задач-не-эпиков секции. Заголовок —<button className="agile-section__toggle" aria-expanded aria-controls>сIconChevronDown/IconChevronUp; id секции вcollapsed—String(sprint.id)и"backlog". -
Step 4: тот же vitest — PASS;
npm run lint— PASS. -
Step 5: коммит
feat(web): «Бэклог» — фильтры, свёртка секций, эпики не строками (#112).
Task 5: Панель «Эпики» на «Бэклоге»
Files:
- Create:
web/src/modules/jira/agile/EpicsPanel.tsx - Modify:
web/src/modules/jira/agile/BacklogPage.tsx,web/src/modules/jira/agile/agile.css - Test:
web/src/modules/jira/agile/BacklogPage.test.tsx
Interfaces:
-
Consumes:
epicEntries,EpicEntry,NONE,useAgileView(Task 2–3), страница из Task 4. -
Produces:
EpicsPanel({ entries, value, onChange, hideDone }: { entries: EpicEntry[]; value: string; onChange(v: string): void; hideDone: boolean })иEpicSelectс теми же пропсами (Select aria-label="Эпик": «Все задачи», эпики, «Без эпика»). -
Step 1: тесты:
- сценарий «Фильтр по эпику» спеки дословно (3 + 5 в бэклоге, 2 в спринте; выбран
AURORA-10→ в спринте 2 и «показано 2», в «Бэклоге» 3, строки эпика нет, у пункта в панели 5); - пункт — кнопка с
aria-pressed; повторный щелчок по выбранному — «Все задачи» (aria-pressed="true"); - «Без эпика» — только задачи с
epic_key: null; - эпик, на который ссылаются, но строки нет, — пункт с ключом; фильтр по нему работает;
- «Скрыть выполненные»: выполненный эпик пропадает из панели, кроме выбранного (Review Focus 2);
- сохранённый эпик, которого нет в данных, остаётся выбранным пунктом (по ключу), секции — «Нет задач по фильтрам»;
- кнопка «Эпики» в панели фильтров (
aria-pressed) скрывает и показывает панель, состояние переживает повторный монтаж; - фильтр эпика применяется и к задачам прошлого спринта.
- сценарий «Фильтр по эпику» спеки дословно (3 + 5 в бэклоге, 2 в спринте; выбран
-
Step 2: vitest файла — новые FAIL.
-
Step 3: реализация. Раскладка
.agile-backlog: сетка240px minmax(0,1fr)(без панели — одна колонка); при@container page (max-width: 899px)панель скрыта, в панели фильтров показанEpicSelect(на широком — скрыт); кнопка «Эпики» на узком скрыта. Пункт: тема (или ключ), ключ моноширинным, число. -
Step 4: vitest файла — PASS;
npm run lint— PASS. -
Step 5: коммит
feat(web): панель «Эпики» на «Бэклоге» (#112).
Task 6: «Спринт»: выбор спринтов и фильтры
Files:
- Create:
web/src/modules/jira/agile/SprintPicker.tsx - Modify:
web/src/modules/jira/agile/SprintPage.tsx - Test:
web/src/modules/jira/agile/SprintPage.test.tsx
Interfaces:
-
Consumes:
selectableSprints,parseSprintIds,sprintIssues,matches,useAgileView(label, "sprint"),AgileToolbar. -
Produces:
SprintPicker({ sprints, selected, onChange }: { sprints: AgileSprint[]; selected: number[]; onChange(ids: number[]): void })—Dropdownс кнопкой «Спринты» (на кнопке — имя единственного выбранного или «Спринты: N»), внутриCheckboxпо спринту (имя, «активный»/«будущий»); снять последнюю отметку нельзя (disabled).BoardColumnsполучает отфильтрованные задачи (Task 7 добавитhidden). -
Step 1: тесты (переписать «два активных: переключатель…», «один активный: переключателя нет», «устаревший ?sprint=», «мусорный ?sprint=abc» под новую спеку; остальные — оставить):
- по умолчанию выбраны все активные; два активных → два заголовка и задачи обоих;
- сценарий «Будущий спринт на доске»: отметить будущий 102 при активном 101 → адрес
?sprint=101,102без новой записи истории (router.state.historyAction === "REPLACE"), два заголовка, «осталось N дн.» только у 101; - задача в обоих выбранных спринтах — одна карточка (Review Focus 1);
?sprint=999и?sprint=abc→ все активные;?sprint=103(будущий) → только он;- нет активного, есть будущий → «Нет активного спринта», ссылка «Бэклог» и выбор спринтов доступен; выбор будущего показывает доску;
- сценарий «Исполнитель на доске спринта»: выбран исполнитель → только его карточки, числа колонок — по видимым; на
«Бэклоге» (
open("/jira/backlog?…")) исполнитель «все»; - «Скрыть выполненные» убирает выполненные карточки.
-
Step 2: vitest файла — новые FAIL.
-
Step 3: реализация по Interfaces; заголовки —
SprintHeadна каждый выбранный, компактно (agile-section__head), «осталось…»/«срок прошёл» — только уstate === "active". ПрежнийSegmentedубрать. -
Step 4: vitest файла — PASS;
npm run lint— PASS. -
Step 5: коммит
feat(web): «Спринт» — выбор активных и будущих спринтов, фильтры (#112).
Task 7: Колонки доски: скрытие, одна высота, прокрутка; «Kanban»
Files:
- Create:
web/src/modules/jira/agile/ColumnsMenu.tsx - Modify:
web/src/modules/jira/agile/BoardColumns.tsx,SprintPage.tsx,KanbanPage.tsx,agile.css - Test:
web/src/modules/jira/agile/SprintPage.test.tsx,KanbanPage.test.tsx,columns.test.tsпри необходимости
Interfaces:
-
Consumes:
ColumnView/columnsOf(без изменений),useAgileView(label, "sprint" | "kanban"),AgileToolbar. -
Produces:
ColumnsMenu({ names, hidden, onChange }: { names: string[]; hidden: string[]; onChange(hidden: string[]): void })—Dropdownс кнопкой «Колонки» (+Badgeс числом скрытых, если > 0), отметки по именам; последняя видимая —disabled; имя изhidden, которого нет вnames, в меню не показывается и наBadgeне считается.BoardColumns({ columns, lastCaption, hidden }: { columns: ColumnView[]; lastCaption?: string; hidden?: string[] }). -
Step 1: воспроизвести баг п. 10 (superpowers:systematic-debugging): тестовый хаб (
bash web/scripts/test-hub.shв фоне +npm run devили собранное приложение) с широкой доской из Task 8 Step 1 (если её ещё нет — временно в своём сиде), Playwright-скрипт в scratchpad: окно 2560 × 1300, замерить у.page,.agile-columnsширину иgetBoundingClientRect().bottomпротивinnerHeight. Записать причину в ledger. Ожидаемая по design #9 и R-12: полоса прокрутки ниже окна и ширина страницы ограниченаmax-width:1440pxу.page. Если причина другая — чинить её, требование спеки то же. -
Step 2: тесты: сценарий «Скрытая колонка» (снять «Готово» → колонки нет, на «Колонки» — 1, после повторного монтажа так же); последнюю видимую снять нельзя; заголовки колонок —
getAllByRole("heading", { level: 3 })(T10.3); «Kanban»: поиск и исполнитель фильтруют колонки и «Бэклог (N)», флажка «Скрыть выполненные» нет, меню «Колонки» есть; скрытое имя колонки, которой больше нет, не ломает меню. -
Step 3: vitest файлов — новые FAIL.
-
Step 4: реализация. Скрытие — фильтр
columnsпо имени вBoardColumns. Раскладка (design #9, R-12): страница доски (.agile--wide) без ограниченияmax-widthу.page(.page:has(> .agile--wide)или класс от страницы — выбрать и записать рулинг), доска занимает высоту окна под шапкой и панелью фильтров (min-height:360px; на экране < 640 px учесть закреплённую строку «Меню»),.agile-columns{align-items:stretch}, у колонки прокручивается.agile-col__list(overflow-y:auto; min-height:0). Горизонтальная прокрутка — у.agile-columns. -
Step 5: vitest файлов — PASS;
npm run lint— PASS; скрипт из Step 1 — полоса прокрутки в окне, последняя колонка достижима, колонки одной высоты. -
Step 6: коммит
fix(web): колонки доски — одна высота, прокрутка в окне, скрытие колонок (#112, T10.3).
Task 8: e2e, сид и попутные тесты hub#111
Files:
- Modify:
web/scripts/seed-hub.py,web/e2e/agile.spec.ts - Test:
web/src/modules/jira/agile/AgileGate.test.tsx(новый),web/src/shell/nav.test.tsилиKanbanPage.test.tsx
Interfaces:
-
Consumes: всё выше; сид — прежний формат
boardsвmirror.apply_state. -
Step 1: сид. Проект
WIDE_E2E(scrum-доска 6100): 11 колонок по своим статусам + задачи со статусом вне колонок («Без колонки»), активный спринт, 40 задач в одной колонке, по 1–3 в остальных; эпики для AWPCA уже есть в фикстуре (AURORA-9100«Фича», ссылки на отсутствующиеAURORA-1359,AURORA-9999). Фиксированныйjira_updatedу задач канбана вместо «сегодня 12:00», если от него не зависит «за 14 дней» (T12.2; если зависит — датаtoday - 1 dayи комментарий). Проверить, что прочие e2e (projects.spec.ts,overview.spec.ts) не считают проекты жёстко; если считают — поправить ожидание. -
Step 2: e2e (
agile.spec.ts):- «Широкая доска» по спеке: окно 2560 × 1300,
WIDE_E2E— высоты всех.agile-colравны (±1 px), нижний край.agile-columns≤innerHeight,scrollWidth > clientWidthу доски, послеscrollLeft = scrollWidthколонка «Без колонки» целиком в окне,document.documentElement.scrollWidth ≤ clientWidth, ширина.agile-columnsбольше 1440 px; - 900 px — прежний тест плюс нижний край доски ≤
innerHeight; - «Бэклог» AWPCA: панель «Эпики» с
AURORA-9100, выбор — строки только его задач; свёртка секции переживает перезагрузку; - «Спринт» AWPCA: отметить «AWPCA_Спринт 3» → адрес
sprint=102,103; скрыть «Готово» → после перезагрузки скрыта; - T12.3/T12.4: в существующих тестах файла — локаторы по роли и точному тексту вместо нестрогих
getByTextи.last()/.first()по порядку DOM.
- «Широкая доска» по спеке: окно 2560 × 1300,
-
Step 3: T9.4 — vitest
AgileGate.test.tsx: «Загрузка…» пока/agileвисит; ошибка/agile→ текст ошибки и «Повторить», щелчок повторяет запрос; меню kanban-проекта: «Kanban» есть, «Бэклог»/«Спринт» нет. -
Step 4:
cd web && npm run e2e— весь набор PASS;make check(из корня worktree) — PASS. -
Step 5: коммит
test(web): e2e широкой доски и фильтров, сид WIDE_E2E, тесты AgileGate (#112, T9.4, T12.2–T12.4).
Task 9: Документы
Files:
-
Modify:
openspec/changes/agile-web-polish/design.md(рулинги контроллера R-13… в «Decisions made without discussion»),CLAUDE.md/ARCHITECTURE.md— только если упоминают составagile/или ключиlocalStorage(проверить grep). -
grep -n "agile\|sdlc-hub-legend" CLAUDE.md ARCHITECTURE.md— дописатьsdlc-hub-agileи новые файлы, где перечислены соседние;openspec validate agile-web-polish --strict— valid. -
коммит
docs: доработки экранов доски — рулинги и карта (#112).
После плана (сессия, не SDD): перенести новые значки и стиль agile-type в kit скилла aura-design
(вне worktree — только руками сессии), PR в Gitea, выкатка make web + kickstart — за владельцем.