fix(ui): очищать недоступные интерфейсы при загрузке
This commit is contained in:
1 parent
ab334764cf
commit
2bdcc1621f
5 files changed
+62
-26
No files matched your search
+19
-24
@@ -279,6 +279,14 @@ function filterActiveInterfaces<T extends { running?: boolean; disabled?: boolea
|
||||
return list.filter(isActiveRouterOsInterface)
|
||||
}
|
||||
|
||||
function clearInactiveSpeedInterfaces(draft: SpeedProbeRow, serverId: string, interfaces: Array<{ name: string; running: boolean; disabled: boolean }>): SpeedProbeRow {
|
||||
const active = filterActiveInterfaces(interfaces)
|
||||
const unavailable = (name: string) => name !== "" && !active.some(item => item.name === name)
|
||||
const srcInterface = draft.srcServerId === serverId && unavailable(draft.srcInterface) ? "" : draft.srcInterface
|
||||
const dstInterface = draft.dstServerId === serverId && unavailable(draft.dstInterface) ? "" : draft.dstInterface
|
||||
return srcInterface === draft.srcInterface && dstInterface === draft.dstInterface ? draft : { ...draft, srcInterface, dstInterface }
|
||||
}
|
||||
|
||||
function serverMatchesSearch(server: Server, raw: string): boolean {
|
||||
const q = raw.trim().toLowerCase()
|
||||
if (!q) return true
|
||||
@@ -1291,37 +1299,24 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId
|
||||
|
||||
const loadSpeedInterfaces = useCallback(async (serverId: string) => {
|
||||
if (!liveApi) return
|
||||
if (!serverId || speedIfaces[serverId]) return
|
||||
if (!serverId) return
|
||||
const cached = speedIfaces[serverId]
|
||||
if (cached !== undefined) {
|
||||
setSpeedDraft(previous => clearInactiveSpeedInterfaces(previous, serverId, cached))
|
||||
return
|
||||
}
|
||||
const id = Number.parseInt(serverId, 10)
|
||||
if (!Number.isFinite(id)) return
|
||||
try {
|
||||
const res = await apiFetch<{ interfaces: Array<{ name: string; running: boolean; disabled: boolean; addresses: string[] }> }>(`/api/uptime/speed-test/endpoints/${id}/interfaces`)
|
||||
setSpeedIfaces((prev) => ({ ...prev, [serverId]: res.interfaces ?? [] }))
|
||||
const interfaces = res.interfaces ?? []
|
||||
setSpeedIfaces((prev) => ({ ...prev, [serverId]: interfaces }))
|
||||
setSpeedDraft(previous => clearInactiveSpeedInterfaces(previous, serverId, interfaces))
|
||||
} catch {
|
||||
setSpeedIfaces((prev) => ({ ...prev, [serverId]: [] }))
|
||||
setSpeedDraft(previous => clearInactiveSpeedInterfaces(previous, serverId, []))
|
||||
}
|
||||
}, [apiFetch, liveApi, speedIfaces])
|
||||
|
||||
/** После загрузки списков интерфейсов сбросить выбор, если интерфейс не активен или отсутствует в списке */
|
||||
useEffect(() => {
|
||||
if (!speedSheetOpen) return
|
||||
setSpeedDraft((prev) => {
|
||||
const rawSrc = speedIfaces[prev.srcServerId]
|
||||
const rawDst = speedIfaces[prev.dstServerId]
|
||||
let srcInterface = prev.srcInterface
|
||||
let dstInterface = prev.dstInterface
|
||||
if (rawSrc !== undefined) {
|
||||
const active = filterActiveInterfaces(rawSrc)
|
||||
if (srcInterface && !active.some((i) => i.name === srcInterface)) srcInterface = ""
|
||||
}
|
||||
if (rawDst !== undefined) {
|
||||
const active = filterActiveInterfaces(rawDst)
|
||||
if (dstInterface && !active.some((i) => i.name === dstInterface)) dstInterface = ""
|
||||
}
|
||||
if (srcInterface === prev.srcInterface && dstInterface === prev.dstInterface) return prev
|
||||
return { ...prev, srcInterface, dstInterface }
|
||||
})
|
||||
}, [speedSheetOpen, speedIfaces])
|
||||
}, [apiFetch, liveApi, speedIfaces, setSpeedDraft])
|
||||
|
||||
useEffect(() => {
|
||||
if (!sheetOpen) return
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
## Актуальная точка продолжения — 2026-10-04
|
||||
|
||||
Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. 12.1 принят локально: доступность оболочки/клавиатура/health в описанных сценариях. 12.2.1 принят локально: strict BGP catalog/partial/nullable counters. 12.2.2 принят локально: strict traffic DTO и агрегация без выдуманных точек. 12.2.3 принят локально: observations для server traffic от backend до dashboard. 12.2.4 принят локально: strict servers/probes и unknown server status. 12.2.5 принят локально: реальные ping samples/unknown/ось RTT/Recharts. 12.2.6 принят локально: strict GRE/WireGuard/VXLAN и device failures. 12.2.7 принят локально: strict Internet path snapshot/fallback. 12.2.8 принят локально: подтверждение полного backend сбора. 12.2.9 принят локально: метрики участков и наблюдаемый WAN без эвристической подмены. 12.3.1 принят локально:1000 серверов/штатная пагинация. 12.3.2 принят локально: пагинация CompactDataGrid/1000 строк статистики. 12.3.3 принят локально: порционный DOM очереди проблем. 12.3.4 принят локально: большой BGP каталог/страница при обновлении. Production build и123 профильных browser приняты локально на3978976. 12.2.10 принят локально: обязательные RouterOS поля. 12.3.5 принят локально: страница CompactDataGrid сохраняется при опросе,89 browser и повторный production build прошли. 12.3.6 сохранён: baseline1000 speed probes (ограничение DOM пока не выполнено). 12.3.7 принят локально:50 строк speed-проб/сохранение страницы/глобальная сортировка/1000→1; каталог1001 устройства остаётся в DOM. 12.3.8 принят локально:50 строк ресурсов, URL/поиск/сохранение страницы/1000→1; исправлена pagination оболочки с children, production build и8 больших browser прошли. 12.3.9 принят локально:порционное раскрытие1000 предупреждений ресурсов/клавиатура/axe; исходная ошибка ESLint speedDraft подтверждена. Следующий блок12.3.10:синхронизация speedDraft/формы/build, затем каталог устройств/schedule entries и остальные grids;12.4/12.5 ещё не завершены. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются.
|
||||
Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. 12.1 принят локально: доступность оболочки/клавиатура/health в описанных сценариях. 12.2.1 принят локально: strict BGP catalog/partial/nullable counters. 12.2.2 принят локально: strict traffic DTO и агрегация без выдуманных точек. 12.2.3 принят локально: observations для server traffic от backend до dashboard. 12.2.4 принят локально: strict servers/probes и unknown server status. 12.2.5 принят локально: реальные ping samples/unknown/ось RTT/Recharts. 12.2.6 принят локально: strict GRE/WireGuard/VXLAN и device failures. 12.2.7 принят локально: strict Internet path snapshot/fallback. 12.2.8 принят локально: подтверждение полного backend сбора. 12.2.9 принят локально: метрики участков и наблюдаемый WAN без эвристической подмены. 12.3.1 принят локально:1000 серверов/штатная пагинация. 12.3.2 принят локально: пагинация CompactDataGrid/1000 строк статистики. 12.3.3 принят локально: порционный DOM очереди проблем. 12.3.4 принят локально: большой BGP каталог/страница при обновлении. Production build и123 профильных browser приняты локально на3978976. 12.2.10 принят локально: обязательные RouterOS поля. 12.3.5 принят локально: страница CompactDataGrid сохраняется при опросе,89 browser и повторный production build прошли. 12.3.6 сохранён: baseline1000 speed probes (ограничение DOM пока не выполнено). 12.3.7 принят локально:50 строк speed-проб/сохранение страницы/глобальная сортировка/1000→1; каталог1001 устройства остаётся в DOM. 12.3.8 принят локально:50 строк ресурсов, URL/поиск/сохранение страницы/1000→1; исправлена pagination оболочки с children, production build и8 больших browser прошли. 12.3.9 принят локально:порционное раскрытие1000 предупреждений ресурсов/клавиатура/axe; исходная ошибка ESLint speedDraft подтверждена. 12.3.10 принят локально:недоступные интерфейсы очищаются в обработчиках,54 browser/полный ESLint/production build прошли. Следующий блок12.3.11:ServerTileRail1000 устройств/поиск/URL/клавиатура/mobile Sheet, затем schedule entries и остальные grids;12.4/12.5 ещё не завершены. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются.
|
||||
|
||||
Реальные pg_dump/pg_restore, PG rollback и остановка UDP worker требуют внешней приёмки. Датированные продолжения ниже — история; точный следующий шаг также указан в начале [журнала](ux-ui-progress.md).
|
||||
|
||||
|
||||
@@ -29,13 +29,21 @@
|
||||
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
||||
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | В работе;12.1/12.2.1–12.2.10 и12.3.1–12.3.5 и12.3.7–12.3.9 приняты в описанных локальных границах |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | В работе;12.1/12.2.1–12.2.10 и12.3.1–12.3.5 и12.3.7–12.3.10 приняты в описанных локальных границах |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 12.3.10 — синхронизация интерфейсов формы speed-проб (2026-10-04)
|
||||
|
||||
Исходный set-state-in-effect устранён: недоступный интерфейс очищается при получении списка endpoint и при повторном открытии формы с кэшем. Проверка относится только к совпадающему src/dst serverId; активный интерфейс сохраняется. Effect с синхронным setSpeedDraft удалён, правило ESLint не отключалось. Права и подтверждение сохранения API сохранены.
|
||||
|
||||
54 browser uptime links прошли, включая2 новых сценария active=false/true с холодной загрузкой и повторным открытием/проверкой PUT. Typecheck и полный ESLint изменённой страницы/тестов прошли без ошибок (6 исходных unused warnings). Повторный frontend production/contracts build прошёл:34 страницы; включает ResourceWarnings12.3.9. Живые интерфейсы RouterOS не проверены.
|
||||
|
||||
Следующий блок12.3.11: ограничение DOM ServerTileRail на1000 устройствах с поиском по всему каталогу, выбранным сервером из URL, клавиатурой и мобильным Sheet. Затем оставшиеся25 grids: scheduler ограничен11 job keys, speed history backend limit200, остальные требуют проверки потребителя/API.12.4/12.5 не завершены. Коммит локальный, без push.
|
||||
|
||||
## 12.3.9 — порционный список предупреждений ресурсов (2026-10-04)
|
||||
|
||||
Список1000 серверов с CPU90% воспроизведён через обычный uptime overview:2009 warning nodes/4739 nodes страницы. ResourceWarnings применяет существующий шаблон AttentionRows:5 начальных записей,55 после раскрытия,105 после кнопки,5 после закрытия,55 при повторном раскрытии. Счётчик1000 остаётся полным, причины предупреждений и пороги не менялись. Начальная секция21 nodes, вся страница2751 nodes; таблица50 строк.
|
||||
|
||||
@@ -197,3 +197,11 @@ UptimeResourcesDataGrid использует ReUI client pagination по50 ст
|
||||
9 browser ресурсов/URL/reload/320–1440px и отдельный large-case с WCAG-tagged axe audit предупреждений прошли; Enter/summary и порционное раскрытие проверены. Typecheck прошёл. Полный ESLint uptime page имеет исходную ошибку react-hooks/set-state-in-effect в setSpeedDraft после загрузки интерфейсов (подтверждена на HEAD2762f07),6 исходных unused warnings; с временным отключением этого правила остальные правила не дают ошибок. Это ограничение проверки, правило в файле не отключалось. Последний production build —12.3.8, после ResourceWarnings не повторялся.
|
||||
|
||||
Следующий шаг12.3.10: устранить исходную ошибку синхронизации speedDraft с доступными интерфейсами, проверить формы и production build; затем ServerTileRail на1000 устройствах и оставшиеся25 grids. Демо GRE schedule хранится только в React state, live отдельного расписания нет:1000 entries пока не проверены.12.4/12.5 не завершены; локальная приёмка не доказывает реальные PG/RouterOS операции. Без push.
|
||||
|
||||
## 12.3.10 — синхронизация интерфейсов формы speed-проб (2026-10-04)
|
||||
|
||||
Исходный set-state-in-effect устранён: недоступный интерфейс очищается при получении списка endpoint и при повторном открытии формы с кэшем. Проверка относится только к совпадающему src/dst serverId; активный интерфейс сохраняется. Effect с синхронным setSpeedDraft удалён, правило ESLint не отключалось. Права и подтверждение сохранения API сохранены.
|
||||
|
||||
54 browser uptime links прошли, включая2 новых сценария active=false/true с холодной загрузкой и повторным открытием/проверкой PUT. Typecheck и полный ESLint изменённой страницы/тестов прошли без ошибок (6 исходных unused warnings). Повторный frontend production/contracts build прошёл:34 страницы; включает ResourceWarnings12.3.9. Живые интерфейсы RouterOS не проверены.
|
||||
|
||||
Следующий блок12.3.11: ограничение DOM ServerTileRail на1000 устройствах с поиском по всему каталогу, выбранным сервером из URL, клавиатурой и мобильным Sheet. Затем оставшиеся25 grids: scheduler ограничен11 job keys, speed history backend limit200, остальные требуют проверки потребителя/API.12.4/12.5 не завершены. Коммит локальный, без push.
|
||||
@@ -663,3 +663,28 @@ test('Смена режима через настройки: поздняя ош
|
||||
await expect(page.getByText('Ошибка старого live-подключения', { exact: true })).toHaveCount(0)
|
||||
await expect(page.getByRole('button', { name: 'Новая проба', exact: true })).toBeEnabled()
|
||||
})
|
||||
|
||||
for (const active of [false, true]) test(`Speed interfaces: загрузка и повторное открытие, active=${active}`, async ({ page }) => {
|
||||
await setup(page, "/uptime?tab=speed", 0, false, "mm:uptime:write")
|
||||
const probe = { id: "s1", srcServerId: "1", dstServerId: "2", srcInterface: "ether1", dstInterface: "ether1", protocol: "tcp", direction: "both", durationSec: "10", enabled: true, lastRunAt: null, lastTxAvgMbps: null, lastRxAvgMbps: null, lastStatus: null, lastError: null, lastPingRttMs: null, lastPingLossPct: null, lastPingAt: null, lastPingError: null }
|
||||
const bodies: { probes: Record<string, unknown>[] }[] = []
|
||||
let interfaceCalls = 0
|
||||
await page.route("**/api/uptime/speed-probes", route => {
|
||||
if (route.request().method() === "PUT") { bodies.push(route.request().postDataJSON()); return route.fulfill({ json: { ok: true } }) }
|
||||
return route.fulfill({ json: { probes: [probe] } })
|
||||
})
|
||||
await page.route("**/api/uptime/speed-test/endpoints/*/interfaces", route => { interfaceCalls++; return route.fulfill({ json: { interfaces: [{ name: "ether1", running: active, disabled: !active, addresses: ["192.0.2.1/24"] }] } }) })
|
||||
await page.reload()
|
||||
await page.getByRole("button", { name: "Пауза", exact: true }).click()
|
||||
for (let attempt = 0; attempt < 2; attempt++) {
|
||||
await page.getByRole("button", { name: "Редактировать speed-пробу", exact: true }).click()
|
||||
await expect.poll(() => interfaceCalls).toBe(2)
|
||||
const dialog = page.getByRole("dialog")
|
||||
await expect(dialog).toBeVisible()
|
||||
await dialog.getByRole("button", { name: "Сохранить", exact: true }).click()
|
||||
await expect(dialog).toBeHidden()
|
||||
expect(bodies[attempt].probes[0].srcInterface).toBe(active ? "ether1" : "")
|
||||
expect(bodies[attempt].probes[0].dstInterface).toBe(active ? "ether1" : "")
|
||||
}
|
||||
expect(interfaceCalls).toBe(2)
|
||||
})
|
||||
Reference in new issue
Block a user