fix(ui): сохранять вкладку и фильтры Ping в URL

This commit is contained in:
Denozordec committed 2026-09-23 09:24:18 +07:00
1 parent f7e0e20673
commit fd7a08d5dc
7 files changed
+157 -9

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
import assert from "node:assert/strict"
import test from "node:test"
import { readUptimeUrl, patchUptimeUrl } from "./uptime-url-state"
test("вкладка и фильтры Ping восстанавливаются из ссылки", () => {
const state = readUptimeUrl(new URLSearchParams({ tab: "speed", q: "узел", status: "down", servers: '["1","x/2"]' }))
assert.deepEqual(state, { tab: "speed", search: "узел", status: "down", servers: ["1", "x/2"], error: null })
})
test("некорректные и повторяющиеся параметры дают ошибку", () => {
for (const raw of ['tab=unknown', 'status=online', 'q=a&q=b', 'servers={}', 'servers=[1]', 'servers=["1","1"]', 'servers=[""]']) {
assert.ok(readUptimeUrl(new URLSearchParams(raw)).error, raw)
}
})
test("сброс оставляет пробу, вкладку и чужие параметры", () => {
const result = patchUptimeUrl(new URLSearchParams('probe=p%2F2&keep=1&tab=speed&q=a&status=down&servers=%5B%221%22%5D'), { q: null, status: null, servers: null })
assert.equal(result, '/uptime?probe=p%2F2&keep=1&tab=speed')
})
+37
View File
@@ -0,0 +1,37 @@
import type { Dispatch, SetStateAction } from "react"
export type UptimeTab = "probes" | "resources" | "speed"
export type ProbeStatusFilter = "all" | "up" | "warn" | "down"
export function readUptimeUrl(params: URLSearchParams) {
const rawTab = params.get("tab")
const rawStatus = params.get("status")
const search = params.get("q") ?? ""
const tab: UptimeTab = rawTab === "resources" || rawTab === "speed" ? rawTab : "probes"
const status: ProbeStatusFilter = rawStatus === "up" || rawStatus === "warn" || rawStatus === "down" ? rawStatus : "all"
let error: string | null = null
let servers: string[] = []
if ((rawTab !== null && !["probes", "resources", "speed"].includes(rawTab)) ||
(rawStatus !== null && !["up", "warn", "down"].includes(rawStatus)) ||
["tab", "q", "status", "servers"].some(key => params.getAll(key).length > 1)) error = "В ссылке указаны неверные или повторяющиеся параметры мониторинга."
const rawServers = params.get("servers")
if (rawServers !== null) {
try {
if (rawServers.length > 8192) throw new Error()
const value: unknown = JSON.parse(rawServers)
if (!Array.isArray(value) || value.length > 50 || !value.every(id => typeof id === "string" && id.length > 0 && id.length <= 128) || new Set(value).size !== value.length) throw new Error()
servers = value
} catch { error = "Не удалось прочитать выбранные серверы из ссылки." }
}
return { tab, search, status, servers, error }
}
export function patchUptimeUrl(params: URLSearchParams, changes: Record<string, string | null>) {
const next = new URLSearchParams(params)
for (const [key, value] of Object.entries(changes)) {
if (value === null || value === "") next.delete(key)
else next.set(key, value)
}
return "/uptime" + (next.size ? "?" + next.toString() : "")
}
export type UrlSetter<T> = Dispatch<SetStateAction<T>>