fix(backups): показывать ошибки диалогов на узких экранах

This commit is contained in:
Denozordec committed 2026-10-01 16:48:20 +07:00
1 parent b74084b67c
commit ad457b90a9
11 files changed
+53 -5

No files matched your search

@@ -36,7 +36,7 @@ export function BackupDeleteDialog({
<AlertCircleIcon />
</AlertDialogMedia>
<AlertDialogTitle>Удалить бэкап?</AlertDialogTitle>
<AlertDialogDescription>
<AlertDialogDescription className="[overflow-wrap:anywhere]">
Файл <span className="font-mono text-foreground">{backup?.filename}</span> будет удалён
{backup?.storage === "s3" || backup?.storage === "both" ? " локально; объект S3 — через текущее подключение к хранилищу" : " с диска"}.
</AlertDialogDescription>
@@ -77,7 +77,7 @@ export function BackupRestoreDialog({
<TriangleAlertIcon />
</AlertDialogMedia>
<AlertDialogTitle>Восстановить конфигурацию?</AlertDialogTitle>
<AlertDialogDescription>
<AlertDialogDescription className="[overflow-wrap:anywhere]">
<span>
Файл <span className="font-mono text-foreground">{backup?.filename}</span> будет загружен
на <span className="text-foreground">{backup?.server}</span> и импортирован.
@@ -85,7 +85,7 @@ export function BackupRestoreDialog({
</AlertDialogDescription>
<Alert variant="warning">
<TriangleAlertIcon />
<AlertTitle>Это изменит рабочую конфигурацию роутера</AlertTitle>
<AlertTitle className="line-clamp-none">Это изменит рабочую конфигурацию роутера</AlertTitle>
<AlertDescription>
Сессия может оборваться. Убедитесь, что выбран именно этот сервер и этот снимок.
</AlertDescription>
+7 -1
View File
@@ -226,7 +226,7 @@ REST запрос → ожидание → подтверждённый output /
| Пользователи | [Профиль](ux-ui/screens/users-profile-desktop.png), [ошибка](ux-ui/screens/users-error-desktop.png) | [390](ux-ui/screens/users-profile-mobile.png), [320](ux-ui/screens/users-profile-narrow.png) |
| Контейнеры | [Обзор](ux-ui/screens/containers-overview-desktop.png), [снимок](ux-ui/screens/containers-export-desktop.png) | [390](ux-ui/screens/containers-export-mobile.png), [320](ux-ui/screens/containers-export-narrow.png) |
Актуальная точка продолжения: 11А.31.2 — S3/ошибки/диалоги и визуальная приёмка резервных копий. Frame/первые 9 экранов приняты в 11А.31.1. URL/Filters контекст принят в 11А.30. Клиентский checkpoint restore принят в 11А.29.5. Backend outcome неизвестного импорта принят в 11А.29.4. Идентичность receipt принята в 11А.29.3. Backend cleanup удаления принят в 11А.29.2. Frontend delete/restore/download принят в 11А.29.1, затем URL/Frame/визуальная приёмка и scheduler cleanup. Frontend checkpoint/создание/serial polling приняты локально в 11А.28.2. API/основа наблюдения реализованы в 11А.28.1. Настройки расписания/S3 реализованы в 11А.27.1–11А.27.2. Каталоги/source/права реализованы в 11А.25, backend результат ручных операций исправлен в 11А.26. Сертификаты приняты локально в 11А.24, backups API стал строгим. State API, reader, snapshot merge и nullable представление подключены в 11А.14–11А.17.3; таблица требований — [этап 11А](ux-ui-stage-11a.md). Резервные копии и весь 11А ещё не приняты.
Актуальная точка продолжения: 11А.31.2.2 — S3/partial job/initial errors и визуальная приёмка резервных копий. Диалоги ошибок приняты в 11А.31.2.1. Frame/первые 9 экранов приняты в 11А.31.1. URL/Filters контекст принят в 11А.30. Клиентский checkpoint restore принят в 11А.29.5. Backend outcome неизвестного импорта принят в 11А.29.4. Идентичность receipt принята в 11А.29.3. Backend cleanup удаления принят в 11А.29.2. Frontend delete/restore/download принят в 11А.29.1, затем URL/Frame/визуальная приёмка и scheduler cleanup. Frontend checkpoint/создание/serial polling приняты локально в 11А.28.2. API/основа наблюдения реализованы в 11А.28.1. Настройки расписания/S3 реализованы в 11А.27.1–11А.27.2. Каталоги/source/права реализованы в 11А.25, backend результат ручных операций исправлен в 11А.26. Сертификаты приняты локально в 11А.24, backups API стал строгим. State API, reader, snapshot merge и nullable представление подключены в 11А.14–11А.17.3; таблица требований — [этап 11А](ux-ui-stage-11a.md). Резервные копии и весь 11А ещё не приняты.
| Экран | ПК | Телефон |
| --- | --- | --- |
@@ -236,3 +236,9 @@ REST запрос → ожидание → подтверждённый output /
Референсы: [Settings 16](https://reui.io/preview/base/settings-16?ref=mcp), [Data Grid Filtering 2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp), [Sheet 8](https://reui.io/preview/base/sheet-8?ref=mcp). Схема: источник → сводка → история/настройки → immutable цель → подтверждение API/неизвестный результат.
| Экран | ПК | Телефон |
| --- | --- | --- |
| Ошибка удаления | [PNG](ux-ui/screens/backups-delete-error-desktop.png) | [390](ux-ui/screens/backups-delete-error-mobile.png), [320](ux-ui/screens/backups-delete-error-narrow.png) |
| Неизвестный импорт | [PNG](ux-ui/screens/backups-restore-unknown-desktop.png) | [390](ux-ui/screens/backups-restore-unknown-mobile.png), [320](ux-ui/screens/backups-restore-unknown-narrow.png) |
+12 -1
View File
@@ -27,7 +27,7 @@
| 8 | Трафик и статистика | Завершён 2026-09-28 в границах локальной приёмки; ограничения в блоке 8.13 |
| 9 | VPN, Firewall и Filters | Завершён в границах локальной приёмки 2026-09-30; блоки 9.1–9.64, ограничения в 9.64 |
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | В работе: 11А.1–11А.31.1; пользователи/контейнеры/сертификаты приняты локально; резервные копии: Frame/первые экраны, далее 11А.31.2 |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | В работе: 11А.1–11А.31.2.1; пользователи/контейнеры/сертификаты приняты локально; резервные копии: Frame/диалоги, далее 11А.31.2.2 |
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Не начат |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
@@ -36,6 +36,17 @@
## Блок 11А.31.2.1 — ошибки и подтверждения в узких диалогах (2026-10-01)
- Delete/restore описания переносят непрерывное имя файла. Предупреждение изменения рабочей конфигурации не обрезается line-clamp на 320 px. Ошибка удаления сохраняет цель; unknown restore оставляет disabled import/«Закрыть», Escape не объявляет отмену RouterOS.
- 3 keyboard/dialog layout E2E прошли повторно после снятия clamp; профильный ESLint прошёл. 6 PNG ПК/390/320 сохранены, узкий restore просмотрен. Проверены границы диалога по ширине/высоте и отсутствие его внутреннего горизонтального overflow. Production frontend прошёл в 11А.31.1; в этом блоке только CSS отображения и layout тесты, полная сборка не повторялась.
- **Следующий блок 11А.31.2.2:** S3/partial job/initial resource error визуальные состояния, затем backup scheduler cleanup (lock при setup/event сбоях, отделение результата от event/prune) и профильная приёмка. Backup scheduler обнаруженные дефекты пока не исправлены, весь backups/11А не принят. Реальные RouterOS/PostgreSQL/S3 остаются внешней приёмкой.
| Экран | ПК | Телефон |
| --- | --- | --- |
| Ошибка удаления | [PNG](ux-ui/screens/backups-delete-error-desktop.png) | [390](ux-ui/screens/backups-delete-error-mobile.png), [320](ux-ui/screens/backups-delete-error-narrow.png) |
| Неизвестный импорт | [PNG](ux-ui/screens/backups-restore-unknown-desktop.png) | [390](ux-ui/screens/backups-restore-unknown-mobile.png), [320](ux-ui/screens/backups-restore-unknown-narrow.png) |
## Блок 11А.31.1 — Frame и первые адаптивные экраны резервных копий (2026-10-01)
- История/настройки объединены существующим ReUI Frame/FramePanel, добавлены h1/краткая подпись, min-width и адаптивные отступы. Refresh и элементы настроек переносятся. Null status API становится «Неизвестно», а не offline/«недоступен».
+12
View File
@@ -435,3 +435,15 @@
Референсы: [Settings 16](https://reui.io/preview/base/settings-16?ref=mcp), [Data Grid Filtering 2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp), [Sheet 8](https://reui.io/preview/base/sheet-8?ref=mcp). Схема: источник → сводка → история/настройки → immutable цель → подтверждение API/неизвестный результат.
## Блок 11А.31.2.1 — ошибки и подтверждения в узких диалогах (2026-10-01)
- Delete/restore описания переносят непрерывное имя файла. Предупреждение изменения рабочей конфигурации не обрезается line-clamp на 320 px. Ошибка удаления сохраняет цель; unknown restore оставляет disabled import/«Закрыть», Escape не объявляет отмену RouterOS.
- 3 keyboard/dialog layout E2E прошли повторно после снятия clamp; профильный ESLint прошёл. 6 PNG ПК/390/320 сохранены, узкий restore просмотрен. Проверены границы диалога по ширине/высоте и отсутствие его внутреннего горизонтального overflow. Production frontend прошёл в 11А.31.1; в этом блоке только CSS отображения и layout тесты, полная сборка не повторялась.
- **Следующий блок 11А.31.2.2:** S3/partial job/initial resource error визуальные состояния, затем backup scheduler cleanup (lock при setup/event сбоях, отделение результата от event/prune) и профильная приёмка. Backup scheduler обнаруженные дефекты пока не исправлены, весь backups/11А не принят. Реальные RouterOS/PostgreSQL/S3 остаются внешней приёмкой.
| Экран | ПК | Телефон |
| --- | --- | --- |
| Ошибка удаления | [PNG](ux-ui/screens/backups-delete-error-desktop.png) | [390](ux-ui/screens/backups-delete-error-mobile.png), [320](ux-ui/screens/backups-delete-error-narrow.png) |
| Неизвестный импорт | [PNG](ux-ui/screens/backups-restore-unknown-desktop.png) | [390](ux-ui/screens/backups-restore-unknown-mobile.png), [320](ux-ui/screens/backups-restore-unknown-narrow.png) |
Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

+19
View File
@@ -0,0 +1,19 @@
import { test, expect } from "@playwright/test"
import { backup, setupBackups } from "./fixtures/backups"
for (const [name, width] of [["desktop", 1440], ["mobile", 390], ["narrow", 320]] as const) test("Бэкапы: длинный файл и ошибки диалогов/" + name, async ({ page }) => {
await page.setViewportSize({ width, height: 900 }); await setupBackups(page)
const filename = "a".repeat(130) + ".rsc"
await page.route("**/api/backups", r => r.fulfill({ json: [{ ...backup, filename }] }))
await page.route("**/api/backups/backup-1", r => r.fulfill({ status: 503, json: { error: "Хранилище не подтвердило удаление. Запись резервной копии сохранена." } }))
await page.route("**/api/backups/backup-1/restore", r => r.fulfill({ status: 502, json: { outcome: "unknown", error: "Связь с роутером оборвалась после отправки импорта." } }))
await page.goto("/backups"); await page.getByRole("button", { name: "Удалить " + filename, exact: true }).click()
const dialog = page.getByRole("alertdialog"); await dialog.getByRole("button", { name: "Удалить", exact: true }).click(); await expect(dialog).toContainText("Запись резервной копии сохранена")
expect(await dialog.evaluate(element => element.scrollWidth <= element.clientWidth + 1)).toBe(true)
await page.screenshot({ path: "docs/ux-ui/screens/backups-delete-error-" + name + ".png", fullPage: true })
await dialog.getByRole("button", { name: "Отмена", exact: true }).click(); await page.getByRole("button", { name: "Восстановить " + filename, exact: true }).click()
await dialog.getByRole("button", { name: "Восстановить", exact: true }).click(); await expect(dialog).toContainText("Результат импорта неизвестен"); await expect(dialog.getByRole("button", { name: "Восстановить", exact: true })).toBeDisabled()
expect(await dialog.evaluate(element => element.scrollWidth <= element.clientWidth + 1)).toBe(true)
const box = await dialog.boundingBox(); expect(box && box.x >= 0 && box.y >= 0 && box.x + box.width <= width + 1 && box.y + box.height <= 901).toBe(true)
await page.screenshot({ path: "docs/ux-ui/screens/backups-restore-unknown-" + name + ".png", fullPage: true })
await page.keyboard.press("Escape"); await expect(dialog).toHaveCount(0)
})