useMemo с attachmentUrls стоял ПОСЛЕ `if (loading) return` — на первом
рендере (загрузка) он не вызывался, на втором вызывался, порядок хуков
менялся, и React ронял компонент с #310 «rendered more hooks than during
the previous render». Карточка заявки на услуги не открывалась вообще.
Перенёс расчёт выше ранних выходов.
Заодно включил `react-hooks/rules-of-hooks` (error) — плагин давно в
зависимостях и в коде есть eslint-disable для exhaustive-deps, то есть
правила подразумевались, но в .eslintrc их забыли объявить. По остальному
коду правило даёт 0 нарушений, так что этот баг был единственным.
`exhaustive-deps` пока оставил выключенным: на текущем коде это 16
предупреждений, их разбор — отдельная задача, а не довесок к фиксу.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CollapseSection.body у @tnsu/ui-kit уже сам является 2-колоночным грид-
контейнером (._body{grid-template-columns:1fr 1fr}) — FormGrid внутри
неё создавал ВЛОЖЕННЫЙ грид, который занимал только ОДНУ из двух колонок
родителя (как единственный grid-item без явного grid-column), а его
собственные две колонки делили уже урезанную пополам ширину. Из-за этого
«Объём работ», «Итого объёмы работ» и «Общие замечания» рендерились на
половине ширины карточки, хотя место было.
FormField кладём прямо в CollapseSection, без обёртки FormGrid — так уже
сделано во всех остальных формах (см. Clearance/RequestSection.tsx).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Форма открывается в боковом Drawer, а не на всю страницу — его ширина не
связана с viewport, поэтому брейкпоинты CollapseSection/FormGrid (следят
за шириной окна) не спасают. Фикс-колонки строки (ед.изм/кол-во/цена/
сумма) при этом не сжимались (grid-колонки по умолчанию не сжимаются
своего содержимого) и вылезали за рамку карточки.
Обернул строки в горизонтально скроллящийся контейнер (тот же приём, что
раньше был у плоской таблицы — .tableWrap в AnnexesSection) вместо попытки
сжать поля до нечитаемости.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Итог сметы и объёмов работ теперь кладём прямо в JSON-колонку рядом с
группами ({ groups, total } — см. serializeGroups/parseGroupedJson в
cost.ts), а не отдельной числовой колонкой SharePoint. Форма total из
хранилища не доверяет, всегда считает заново; в JSON он нужен только тем,
кто читает колонку напрямую (отчёты, sp-query), не поднимая форму.
Убраны EstimateTotal/WorkVolumesTotal из провижининг-манифеста — они ещё
не были провижинены на тенанте, миграция не нужна.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Под текстовым описанием объёма работ добавлена таблица групп/позиций с
ценой и суммой — в том же формате, что и смета (группа → позиции → сумма
по группе → общий итог). Дополняет текст итоговыми цифрами, не заменяет
его.
Редактор таблицы «группы → позиции» вынесен в отдельный переиспользуемый
компонент CostGroupsEditor — CostsSection и новый блок в ScopeSection
используют один и тот же код вместо двух копий.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Вернул возможность прикладывать файл прямо к строке «Приложения» (fileName
на IAnnexRow, хранится как встроенное вложение элемента списка) и убрал
общий блок «Вложения» — он был избыточен: файлы теперь привязаны к своим
строкам, отдельного места под них не нужно.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Убрано прикрепление реальных файлов к строке (в исходной бумажной форме
их нет — только перечень с номером и подтверждением), а заодно колонки
«Подтверждение» и «Кол-во стр.». Приложения теперь просто опись: описание
документа + номер приложения. Для файлов остаётся общий блок «Вложения».
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Каждую строку таблицы приложений теперь можно связать с реальным файлом —
он хранится как встроенное вложение элемента списка (тот же механизм, что
у общего блока «Вложения»), новых списков/библиотек в SharePoint под это
заводить не нужно. В IAnnexRow добавлено fileName; выбранный, но ещё не
сохранённый файл держится в памяти формы и грузится вместе с общими
вложениями при save() (нужен id элемента). Удаление строки/замена файла
открепляет уже загруженное вложение, чтобы не оставалось висящих файлов.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Смета теперь — список групп (разделов работ), внутри каждой свои позиции;
название группы необязательно. Сумма по позиции/группе/общий итог по-прежнему
считаются на лету, не хранятся построчно. UI — карточка на группу с полями
без рамки таблицы, по макету коллеги.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Электронный аналог бумажной Service Requisition Form ПТО: заявитель,
проект (маршрут резолвится по нему), описание требований, табличные части
«Приложения» и «Смета» (JSON-колонки, сумма считается на лету), только
фаза согласования — без исполнения. Форма подачи + режим согласующего,
провижининг-манифесты данных и согласования, регистрация в реестрах форм.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Пункт меню виден только заданному списку почт (Тришина, Городецкий,
Горбенко) — группы HR в SharePoint пока нет, добавили TODO завести
проверку по ней отдельно (reportsAccess.ts). Скрыт из меню совсем, а
не показан неактивным, и прямой переход по ?rpnav=reports у остальных
редиректит на «Новую заявку».
Раздел — форма периода (С/По) и кнопка «Скачать xlsx», дергает
GET api/reports/vacancies через тот же AadHttpClient, что и остальные
вызовы approval-route API. Имя файла собирается на фронте по формату
бэкенда (VacancyReportWorkbook.FileName), а не читается из
Content-Disposition — approval-route не объявляет заголовок в
Access-Control-Expose-Headers, браузер бы его не отдал.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/17
- Печать доступна только после согласования (Отдел рекрутинга); выбор
организации и логотип-шапка для форм с несколькими юрлицами
- «СЗ на перемещение ТМЦ»: заявителя можно выбрать (подача за другого),
маршрут резолвится на выбранного
- «Реферальная рекомендация»: организация вакансии (мультивыбор) и
подразделение/проект вакансии
- Поле «Подразделение» (справочник) — Vacation, UnpaidLeave, Clearance,
WorkplaceSetup, RecruitingHire, RecruitingSelection, TmcTransfer
- Поле «Проект» — Vacation, UnpaidLeave, Clearance
Обсуждение заявки поверх штатных комментариев SharePoint (PnPjs
item.comments) — без новых колонок и провижининга, права на переписку
раздаёт сам SharePoint по правам на элемент.
Встроено в ApproveFeature и EditFeature (единственные входы в просмотр
заявки для всех типов), поэтому доступно автору, всем согласующим
(включая уже решивших и ещё не дошедших до своего шага) и исполнителям,
а не только текущему шагу маршрута, как DecisionPanel.
Автора комментария всегда ставит реальная учётка — отладочная подмена
личности на запись в SharePoint не влияет, в UI есть предупреждение.
---------
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/14