This commit is contained in:
Zuev
2026-10-02 04:07:56 +03:00
parent 97bf3cc50a
commit fc5801d683
42 changed files with 1201 additions and 305 deletions

View File

@@ -4,15 +4,15 @@
| Параметр | Значение |
|----------|----------|
| **Фреймворк** | Переходный режим: React 19 для страницы входа, кабинетов студента и преподавателя, страницы настроек и общего слоя `react/shared`, Vanilla JavaScript для остальных разделов |
| **Фреймворк** | React 19 для всех пользовательских страниц и вкладок; общие сервисы и чистые вспомогательные функции остаются ES-модулями |
| **Модульная система** | ES6 Modules (`import`/`export`) |
| **Стили** | CSS (модульный подход) |
| **Шрифт** | Системный стек без внешних font-CDN |
| **Веб-сервер** | Apache httpd на Alpine со строгим CSP |
Пошаговый план и актуальная точка продолжения находятся в
[`REACT_MIGRATION.md`](REACT_MIGRATION.md). Миграция выполняется по целым страницам и
разделам без изменения действующих URL и REST-контрактов.
[`REACT_MIGRATION.md`](REACT_MIGRATION.md). Все страницы и вкладки переведены на React
с сохранением действующих URL и REST-контрактов.
---
@@ -102,14 +102,15 @@ frontend/
│ │ │ └── TeacherAbsencesTab.jsx # Отсутствия: реестр, мастер замены, пожелания и заявки на изменение
│ │ ├── main.jsx # React entrypoint для `/admin/`
│ │ └── testing/ # render-admin.jsx для DOM-проверок
│ └── shared/ # Общий React-слой для следующих переносимых страниц
│ └── shared/ # Общий React-слой всех кабинетов
│ ├── api-client.js # requestJson/apiClient поверх auth-транспорта
│ ├── auth-client.js # Восстановление сессии и logout с redirect
│ ├── use-sidebar.js # Десктопное сворачивание и мобильное меню
│ ├── dates.js # Дата-математика (недели, ISO, форматирование)
│ ├── session-policy.js # Фазы loading/ready/unauthorized/error и русские тексты
│ ├── use-authorized-session.js # Хук проверки роли при монтировании страницы
│ ├── runtime-entry.jsx # Единая точка экспорта общего runtime-chunk
│ ├── ui/ # AppErrorBoundary, AsyncState, FormAlert, AsyncCombobox, ScheduleOverview, ConfirmDialog, Pagination
│ ├── ui/ # CustomSelect, SidebarToggle, AppErrorBoundary, AsyncState, FormAlert, AsyncCombobox, ScheduleOverview, ConfirmDialog, Pagination
│ └── testing/ # render-shared.jsx для DOM-проверок через renderToStaticMarkup
├── tests/
│ ├── academic-calendar-grid.test.mjs # Неполная первая неделя календарного графика
@@ -132,6 +133,7 @@ frontend/
│ ├── schedule-view-semesters.test.mjs # Выбор семестра и расчёт двухнедельного диапазона просмотра
│ ├── teacher-absences.test.mjs # Payload мастера замены и доступность вкладки по ролям
│ ├── teacher-preferences.test.mjs # Календарь пожеланий, заявки и подсказки конструктора
│ ├── browser/ # Playwright: наведение, селекты и мобильное меню
│ └── security-policy.test.mjs # Web Storage, XSS, пароли, язык, CSP и Dockerfile
├── index.html # 🔐 Страница авторизации (общая)
├── style.css # Стили страницы авторизации
@@ -330,9 +332,15 @@ settings SPA не содержат неработающей кнопки бур
`PageResponse`; размер страницы — 25, 50 или 100. `view-state.js` унифицирует
загрузку со spinner, пустой результат и ошибку с кнопкой повторного запроса.
- `AsyncCombobox` загружает варианты с сервера, сохраняет выбранный ID, поддерживает
клавиатуру и роли `combobox/listbox`. Он используется для групп, преподавателей,
клавиатуру и роли `combobox/listbox`. При новом вводе сразу исключаются устаревшие
результаты, включая ответы во время задержки поиска. Escape закрывает меню с возвратом
фокуса без нового запроса; уход фокуса за пределы компонента отменяет отложенный поиск.
Возврат стрелкой вверх сохраняет введённый текст. Он используется для групп, преподавателей,
аудиторий и совместимых календарных графиков; предварительная загрузка вариантов не
раскрывает меню. Студент больше не загружает полный список групп.
- Реестры пользователей, групп, дисциплин и заявок сохраняют выбранные параметры до
завершения запроса, чтобы быстрые изменения фильтров и сортировки не отменяли друг друга.
Сброс фильтров групп также отменяет отложенный поиск.
- `dialog.js` заменяет нативные `confirm`, `prompt` и `alert`: возвращает фокус, удерживает
его внутри окна, закрывается по Escape и может требовать причину. Нативных диалогов в
admin/settings-модулях нет.
@@ -414,11 +422,28 @@ SHA-256 style-хэшей с CSP. Там же закреплены безопас
npm run build # собрать dist/vendor/otel.js и dist/react/login.js
npm test # frontend unit/static tests
npm run check # React-сборка, синтаксис auth/UI-модулей + все frontend-тесты
npm run check:browser # Проверка UI, асинхронного поиска и валидации в локальном Chromium
```
React-сборка выполняется существующим esbuild без отдельного dev-сервера. Для страницы
входа установлен лимит 75 000 байт gzip; превышение завершает сборку ошибкой. При появлении
нескольких React entrypoint общий runtime будет вынесен в отдельный кэшируемый chunk.
React-сборка выполняется esbuild без отдельного dev-сервера. Общие зависимости вынесены
в кэшируемые chunk'и, вкладки админки загружаются через `React.lazy`. Холодный бюджет
входа — 85 000 байт gzip, остальных кабинетов — 90 000 байт. Для каждого entrypoint
считаются только его статические зависимости: lazy-вкладки и модули других страниц
не включаются в холодную загрузку. Превышение лимита завершает сборку ошибкой.
Браузерные проверки требуют запущенной локальной версии в Docker и Chromium
(`/usr/bin/chromium`, другой путь задаётся через `CHROMIUM_PATH`). По умолчанию
используются `https://localhost` и демо-аккаунт `admin`; настройки можно передать через
`FRONTEND_TEST_BASE_URL`, `FRONTEND_TEST_LOGIN`, `FRONTEND_TEST_PASSWORD`.
Проверка пожеланий использует демо-аккаунт преподавателя; для другого аккаунта
задаются `FRONTEND_TEST_TEACHER_LOGIN` и `FRONTEND_TEST_TEACHER_PASSWORD`.
Проверки не сохраняют изменения данных: проверяются обе темы, доступные вкладки,
края кнопок, смена роли в форме, сброс фильтра, мобильное меню админки/настроек
и стабильность ячеек пожеланий преподавателя. Отдельные сценарии задерживают ответы
API для проверки совместного изменения роли и сортировки и отмены поиска после сброса.
`shared-controls.test.mjs` собирает текущие компоненты в изолированную браузерную форму:
проверяет устаревшие ответы и ошибки поиска, клавиатурное управление, уход фокуса
и валидацию обязательного селекта без записи данных в API.
---
@@ -549,6 +574,32 @@ ID преподавателя берётся из восстановленног
4. **`modals.css`** — Модальные окна
5. **`departments-data.css`** — Стили создания кафедры/специальности
### Общие элементы управления после миграции
Кнопки сохраняют область наведения: hover и active меняют цвет, границу и тень,
не смещая сам элемент через `translateY`. Это исключает мерцание у нижней кромки.
Пункты бокового меню и ячейки пожеланий преподавателя также не смещаются при наведении.
Карточки и боковая панель админки/настроек используют непрозрачные фоновые токены
без `backdrop-filter`; у карточек отключена анимация с сохраняемым `transform`.
Это убирает фоновые фильтруемые слои, на которых наблюдались цветные полосы при
перерисовке после наведения на меню. В развёрнутой панели не создаются избыточные
нативные подсказки `title`; подсказки остаются у скрытых подписей свёрнутого меню.
Волна нажатия страницы входа ограничена `.btn-submit`; админка больше не добавляет
ripple-узлы в React-разметку старым глобальным обработчиком.
Одинарные селекты вкладок и пагинации используют React-компонент `CustomSelect`.
Подписи, пункты и `disabled` синхронизируются с нативным контролом после рендера;
пустой пункт доступен для сброса фильтров. Автоматическое оборачивание селектов
через `admin/js/dropdown.js` отключено. При отправке формы пустой обязательный
селект показывает «Выберите значение», получает фокус на видимой кнопке и помечается
`aria-invalid`; выбор значения снимает ошибку. Пример — в `docs/UI_COMPONENTS.md`.
Оболочки админки и настроек используют `useSidebar` и `SidebarToggle`:
сворачивание десктопной панели хранится в `localStorage`, открытие мобильного
меню — отдельное временное состояние. Мобильная панель закрывается при выборе
раздела, клике по затемнению, Escape и смене размера экрана. Навигация развёрнутой
панели прокручивается, а её заголовок и нижние действия остаются доступными.
### Темизация
Общий `ui-foundation.css` подключается последним во всех пяти оболочках.