fix(ui): показывать неопределённый исход speed и сверять историю
This commit is contained in:
1 parent
96fa910804
commit
8782054078
8 files changed
+145
-11
No files matched your search
@@ -707,7 +707,7 @@ interface SpeedTestRun {
|
|||||||
durationSec: number
|
durationSec: number
|
||||||
txAvgMbps: number | null
|
txAvgMbps: number | null
|
||||||
rxAvgMbps: number | null
|
rxAvgMbps: number | null
|
||||||
status: "running" | "done" | "error"
|
status: "running" | "done" | "error" | "unknown"
|
||||||
command: string
|
command: string
|
||||||
lines: string[]
|
lines: string[]
|
||||||
afterBtPing?: { rttMs: number | null; lossPct: number | null; error: string | null } | null
|
afterBtPing?: { rttMs: number | null; lossPct: number | null; error: string | null } | null
|
||||||
@@ -1077,7 +1077,14 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId
|
|||||||
const [probeRttChartOpen, setProbeRttChartOpen] = useState<Record<string, boolean>>({})
|
const [probeRttChartOpen, setProbeRttChartOpen] = useState<Record<string, boolean>>({})
|
||||||
const [speedBusy, setSpeedBusy] = useState(false)
|
const [speedBusy, setSpeedBusy] = useState(false)
|
||||||
const [speedError, setSpeedError] = useState<string | null>(null)
|
const [speedError, setSpeedError] = useState<string | null>(null)
|
||||||
|
const [speedUnknownRunId, setSpeedUnknownRunId] = useState<string | null>(null)
|
||||||
const [speedRuns, setSpeedRuns] = useState<SpeedTestRun[]>([])
|
const [speedRuns, setSpeedRuns] = useState<SpeedTestRun[]>([])
|
||||||
|
useEffect(() => {
|
||||||
|
if (speedUnknownRunId && speedRuns.some(run => run.id === speedUnknownRunId && (run.status === "done" || run.status === "error"))) {
|
||||||
|
setSpeedUnknownRunId(null)
|
||||||
|
setSpeedError(null)
|
||||||
|
}
|
||||||
|
}, [speedRuns, speedUnknownRunId])
|
||||||
const [speedProbes, setSpeedProbes] = useState<SpeedProbeRow[]>([])
|
const [speedProbes, setSpeedProbes] = useState<SpeedProbeRow[]>([])
|
||||||
const speedReadRevision = useRef(0)
|
const speedReadRevision = useRef(0)
|
||||||
const [speedReads, setSpeedReads] = useState<Record<"probes" | "history", { receivedAt: number | null; error: string | null }>>({ probes: { receivedAt: null, error: null }, history: { receivedAt: null, error: null } })
|
const [speedReads, setSpeedReads] = useState<Record<"probes" | "history", { receivedAt: number | null; error: string | null }>>({ probes: { receivedAt: null, error: null }, history: { receivedAt: null, error: null } })
|
||||||
@@ -1182,7 +1189,10 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId
|
|||||||
srcInterfaceAddress: r.srcInterfaceAddress ?? null,
|
srcInterfaceAddress: r.srcInterfaceAddress ?? null,
|
||||||
dstInterfaceAddress: r.dstInterfaceAddress ?? null,
|
dstInterfaceAddress: r.dstInterfaceAddress ?? null,
|
||||||
}))
|
}))
|
||||||
if (current()) setSpeedRuns(rows)
|
if (current()) setSpeedRuns(previous => [
|
||||||
|
...previous.filter(run => (run.status === "running" || run.status === "unknown") && !rows.some(row => row.id === run.id)),
|
||||||
|
...rows,
|
||||||
|
])
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
}, [apiFetch, liveApi])
|
}, [apiFetch, liveApi])
|
||||||
@@ -1687,6 +1697,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId
|
|||||||
overviewReqRef.current++
|
overviewReqRef.current++
|
||||||
const context = ++saveContext.current
|
const context = ++saveContext.current
|
||||||
setSpeedError(null)
|
setSpeedError(null)
|
||||||
|
setSpeedUnknownRunId(null)
|
||||||
setSpeedBusy(true)
|
setSpeedBusy(true)
|
||||||
const durationSec = Math.max(3, Number.parseInt(probe.durationSec, 10) || 10)
|
const durationSec = Math.max(3, Number.parseInt(probe.durationSec, 10) || 10)
|
||||||
const runId = `speed-${Date.now()}`
|
const runId = `speed-${Date.now()}`
|
||||||
@@ -1806,13 +1817,15 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context !== saveContext.current) return
|
if (context !== saveContext.current) return
|
||||||
const message = serverOperationError(e)
|
const message = serverOperationError(e)
|
||||||
|
const persistenceUnknown = isSpeedPersistenceUnknown(e, runId)
|
||||||
|
setSpeedUnknownRunId(persistenceUnknown ? runId : null)
|
||||||
setSpeedRuns((prev) => prev.map((r) => r.id === runId ? ({
|
setSpeedRuns((prev) => prev.map((r) => r.id === runId ? ({
|
||||||
...r,
|
...r,
|
||||||
status: "error",
|
status: persistenceUnknown ? "unknown" : "error",
|
||||||
lines: [`status: error`, message],
|
lines: [`status: ${persistenceUnknown ? "unknown" : "error"}`, message],
|
||||||
}) : r))
|
}) : r))
|
||||||
setSpeedError(message)
|
setSpeedError(message)
|
||||||
if (!isSpeedPersistenceUnknown(e, runId)) setSpeedProbes((prev) => prev.map((p) => p.id === probe.id ? ({
|
if (!persistenceUnknown) setSpeedProbes((prev) => prev.map((p) => p.id === probe.id ? ({
|
||||||
...p,
|
...p,
|
||||||
lastRunAt: new Date().toISOString(),
|
lastRunAt: new Date().toISOString(),
|
||||||
lastStatus: "error",
|
lastStatus: "error",
|
||||||
@@ -2107,7 +2120,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId
|
|||||||
{/* ── error ── */}
|
{/* ── error ── */}
|
||||||
{speedError && (
|
{speedError && (
|
||||||
<div className="mx-6 mt-4">
|
<div className="mx-6 mt-4">
|
||||||
<Alert variant="destructive" className="py-2 text-xs">
|
<Alert variant={speedUnknownRunId ? "default" : "destructive"} className="py-2 text-xs">
|
||||||
<AlertCircleIcon />
|
<AlertCircleIcon />
|
||||||
<AlertDescription>{speedError}</AlertDescription>
|
<AlertDescription>{speedError}</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
@@ -2160,7 +2173,7 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId
|
|||||||
const run = speedRuns.find((r) =>
|
const run = speedRuns.find((r) =>
|
||||||
sameSpeedMeasurement(r, probe),
|
sameSpeedMeasurement(r, probe),
|
||||||
)
|
)
|
||||||
const useRun = run && (run.status === "running" || (
|
const useRun = run && run.status !== "unknown" && (run.status === "running" || (
|
||||||
probe.lastStatus != null && probe.lastRunAt != null && run.startedAt >= Date.parse(probe.lastRunAt)
|
probe.lastStatus != null && probe.lastRunAt != null && run.startedAt >= Date.parse(probe.lastRunAt)
|
||||||
))
|
))
|
||||||
const viewStatus = useRun ? run.status : (probe.lastStatus === "error" || probe.lastStatus === "done" ? probe.lastStatus : null)
|
const viewStatus = useRun ? run.status : (probe.lastStatus === "error" || probe.lastStatus === "done" ? probe.lastStatus : null)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export interface SpeedTestRunRow {
|
|||||||
durationSec: number
|
durationSec: number
|
||||||
txAvgMbps: number | null
|
txAvgMbps: number | null
|
||||||
rxAvgMbps: number | null
|
rxAvgMbps: number | null
|
||||||
status: "running" | "done" | "error"
|
status: "running" | "done" | "error" | "unknown"
|
||||||
afterBtPing?: { rttMs: number | null; lossPct: number | null; error: string | null } | null
|
afterBtPing?: { rttMs: number | null; lossPct: number | null; error: string | null } | null
|
||||||
srcInterfaceAddress?: string | null
|
srcInterfaceAddress?: string | null
|
||||||
dstInterfaceAddress?: string | null
|
dstInterfaceAddress?: string | null
|
||||||
@@ -130,6 +130,14 @@ function UptimeSpeedHistoryDataGrid({ runs, servers }: UptimeSpeedHistoryDataGri
|
|||||||
if (status === "error") {
|
if (status === "error") {
|
||||||
return <span className="text-[var(--status-offline-fg)] text-xs">error</span>
|
return <span className="text-[var(--status-offline-fg)] text-xs">error</span>
|
||||||
}
|
}
|
||||||
|
if (status === "unknown") {
|
||||||
|
return (
|
||||||
|
<div className="max-w-64 text-xs text-[var(--status-degraded-fg)]">
|
||||||
|
<span>Сохранение не подтверждено</span>
|
||||||
|
<div className="mt-1 font-mono wrap-anywhere">runId: {row.original.id}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return <span className="text-[var(--status-online-fg)] text-xs">done</span>
|
return <span className="text-[var(--status-online-fg)] text-xs">done</span>
|
||||||
},
|
},
|
||||||
meta: { headerTitle: "Статус", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD },
|
meta: { headerTitle: "Статус", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD },
|
||||||
|
|||||||
@@ -117,3 +117,11 @@ BGP-prefix evaluator, отдельное live GRE расписание и recove
|
|||||||
## Локальный snapshot guard — 2026-10-08
|
## Локальный snapshot guard — 2026-10-08
|
||||||
|
|
||||||
12.5.20 сохраняетlastconfirmedspeed snapshot дляunknown502/совпадающегоrunId.2unit tests/frontendtypecheck passed;browserunknownUX ещёнепроверен,patchнеразвёрнут. Backend4c12c55/frontend673e5ba прежние. Следующий12.5.21 — build/browserunknown/deploymentобоихобразов.
|
12.5.20 сохраняетlastconfirmedspeed snapshot дляunknown502/совпадающегоrunId.2unit tests/frontendtypecheck passed;browserunknownUX ещёнепроверен,patchнеразвёрнут. Backend4c12c55/frontend673e5ba прежние. Следующий12.5.21 — build/browserunknown/deploymentобоихобразов.
|
||||||
|
|
||||||
|
## Локальный unknown UX — 2026-10-08
|
||||||
|
|
||||||
|
12.5.21: отдельная строка unknown/runId, сохранение snapshot и сверка по идентификатору при чтении истории. 13 браузерных тестов с HTTP-моками/typecheck/ESLint прошли; это не приёмка real browser/PG. Основной backend4c12c55/frontend673e5ba прежний. Следующий 12.5.22 — сборка и проверка обновлённых образов. Полный 12.5 открыт.
|
||||||
|
|
||||||
|
## Локальный unknown UX — 2026-10-08
|
||||||
|
|
||||||
|
12.5.21: отдельная строка unknown/runId, сохранение snapshot и сверка по идентификатору при чтении истории. 13 браузерных тестов с HTTP-моками/typecheck/ESLint прошли; это не приёмка real browser/PG. Основной backend4c12c55/frontend673e5ba прежний. Следующий 12.5.22 — сборка и проверка обновлённых образов. Полный 12.5 открыт.
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# План реализации UX/UI по пятичасовым окнам
|
# План реализации UX/UI по пятичасовым окнам
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-08:12.5.20 завершёнлокально — unknown502/currentrunId не переписываетподтверждённыйsnapshot пробы.2unit tests/frontendtypecheck passed;временнаястроказапросаещёerror,полныйbrowserunknownUX открыт. Runtimebackend4c12c55/frontend673e5ba прежние. Следующий12.5.21 — build/browserunknownspeed/deploymentобоихобразов.
|
Актуальное продолжение 2026-10-08: 12.5.21 завершён локально — speed unknown отображается отдельно от error, сохраняется при чтении пустой истории и сверяется по runId. Последний подтверждённый snapshot пробы сохранён. 13 браузерных тестов с HTTP-моками, frontend typecheck и ESLint прошли. Основной runtime backend4c12c55/frontend673e5ba прежний. Следующий 12.5.22 — сборка обновлённых образов и приёмка на стенде перед deployment.
|
||||||
|
|
||||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-07. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-07. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||||
|
|
||||||
|
|||||||
+17
-1
@@ -1,6 +1,6 @@
|
|||||||
# UX/UI: журнал реализации
|
# UX/UI: журнал реализации
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-08:12.5.20 завершёнлокально — unknown502/currentrunId не переписываетподтверждённыйsnapshot пробы.2unit tests/frontendtypecheck passed;временнаястроказапросаещёerror,полныйbrowserunknownUX открыт. Runtimebackend4c12c55/frontend673e5ba прежние. Следующий12.5.21 — build/browserunknownspeed/deploymentобоихобразов.
|
Актуальное продолжение 2026-10-08: 12.5.21 завершён локально — speed unknown отображается отдельно от error, сохраняется при чтении пустой истории и сверяется по runId. Последний подтверждённый snapshot пробы сохранён. 13 браузерных тестов с HTTP-моками, frontend typecheck и ESLint прошли. Основной runtime backend4c12c55/frontend673e5ba прежний. Следующий 12.5.22 — сборка обновлённых образов и приёмка на стенде перед deployment.
|
||||||
|
|
||||||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
||||||
|
|
||||||
@@ -34,6 +34,22 @@
|
|||||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
||||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в описанных границах:12.3.83,main1186/1186,context221/221. Этап остаётся в работе: стенд12.5.1–3 развёрнут,bootstrap/smoke проверены;остальные сценарии12.5 не выполнены. |
|
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в описанных границах:12.3.83,main1186/1186,context221/221. Этап остаётся в работе: стенд12.5.1–3 развёрнут,bootstrap/smoke проверены;остальные сценарии12.5 не выполнены. |
|
||||||
|
|
||||||
|
## 12.5.21 — неопределённый исход speed-запуска и сверка с историей (2026-10-08)
|
||||||
|
|
||||||
|
В локальной строке запуска введён status unknown: «Сохранение не подтверждено», с видимым runId; это не новый статус серверного DTO (история API по-прежнему принимает только done/error). При обновлении истории незавершённая или неподтверждённая локальная строка сохраняется, если её идентификатора нет в ответе. Подтверждённая строка с тем же runId заменяет локальную, предупреждение снимается. Unknown не подменяет последний подтверждённый snapshot карточки пробы; предупреждение показано без destructive-оформления. Автоматического повторного сетевого теста нет. Ручной новый запуск остаётся доступен; предупреждение просит проверить историю перед повтором. Состояние локальной строки не сохраняется после перезагрузки страницы.
|
||||||
|
|
||||||
|
Проверки: 13/13 Playwright (uptime-speed-data и uptime-speed-unknown) за 27.7s, включая unknown → пустая история → done/error, сохранение TX42, один POST и адаптацию 320px. Это live-ветка UI с HTTP-моками, не real PG/browser proof. Scoped frontend typecheck (tmp/tsconfig-speed-check.json, исключён старый ignored tmp build context) и ESLint изменённых файлов прошли. Существующие null/zero, malformed DTO, свежесть, независимые источники и Ping-состояния сохранены.
|
||||||
|
|
||||||
|
Основной backend4c12c55/frontend673e5ba не изменён. Новые backend/frontend исправления ещё не развёрнуты. Полный 12.5 открыт. Следующий 12.5.22 — сборка обновлённых образов и приёмка на стенде перед deployment. Локальный коммит без push.
|
||||||
|
|
||||||
|
## 12.5.21 — неопределённый исход speed-запуска и сверка с историей (2026-10-08)
|
||||||
|
|
||||||
|
В локальной строке запуска введён status unknown: «Сохранение не подтверждено», с видимым runId; это не новый статус серверного DTO (история API по-прежнему принимает только done/error). При обновлении истории незавершённая или неподтверждённая локальная строка сохраняется, если её идентификатора нет в ответе. Подтверждённая строка с тем же runId заменяет локальную, предупреждение снимается. Unknown не подменяет последний подтверждённый snapshot карточки пробы; предупреждение показано без destructive-оформления. Автоматического повторного сетевого теста нет. Ручной новый запуск остаётся доступен; предупреждение просит проверить историю перед повтором. Состояние локальной строки не сохраняется после перезагрузки страницы.
|
||||||
|
|
||||||
|
Проверки: 13/13 Playwright (uptime-speed-data и uptime-speed-unknown) за 27.7s, включая unknown → пустая история → done/error, сохранение TX42, один POST и адаптацию 320px. Это live-ветка UI с HTTP-моками, не real PG/browser proof. Scoped frontend typecheck (tmp/tsconfig-speed-check.json, исключён старый ignored tmp build context) и ESLint изменённых файлов прошли. Существующие null/zero, malformed DTO, свежесть, независимые источники и Ping-состояния сохранены.
|
||||||
|
|
||||||
|
Основной backend4c12c55/frontend673e5ba не изменён. Новые backend/frontend исправления ещё не развёрнуты. Полный 12.5 открыт. Следующий 12.5.22 — сборка обновлённых образов и приёмка на стенде перед deployment. Локальный коммит без push.
|
||||||
|
|
||||||
## 12.5.20 — сохранение подтверждённого speed snapshot при unknown receipt (2026-10-08)
|
## 12.5.20 — сохранение подтверждённого speed snapshot при unknown receipt (2026-10-08)
|
||||||
|
|
||||||
Приостатке5%окнавыполненнебольшойлокальныйблокпередdeployment. Frontendcatch раньше ставилlastStatuserror/новыйlastRunAt любойошибкеPOSTspeed-test,включаяunknowncommit. Теперьподтверждённыйsnapshot пробысохраняется,еслиApiClientError502 содержитoutcomeunknown иrunId текущегозапроса. ЧужойrunId/неправильныйpayload/403/обычнаяошибка нераспознаютсякакэтотисход. Существующееservererrorсообщениепоказывается;новыекомпоненты/композицияReUIне менялись. Временнаястрокасамогозапросапо-прежнемуимеетstatuserror; полныйunknown-state/browserUX ещёнужнопроверить.
|
Приостатке5%окнавыполненнебольшойлокальныйблокпередdeployment. Frontendcatch раньше ставилlastStatuserror/новыйlastRunAt любойошибкеPOSTspeed-test,включаяunknowncommit. Теперьподтверждённыйsnapshot пробысохраняется,еслиApiClientError502 содержитoutcomeunknown иrunId текущегозапроса. ЧужойrunId/неправильныйpayload/403/обычнаяошибка нераспознаютсякакэтотисход. Существующееservererrorсообщениепоказывается;новыекомпоненты/композицияReUIне менялись. Временнаястрокасамогозапросапо-прежнемуимеетstatuserror; полныйunknown-state/browserUX ещёнужнопроверить.
|
||||||
|
|||||||
+17
-1
@@ -1,6 +1,6 @@
|
|||||||
# Этап 12: итоговая приёмка UX/UI
|
# Этап 12: итоговая приёмка UX/UI
|
||||||
|
|
||||||
Актуальное продолжение 2026-10-08:12.5.20 завершёнлокально — unknown502/currentrunId не переписываетподтверждённыйsnapshot пробы.2unit tests/frontendtypecheck passed;временнаястроказапросаещёerror,полныйbrowserunknownUX открыт. Runtimebackend4c12c55/frontend673e5ba прежние. Следующий12.5.21 — build/browserunknownspeed/deploymentобоихобразов.
|
Актуальное продолжение 2026-10-08: 12.5.21 завершён локально — speed unknown отображается отдельно от error, сохраняется при чтении пустой истории и сверяется по runId. Последний подтверждённый snapshot пробы сохранён. 13 браузерных тестов с HTTP-моками, frontend typecheck и ESLint прошли. Основной runtime backend4c12c55/frontend673e5ba прежний. Следующий 12.5.22 — сборка обновлённых образов и приёмка на стенде перед deployment.
|
||||||
|
|
||||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||||
|
|
||||||
@@ -1154,3 +1154,19 @@ SchedulerSnapshotError раньшеигнорировалruns[].okfalse уuptime
|
|||||||
Добавленыlib/speed-persistence-outcome.ts и2meaningfultests;подключенguardвuptime/page.tsx. Обаunit tests passed. ПервыйroottscподхватилкопиистарогоCI contextвignoredtmp ивернулисходныеошибкиэтихкопий. Повторныйполныйfrontendtypecheckсвременнымconfig,которыйсохраняетrootoptions/исключения иисключаетtmp,passed; основнойtsconfigне менялся. Diff-check passed. ReUI skillпрочитан: адаптациясуществующегоэкрана,безновойregistryinstallation/редизайна. Browserunknownspeed/productionbuild/deploymentвэтомблокенезапускались.
|
Добавленыlib/speed-persistence-outcome.ts и2meaningfultests;подключенguardвuptime/page.tsx. Обаunit tests passed. ПервыйroottscподхватилкопиистарогоCI contextвignoredtmp ивернулисходныеошибкиэтихкопий. Повторныйполныйfrontendtypecheckсвременнымconfig,которыйсохраняетrootoptions/исключения иисключаетtmp,passed; основнойtsconfigне менялся. Diff-check passed. ReUI skillпрочитан: адаптациясуществующегоэкрана,безновойregistryinstallation/редизайна. Browserunknownspeed/productionbuild/deploymentвэтомблокенезапускались.
|
||||||
|
|
||||||
Основнойruntimebackend4c12c55/frontend673e5ba сохраняется;backendpatchf408afb иfrontendguardещёнеразвёрнуты. Следующий12.5.21 — собратьобаобновлённыхобраза,проверитьbrowserunknownspeed/историю иразвернутьпослепроверок. Журналобновлён;локальныйкоммитбезpush.
|
Основнойruntimebackend4c12c55/frontend673e5ba сохраняется;backendpatchf408afb иfrontendguardещёнеразвёрнуты. Следующий12.5.21 — собратьобаобновлённыхобраза,проверитьbrowserunknownspeed/историю иразвернутьпослепроверок. Журналобновлён;локальныйкоммитбезpush.
|
||||||
|
|
||||||
|
## 12.5.21 — неопределённый исход speed-запуска и сверка с историей (2026-10-08)
|
||||||
|
|
||||||
|
В локальной строке запуска введён status unknown: «Сохранение не подтверждено», с видимым runId; это не новый статус серверного DTO (история API по-прежнему принимает только done/error). При обновлении истории незавершённая или неподтверждённая локальная строка сохраняется, если её идентификатора нет в ответе. Подтверждённая строка с тем же runId заменяет локальную, предупреждение снимается. Unknown не подменяет последний подтверждённый snapshot карточки пробы; предупреждение показано без destructive-оформления. Автоматического повторного сетевого теста нет. Ручной новый запуск остаётся доступен; предупреждение просит проверить историю перед повтором. Состояние локальной строки не сохраняется после перезагрузки страницы.
|
||||||
|
|
||||||
|
Проверки: 13/13 Playwright (uptime-speed-data и uptime-speed-unknown) за 27.7s, включая unknown → пустая история → done/error, сохранение TX42, один POST и адаптацию 320px. Это live-ветка UI с HTTP-моками, не real PG/browser proof. Scoped frontend typecheck (tmp/tsconfig-speed-check.json, исключён старый ignored tmp build context) и ESLint изменённых файлов прошли. Существующие null/zero, malformed DTO, свежесть, независимые источники и Ping-состояния сохранены.
|
||||||
|
|
||||||
|
Основной backend4c12c55/frontend673e5ba не изменён. Новые backend/frontend исправления ещё не развёрнуты. Полный 12.5 открыт. Следующий 12.5.22 — сборка обновлённых образов и приёмка на стенде перед deployment. Локальный коммит без push.
|
||||||
|
|
||||||
|
## 12.5.21 — неопределённый исход speed-запуска и сверка с историей (2026-10-08)
|
||||||
|
|
||||||
|
В локальной строке запуска введён status unknown: «Сохранение не подтверждено», с видимым runId; это не новый статус серверного DTO (история API по-прежнему принимает только done/error). При обновлении истории незавершённая или неподтверждённая локальная строка сохраняется, если её идентификатора нет в ответе. Подтверждённая строка с тем же runId заменяет локальную, предупреждение снимается. Unknown не подменяет последний подтверждённый snapshot карточки пробы; предупреждение показано без destructive-оформления. Автоматического повторного сетевого теста нет. Ручной новый запуск остаётся доступен; предупреждение просит проверить историю перед повтором. Состояние локальной строки не сохраняется после перезагрузки страницы.
|
||||||
|
|
||||||
|
Проверки: 13/13 Playwright (uptime-speed-data и uptime-speed-unknown) за 27.7s, включая unknown → пустая история → done/error, сохранение TX42, один POST и адаптацию 320px. Это live-ветка UI с HTTP-моками, не real PG/browser proof. Scoped frontend typecheck (tmp/tsconfig-speed-check.json, исключён старый ignored tmp build context) и ESLint изменённых файлов прошли. Существующие null/zero, malformed DTO, свежесть, независимые источники и Ping-состояния сохранены.
|
||||||
|
|
||||||
|
Основной backend4c12c55/frontend673e5ba не изменён. Новые backend/frontend исправления ещё не развёрнуты. Полный 12.5 открыт. Следующий 12.5.22 — сборка обновлённых образов и приёмка на стенде перед deployment. Локальный коммит без push.
|
||||||
@@ -125,3 +125,11 @@ ssh -N -L 3000:127.0.0.1:3000 -L 8000:127.0.0.1:8000 root@161.104.46.222
|
|||||||
## Локальный snapshot guard — 2026-10-08
|
## Локальный snapshot guard — 2026-10-08
|
||||||
|
|
||||||
12.5.20 сохраняетlastconfirmedspeed snapshot дляunknown502/совпадающегоrunId.2unit tests/frontendtypecheck passed;browserunknownUX ещёнепроверен,patchнеразвёрнут. Backend4c12c55/frontend673e5ba прежние. Следующий12.5.21 — build/browserunknown/deploymentобоихобразов.
|
12.5.20 сохраняетlastconfirmedspeed snapshot дляunknown502/совпадающегоrunId.2unit tests/frontendtypecheck passed;browserunknownUX ещёнепроверен,patchнеразвёрнут. Backend4c12c55/frontend673e5ba прежние. Следующий12.5.21 — build/browserunknown/deploymentобоихобразов.
|
||||||
|
|
||||||
|
## Локальный unknown UX — 2026-10-08
|
||||||
|
|
||||||
|
12.5.21: отдельная строка unknown/runId, сохранение snapshot и сверка по идентификатору при чтении истории. 13 браузерных тестов с HTTP-моками/typecheck/ESLint прошли; это не приёмка real browser/PG. Основной backend4c12c55/frontend673e5ba прежний. Следующий 12.5.22 — сборка и проверка обновлённых образов. Полный 12.5 открыт.
|
||||||
|
|
||||||
|
## Локальный unknown UX — 2026-10-08
|
||||||
|
|
||||||
|
12.5.21: отдельная строка unknown/runId, сохранение snapshot и сверка по идентификатору при чтении истории. 13 браузерных тестов с HTTP-моками/typecheck/ESLint прошли; это не приёмка real browser/PG. Основной backend4c12c55/frontend673e5ba прежний. Следующий 12.5.22 — сборка и проверка обновлённых образов. Полный 12.5 открыт.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { test, expect } from "@playwright/test"
|
||||||
|
import { server } from "./fixtures/users"
|
||||||
|
|
||||||
|
for (const confirmedStatus of ["done", "error"] as const) {
|
||||||
|
test(`Speed: unknown receipt сохраняет snapshot и сверяется по runId/${confirmedStatus}`, async ({ page }) => {
|
||||||
|
let runId = ""
|
||||||
|
let confirmed = false
|
||||||
|
let writes = 0
|
||||||
|
const probe = {
|
||||||
|
id: "probe-unknown", srcServerId: "1", dstServerId: "2",
|
||||||
|
srcInterface: "ether1", dstInterface: "ether1", protocol: "tcp", direction: "transmit",
|
||||||
|
durationSec: "3", enabled: true, lastStatus: "done", lastRunAt: "2026-10-03T00:00:00Z",
|
||||||
|
lastTxAvgMbps: 42, lastRxAvgMbps: null, lastError: null,
|
||||||
|
}
|
||||||
|
await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
|
||||||
|
await page.route("**/api/**", route => {
|
||||||
|
const path = new URL(route.request().url()).pathname
|
||||||
|
if (path === "/api/uptime/speed-test" && route.request().method() === "POST") {
|
||||||
|
writes++
|
||||||
|
runId = route.request().postDataJSON().runId
|
||||||
|
return route.fulfill({ status: 502, json: {
|
||||||
|
outcome: "unknown", runId,
|
||||||
|
error: `Сетевой тест завершён, сохранение результата не подтверждено. Проверьте историю по runId ${runId} перед повтором`,
|
||||||
|
} })
|
||||||
|
}
|
||||||
|
return route.fulfill({ json:
|
||||||
|
path === "/api/auth/config" ? { required: false } :
|
||||||
|
path === "/api/servers" ? [server, { ...server, id: 2, name: "Приёмник", host: "192.0.2.2" }] :
|
||||||
|
path === "/api/uptime/overview" ? { probes: [], resources: [] } :
|
||||||
|
path === "/api/uptime/speed-probes" ? { probes: [probe] } :
|
||||||
|
path === "/api/uptime/speed-test/runs" ? { runs: confirmed ? [{
|
||||||
|
id: runId, srcServerId: "1", dstServerId: "2", srcInterface: "ether1", dstInterface: "ether1",
|
||||||
|
protocol: "tcp", direction: "transmit", durationSec: 3, status: confirmedStatus,
|
||||||
|
txAvgMbps: confirmedStatus === "done" ? 84 : null, rxAvgMbps: null,
|
||||||
|
error: confirmedStatus === "error" ? "Подтверждённая ошибка" : null,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
}] : [] } : {},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await page.goto("/uptime?tab=speed")
|
||||||
|
await page.getByRole("button", { name: "Пауза", exact: true }).click()
|
||||||
|
const launch = page.getByRole("button", { name: "Запустить", exact: true })
|
||||||
|
const card = launch.locator("xpath=../../..")
|
||||||
|
await expect(card).toContainText("42 Мбит/с")
|
||||||
|
await launch.click()
|
||||||
|
await expect(page.getByText("Сохранение не подтверждено", { exact: true })).toBeVisible()
|
||||||
|
const row = page.locator(`tr[data-row-id="${runId}"]`)
|
||||||
|
await expect(row).toContainText(`runId: ${runId}`)
|
||||||
|
await expect(row).not.toContainText("error")
|
||||||
|
await expect(card).toContainText("42 Мбит/с")
|
||||||
|
await page.setViewportSize({ width: 320, height: 1000 })
|
||||||
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
|
||||||
|
await page.getByRole("button", { name: "Обновить", exact: true }).click()
|
||||||
|
await expect(row).toContainText("Сохранение не подтверждено")
|
||||||
|
await expect(card).toContainText("42 Мбит/с")
|
||||||
|
expect(writes).toBe(1)
|
||||||
|
confirmed = true
|
||||||
|
await page.getByRole("button", { name: "Обновить", exact: true }).click()
|
||||||
|
await expect(row).toContainText(confirmedStatus)
|
||||||
|
await expect(page.getByText("Сохранение не подтверждено", { exact: true })).toHaveCount(0)
|
||||||
|
await expect(page.getByText(/Проверьте историю по runId/)).toHaveCount(0)
|
||||||
|
if (confirmedStatus === "done") await expect(row).toContainText("84 Мбит/с")
|
||||||
|
expect(writes).toBe(1)
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in new issue
Block a user