diff --git a/app/(main)/uptime/page.tsx b/app/(main)/uptime/page.tsx index 2f7cc737..bfcf2b81 100644 --- a/app/(main)/uptime/page.tsx +++ b/app/(main)/uptime/page.tsx @@ -2049,7 +2049,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId )} {/* ── tab switcher ── */} -
+
{(["probes", "resources", "speed"] as const).map(t => ( @@ -2739,7 +2739,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId } setSpeedSheetOpen(true) }}> - +
@@ -2756,7 +2756,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId {permissionError && {permissionError}} {probeSaveError && {probeSaveError}} -
+
-
+
- +
@@ -2901,7 +2901,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId {permissionError && {permissionError}} {probeSaveError && {probeSaveError}} -
+
{/* from → to visual */}
diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index b5da2121..2d685ded 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -29,6 +29,14 @@ | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Не начат | | 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат | +## Приёмка 7.5Б — адаптивность мониторинга и форм (2026-09-23) + +- Формы Ping/Speed используют всю ширину телефона; min-w-0 у fieldset устраняет выход полей за границы панели. Параметры Speed идут вертикально также на ПК: ширины боковой панели недостаточно для трёх колонок без перекрытия Direction и длительности. +- Вкладки мониторинга переносятся на новую строку. Ранее выбор «Скорость» прокручивал общий контейнер по горизонтали и обрезал левую часть экрана, хотя document.scrollWidth не превышал viewport. Добавлена отдельная проверка границ всех трёх вкладок. Длинное имя в заголовке Speed переносится внутри доступной ширины. +- 49 E2E uptime-links прошли после исправления форм; после найденного на скриншотах сдвига вкладок прошли 5 профильных проверок; после финального исправления перекрытия Speed повторно прошли 3 сценария на 320/390/1440 px. Проверены видимость сохранения/отмены, отсутствие выхода полей за экран, Escape, отсутствие перекрытия параметров Speed. Просмотрены скриншоты форм сверху/снизу, Resources и Speed. Production build с TypeScript прошёл: 34 статические страницы. Lint тестов чистый, uptime сохраняет исходные 1 ошибку react-hooks/set-state-in-effect и 6 предупреждений. +- ReUI checklist: установленные примитивы и тема не изменялись, исправлена локальная композиция страницы. Проверки используют HTTP-моки; реальный JWT/RouterOS не проверен. Resources проверен на наличие строки и ширину страницы, но взаимодействие с таблицей после прокрутки требует отдельной приёмки. +- Следующий блок 7.5: адаптивность форм серверов и таблицы Resources после прокрутки; сквозной сценарий дашборд → объект → действие → возврат; смена backend/mode при незавершённой операции. Этап 7 ещё не завершён. Квота после проверок: использовано 39% пятичасовой и 22% недельной. Локальный коммит без push. + ## Приёмка 7.5А — неработающее действие экспорта серверов - Удалена кнопка «Экспорт» серверов без обработчика и её неиспользуемый импорт. Полноценный экспорт не реализован: формат, поля и назначение требуют отдельного контракта. Пользователь больше не видит действие, которое ничего не делает. diff --git a/docs/ux-ui-stage-7.md b/docs/ux-ui-stage-7.md index ab3b0590..b5267c55 100644 --- a/docs/ux-ui-stage-7.md +++ b/docs/ux-ui-stage-7.md @@ -61,7 +61,7 @@ URL — источник сохранённого состояния. Back/Forwa 3. **7.4 — формы, детали и полный контекст мониторинга.** Восстановление вкладки/фильтров из URL, понятные единицы и подписи, возврат к списку после действия. Не дублировать сохранённые исправления этапа 1; проверить загрузку, отмену, 400/403/500, timeout и повторное нажатие. 4. **7.5 — приёмка этапа.** Сценарий «проблема → сервер/проверка → действие → возврат» с сохранением контекста; профильные E2E, права в HTTP-моках, TypeScript, lint и build. Реальные JWT/RouterOS отдельно в тестовом окружении. -Следующий исполняемый шаг: 7.5 — профильная приёмка серверов и мониторинга, сквозные переходы, адаптивность форм/Resources/Speed и фиксация ограничений. URL-контекст вкладки, Ping и Resources выполнен. Учесть границы HTTP-моков, экспорт серверов и ограничения сетевых операций из журнала; этап 7 целиком пока не завершён. +Следующий исполняемый шаг: 7.5 — адаптивность форм серверов и таблицы Resources после прокрутки, сквозные переходы, смена backend/mode при незавершённой операции и фиксация ограничений. Формы Ping/Speed и вкладки проверены на 320/390/1440 px; устранены переполнение форм, перекрытие параметров Speed и сдвиг страницы при выборе вкладки. URL-контекст вкладки, Ping и Resources выполнен. Учесть границы HTTP-моков, экспорт серверов и ограничения сетевых операций из журнала; этап 7 целиком пока не завершён. ## Решение по синхронизации URL (7.1) diff --git a/tests/e2e/uptime-links.spec.ts b/tests/e2e/uptime-links.spec.ts index 4adda1bf..251662aa 100644 --- a/tests/e2e/uptime-links.spec.ts +++ b/tests/e2e/uptime-links.spec.ts @@ -567,3 +567,48 @@ for (const extra of ["&rtype=unknown", "&rq=a&rq=b"]) { await expect(page.locator("tr[data-row-id]")).toHaveCount(1) }) } + +for (const width of [320, 390, 1440]) { + test(`приёмка ${width}px: Resources, Speed и формы проб`, async ({ page }) => { + await page.setViewportSize({ width, height: 844 }) + await resourceSetup(page) + await expect(page.locator("tr[data-row-id]")).toHaveCount(1) + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) + await page.screenshot({ path: `test-results/resources-${width}.png`, animations: "disabled" }) + await page.unrouteAll({ behavior: "wait" }) + await setup(page, "/uptime?probe=p1", 0, true, "mm:uptime:write") + await page.getByRole("button", { name: "Пауза", exact: true }).click() + for (const speed of [false, true]) { + if (speed) await page.getByRole("button", { name: /Скорость/ }).click() + await page.getByRole("button", { name: speed ? "Редактировать speed-пробу" : "Редактировать пробу", exact: true }).click() + const dialog = page.getByRole("dialog") + await expect(dialog).toBeVisible() + await expect(dialog.getByRole("button", { name: "Сохранить", exact: true })).toBeInViewport() + await expect(dialog.getByRole("button", { name: "Отмена", exact: true })).toBeInViewport() + await expect.poll(() => dialog.locator("button, input").evaluateAll(elements => elements.filter(el => { + const rect = el.getBoundingClientRect() + return rect.width > 0 && (rect.left < -1 || rect.right > innerWidth + 1) + }).map(el => el.textContent || el.tagName))).toEqual([]) + await page.screenshot({ path: `test-results/${speed ? "speed" : "ping"}-form-${width}.png`, animations: "disabled" }) + await dialog.locator("fieldset").evaluate(el => { el.scrollTop = el.scrollHeight }) + if (speed) { + const direction = await dialog.getByRole("button", { name: "rx", exact: true }).boundingBox() + const duration = await dialog.locator("input").last().boundingBox() + expect(direction).not.toBeNull() + expect(duration).not.toBeNull() + expect(direction!.y + direction!.height).toBeLessThanOrEqual(duration!.y) + } + await page.screenshot({ path: `test-results/${speed ? "speed" : "ping"}-form-bottom-${width}.png`, animations: "disabled" }) + await page.keyboard.press("Escape") + await expect(dialog).toBeHidden() + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) + } + for (const name of [/Пинг-пробы/, /Ресурсы/, /Скорость/]) { + const bounds = await page.getByRole("button", { name }).boundingBox() + expect(bounds).not.toBeNull() + expect(bounds!.x).toBeGreaterThanOrEqual(0) + expect(bounds!.x + bounds!.width).toBeLessThanOrEqual(width) + } + await page.screenshot({ path: `test-results/speed-${width}.png`, animations: "disabled" }) + }) +}