181 lines
21 KiB
Markdown
181 lines
21 KiB
Markdown
## MODIFIED Requirements
|
||
|
||
### Requirement: Карточка задачи
|
||
Адрес `/app/issues/{key}` SHALL открывать карточку задачи из `GET /issues/{key}` модальным окном поверх страницы, с
|
||
которой её открыли (список «Задачи» или доска); страница под окном SHALL оставаться смонтированной и сохранять фильтры,
|
||
загруженные строки, прокрутку и раскладку. Перезагрузка страницы с открытым окном SHALL сохранять страницу под окном. Открытый напрямую
|
||
адрес (новая вкладка, закладка) SHALL
|
||
показывать окно поверх списка задач без фильтров. Окно SHALL закрываться кнопкой ✕, клавишей Esc и щелчком по фону (нажатие и отпускание — на фоне; выделение текста,
|
||
отпущенное за краем окна, окно не закрывает) и
|
||
возвращать на страницу, с которой его открыли, даже после переходов по связям внутри окна; «назад» браузера после
|
||
закрытия MUST NOT открывать карточку снова. Переход по связанной задаче SHALL менять содержимое окна и адрес, «назад»
|
||
браузера — возвращать к прежней карточке. Пока окно открыто, фокус SHALL оставаться в окне, страница под ним не
|
||
прокручивается.
|
||
|
||
Содержимое окна:
|
||
- шапка: ключ, статус Jira, «Открыть в Jira», ✕, тема; строка
|
||
«исполнитель · срок · спринт · эпик» без пустых частей, срок — `planned_end`, иначе `duedate`, с пометкой «просрочено»,
|
||
если он раньше сегодняшней даты и статус Jira не входит в `closed_statuses`; эпик — темой
|
||
(`epic_summary`), иначе ключом;
|
||
- «Связи» по группам в порядке: «Зависит от» (входящие связи логических типов `блокирует начало` и `блокирует
|
||
завершение` из `link_types`, с меткой «начало» / «завершение»), «Блокирует» (исходящие тех же типов, с теми же метками),
|
||
«Связана с» (тип `связанные` в обе стороны), «Прочие» (тип Jira вне `link_types`: имя типа и направление «→» / «←»);
|
||
в строке — ключ (открывает связанную задачу в окне), тема и статус Jira, а если задачи нет в зеркале — ключ и «нет в
|
||
зеркале»; пустые группы не показываются, без связей — «связей нет»;
|
||
- «Описание» — текст, отрендеренный по требованию «Разметка Jira в карточке», с кнопкой «исходник» / «текст» в
|
||
заголовке раздела; длиннее 8 строк — свёрнуто с кнопкой «развернуть» / «свернуть» в обоих режимах; без описания
|
||
раздела нет;
|
||
- «Вложения (N)» — новые сверху: значок по типу файла (картинка, таблица, PDF, прочее), имя, размер, «автор · дата» и
|
||
кнопка скачивания (требование «Скачивание вложений в карточке»); без вложений раздела нет;
|
||
- «Комментарии (N)» — новые сверху, автор, время, кнопка «исходник» / «текст» у каждого комментария, текст,
|
||
отрендеренный по требованию «Разметка Jira в карточке», под текстом — вложения, на которые ссылается комментарий
|
||
(`attachment_ids`): строка «плашек» с именем и размером, щелчок — скачивание; кнопка «Скрыть» / «Показать» сворачивает раздел, выбор SHALL
|
||
запоминаться в браузере для всех карточек; без комментариев — «комментариев нет»;
|
||
- «Служебные заметки» (требование «Служебные заметки»);
|
||
- «Прочие поля» — непустые из: тип, приоритет, автор, метки, плановое начало, обновлена в Jira, сосед по связям;
|
||
- «Команды моста (N)» — 10 последних команд по задаче (id, пакет, тип, статус, время завершения, ошибка), раздел свёрнут
|
||
при открытии; если команд не было — текст «команд по задаче не было».
|
||
На ширине от 900 px «Связи», «Описание», «Вложения», «Комментарии» — в левой колонке, заметки, прочие поля и команды — в правой;
|
||
уже — одна колонка: заметки, связи, описание, вложения, комментарии, прочие поля, команды. Если задачи нет в зеркале (404), окно
|
||
SHALL сообщать об этом с кнопкой «Закрыть»; хаб не отвечает — сообщение и «Повторить», ранее загруженные данные
|
||
остаются.
|
||
|
||
#### Scenario: Связанная задача
|
||
- **WHEN** у AURORA-1620 исходящая связь `ASUPR_Блокер_Начала` на AURORA-1621 «Расчёт свода» в статусе «В работе»
|
||
- **THEN** в карточке в группе «Блокирует» строка «начало · AURORA-1621 · Расчёт свода · В работе»; щелчок по ключу
|
||
меняет содержимое окна на AURORA-1621, адрес — `/app/issues/AURORA-1621`; «назад» браузера возвращает AURORA-1620
|
||
|
||
#### Scenario: Входящий блокер
|
||
- **WHEN** у AURORA-1620 входящая связь `ASUPR_Блокер_Завершения` от AURORA-1500
|
||
- **THEN** строка с AURORA-1500 и меткой «завершение» — в группе «Зависит от»
|
||
|
||
#### Scenario: Задача без команд
|
||
- **WHEN** по AURORA-1620 не было команд
|
||
- **THEN** в разделе «Команды моста» — текст «команд по задаче не было», таблицы нет
|
||
|
||
#### Scenario: Закрытие после переходов
|
||
- **WHEN** со списка «Задачи» открыта AURORA-1620, в окне — переход по связи на AURORA-1621, нажата Esc
|
||
- **THEN** окно закрыто, адрес — адрес списка с прежними фильтрами; «назад» браузера не открывает карточку
|
||
|
||
#### Scenario: Прямой адрес
|
||
- **WHEN** в новой вкладке открыт `/app/issues/AURORA-1620`, затем нажат ✕
|
||
- **THEN** под окном был список задач без фильтров; после закрытия адрес `/app/issues`, «назад» не открывает карточку
|
||
|
||
#### Scenario: Скрытые комментарии
|
||
- **WHEN** в карточке нажато «Скрыть» у комментариев, затем страница перезагружена и открыта другая карточка
|
||
- **THEN** комментарии в ней скрыты, видна кнопка «Показать» и число комментариев
|
||
|
||
#### Scenario: Просрочка закрытой задачи
|
||
- **WHEN** у AURORA-1620 срок 2026-10-01, сегодня 2026-10-17, статус Jira «Готово»
|
||
- **THEN** в строке под темой «срок 01.10» без пометки «просрочено»; при статусе «В работе» — с пометкой
|
||
|
||
### Requirement: Разметка Jira в карточке
|
||
Описание задачи и текст каждого комментария в карточке SHALL показываться отрендеренной вики-разметкой Jira (хаб
|
||
хранит их как есть, в wiki) так, как их показывает Jira. Разбираются:
|
||
- блоки: заголовки `h1.`–`h6.` в начале строки; списки — строки, начинающиеся (после необязательных пробелов) с
|
||
маркеров `*`, `#` и пробела (уровень вложенности — числом маркеров, `*` — маркированный, `#` — нумерованный,
|
||
смешанная вложенность `*#` — по последнему маркеру) или с одного `-` и пробела (маркированный, первый уровень);
|
||
`--`, `*-` и прочие сочетания с `-` — не список; таблицы — строки, начинающиеся с
|
||
`|`, ячейки `||заголовок||` и `|ячейка|`; `{code}` / `{code:язык}` … `{code}` и `{noformat}` … `{noformat}` —
|
||
моноширинный блок без разбора разметки внутри; `{quote}` … `{quote}` и строка `bq. ` — цитата; открывающий тег
|
||
блока — в начале строки, закрывающий — в любом месте той же или последующей строки, текст после закрывающего тега
|
||
разбирается дальше как обычные строки; тег не в начале строки — текст как есть; строка `----` —
|
||
горизонтальная черта; прочие строки — абзацы, разделённые пустыми строками, одиночный перенос внутри абзаца —
|
||
перенос строки;
|
||
- внутри строки: `*жирный*`, `_курсив_`, `-зачёркнутый-`, `+подчёркнутый+`, `^верхний^`, `~нижний~`, `{{моно}}`
|
||
(`{{…}}` — без разбора внутри); маркер выделения действует, только если открывающий стоит в начале текста или после
|
||
пробела либо знака препинания и за ним не пробел и не тот же символ (`**x**` — текст как есть), а закрывающий стоит после не-пробела и за ним не буква и не
|
||
цифра (`data_type`, `2026-10-15`, `счёт-фактура`, `a*b*c` — обычный текст); `\\` — перенос строки; `\` перед
|
||
символом разметки — сам символ;
|
||
- ссылки: `[текст|адрес]`, `[адрес]` и голые адреса `http://`, `https://` — ссылка в новой вкладке, только для схем
|
||
`http`, `https`, `mailto`, иначе текст как есть; `[ключ задачи]`, `[текст|ключ задачи]` и ключ задачи в тексте вида
|
||
`ПРОЕКТ-123`, где `ПРОЕКТ` — `project_key` из настроек хаба, — ссылка, открывающая карточку этой задачи в окне
|
||
(`UTF-8`, `SHA-256` и ключи других проектов — текст);
|
||
`[~логин]` — «@логин»;
|
||
- ссылки на вложения задачи — `!имя!`, `!имя|параметры!`, `[^имя]`, `[текст|^имя]` с тем же разбором имени, что у хаба
|
||
(`hub-api`, «Ссылки на вложения в тексте»), имя есть среди вложений задачи: ссылка-кнопка со значком скрепки и текстом
|
||
— именем файла (у `[текст|^имя]` — текстом), щелчок — скачивание; картинка в тексте не показывается; имени нет среди
|
||
вложений — исходник как есть.
|
||
Всё, что разборщик не распознал (`{panel}`, `{color}`, `!картинка!` и `[^имя]` без такого вложения у задачи, незакрытые маркеры и блоки и прочее), SHALL
|
||
показываться как текст исходника без потерь. Разметка MUST NOT превращаться в HTML строкой (`innerHTML`,
|
||
`dangerouslySetInnerHTML`): текст задачи не может добавить на страницу элементы, атрибуты или скрипты. Если рендер
|
||
блока завершился ошибкой, блок SHALL показываться исходником.
|
||
|
||
Кнопка «исходник» у описания и у каждого комментария SHALL переключать этот блок на исходник — текст с сохранёнными
|
||
переносами строк, как без разбора разметки, — и обратно кнопкой «текст»; остальные блоки не переключаются. При каждом
|
||
открытии карточки (в том числе при переходе по связи) все блоки показываются отрендеренными, выбор не запоминается.
|
||
|
||
#### Scenario: Описание со структурой
|
||
- **WHEN** описание AURORA-1620 — `h3. Контекст`, строка `Шаги:`, затем `# Загрузить ОСВ` и `# Открыть документ`,
|
||
затем пустая строка и `*Итог:* ошибка в {{data_type}}`
|
||
- **THEN** в «Описании» заголовок «Контекст», абзац «Шаги:», нумерованный список из двух пунктов и абзац, где «Итог:» —
|
||
жирным, «data_type» — моноширинным; символов `h3.`, `#`, `*`, `{{` не видно
|
||
|
||
#### Scenario: Переключение на исходник
|
||
- **WHEN** в карточке AURORA-1620 у описания нажато «исходник»
|
||
- **THEN** описание показано исходником с переносами строк (видны `h3. Контекст` и `# Загрузить ОСВ`), кнопка — «текст»;
|
||
комментарии остаются отрендеренными; после «текст» описание снова отрендерено
|
||
|
||
#### Scenario: Исходник у одного комментария
|
||
- **WHEN** у второго комментария нажато «исходник», затем открыта связанная задача и возврат «назад»
|
||
- **THEN** сразу после нажатия исходником показан только второй комментарий; после возврата все комментарии
|
||
отрендерены
|
||
|
||
#### Scenario: Ключ задачи в тексте
|
||
- **WHEN** комментарий — `П. 1 ведётся в AURORA-1445; AURORA-1645 снята как дубль.`
|
||
- **THEN** «AURORA-1445» и «AURORA-1645» — ссылки; щелчок по первой меняет содержимое окна на AURORA-1445
|
||
|
||
#### Scenario: Неизвестная разметка и опасный адрес
|
||
- **WHEN** описание — `{color:red}важно{color}`, `!схема.png!` и `[нажми|javascript:alert(1)]`
|
||
- **THEN** все три показаны текстом исходника как есть, ссылки и картинки нет, скрипт не выполняется
|
||
|
||
#### Scenario: Списки с отступом и пустыми строками
|
||
- **WHEN** описание — `Шаги воспроизведения:`, ` * Загрузить ОСВ.`, пустая строка, ` * Дождаться обработки.`
|
||
- **THEN** абзац «Шаги воспроизведения:» и маркированные пункты «Загрузить ОСВ.» и «Дождаться обработки.» без
|
||
звёздочек
|
||
|
||
#### Scenario: Обычный текст не портится
|
||
- **WHEN** описание — `Поле data_type = null, дата 2026-10-15, оборот 18 803 903,65 - 9 351 102,89, a*b*c, UTF-8,
|
||
**важно**`
|
||
- **THEN** текст показан как есть, без курсива, зачёркивания, жирного и ссылок
|
||
|
||
#### Scenario: Скриншот в тексте комментария
|
||
- **WHEN** комментарий — «см. !скрин 1.png|thumbnail!», у задачи есть вложение «скрин 1.png»
|
||
- **THEN** вместо `!скрин 1.png|thumbnail!` — кнопка со скрепкой «скрин 1.png»; под комментарием плашка «скрин 1.png ·
|
||
234,4 КБ»; щелчок по любой из них скачивает файл
|
||
|
||
## ADDED Requirements
|
||
|
||
### Requirement: Скачивание вложений в карточке
|
||
Кнопка скачивания вложения (в разделе «Вложения», плашка под комментарием, ссылка в тексте) SHALL работать одинаково:
|
||
1. `POST /attachments/{id}/fetch {author: "web"}`;
|
||
2. `state = ready` — `GET /attachments/{id}/content` с клиентским токеном, браузер сохраняет файл под именем `filename`
|
||
(через `Blob` и временную ссылку `download`; адрес с токеном в строке браузера MUST NOT появляться);
|
||
3. `state = fetching` — у всех кнопок этого вложения в карточке вместо «Скачать» — «Загружается…» (неактивна), опрос
|
||
`GET /attachments/{id}` раз в 2 с, пока окно открыто на этой задаче; `ready` — шаг 2 сам, без второго нажатия; закрыли
|
||
окно или ушли на другую задачу — опрос прекращается, команда остаётся в очереди (файл ляжет в хаб);
|
||
4. `failed` — под вложением в разделе «Вложения» текст ошибки и кнопка «Повторить» (новый запрос); 409 `agent_too_old`
|
||
и прочие ошибки хаба — их текст там же.
|
||
Вложение с `state = ready` в разделе «Вложения» помечается «у хаба» и скачивается сразу. Размер неизвестен — «размер неизвестен» и обычная кнопка.
|
||
Вложение больше 10 МБ —
|
||
вместо кнопки ссылка «Открыть в Jira» (`<адрес Jira>/secure/attachment/<id>/<имя в URL-кодировке>`, новая вкладка) с
|
||
подсказкой «больше 10 МБ — только в Jira»; плашка и ссылка в тексте ведут туда же.
|
||
|
||
#### Scenario: Скачать скриншот
|
||
- **WHEN** в карточке AURORA-1650 нажато «Скачать» у «скрин 1.png», файла у хаба нет, агент онлайн
|
||
- **THEN** кнопка — «Загружается…», через несколько секунд браузер сохраняет «скрин 1.png», кнопка снова «Скачать», у
|
||
вложения отметка «у хаба»
|
||
|
||
#### Scenario: Окно закрыли во время скачивания
|
||
- **WHEN** нажато «Скачать», затем окно карточки закрыто
|
||
- **THEN** опросов `GET /attachments/{id}` больше нет; при следующем открытии карточки, если файл уже у хаба, вложение с
|
||
отметкой «у хаба»
|
||
|
||
#### Scenario: Большой файл
|
||
- **WHEN** у вложения «запись.mp4» размер 25 МБ
|
||
- **THEN** вместо «Скачать» — ссылка «Открыть в Jira» с подсказкой «больше 10 МБ — только в Jira»
|
||
|
||
#### Scenario: Агент старой версии
|
||
- **WHEN** нажато «Скачать», хаб ответил 409 «агент v13 не умеет скачивать вложения — нужен v14»
|
||
- **THEN** под вложением этот текст и «Повторить»
|