[verified] refactor: harden operations and redesign device console

This commit is contained in:
chick
2026-07-15 16:33:16 +08:00
parent e04a16e817
commit 4977afdc20
24 changed files with 769 additions and 779 deletions
+30
View File
@@ -0,0 +1,30 @@
export function fleetStatusKind(status) {
if (!status) return 'unknown'
if (!status.reachable) return 'offline'
if (status.authenticated === false) return 'auth'
return 'online'
}
export function filterAndSortFleet(instances, statuses, { filter = 'all', query = '', sort = 'name' } = {}) {
const needle = String(query).trim().toLocaleLowerCase()
const rank = { online: 0, auth: 1, offline: 2, unknown: 3 }
return instances.filter(item => {
const status = statuses.get(item.id)
if (filter !== 'all' && fleetStatusKind(status) !== filter) return false
if (!needle) return true
return [item.id, item.name, item.url, item.description, ...(item.tags || []), JSON.stringify(status?.summary || {})]
.join(' ').toLocaleLowerCase().includes(needle)
}).slice().sort((a, b) => {
const sa = statuses.get(a.id); const sb = statuses.get(b.id)
if (sort === 'latency') return (sa?.latencyMs ?? Infinity) - (sb?.latencyMs ?? Infinity) || String(a.name || a.id).localeCompare(String(b.name || b.id))
if (sort === 'status') return rank[fleetStatusKind(sa)] - rank[fleetStatusKind(sb)] || String(a.name || a.id).localeCompare(String(b.name || b.id))
return String(a.name || a.id).localeCompare(String(b.name || b.id))
})
}
export function emptyFleetReason({ total = 0, query = '', filter = 'all', visible = 0 } = {}) {
if (!total) return 'config'
if (!visible && String(query).trim()) return 'search'
if (!visible && filter !== 'all') return 'filter'
return null
}
+21
View File
@@ -0,0 +1,21 @@
export function instanceDraftPayload(values, editing = false) {
const action = editing ? (values.passwordAction || 'preserve') : (values.passwordAction || (values.password ? 'set' : 'clear'))
if (!['preserve', 'set', 'clear'].includes(action)) throw new Error('无效密码操作')
if (action === 'set' && !String(values.password || '')) throw new Error('设置密码时必须输入密码')
if (action === 'clear' && editing && !values.clearConfirmed) throw new Error('清除密码需要显式确认')
const payload = {
id: String(values.id || '').trim(), name: String(values.name || '').trim(), url: String(values.url || '').trim(),
description: String(values.description || '').trim(), tags: Array.isArray(values.tags) ? values.tags : [], passwordAction: action,
}
if (action === 'set') payload.password = String(values.password)
return payload
}
export function requestDraft(method, path, body) {
const normalizedMethod = String(method || 'GET').toUpperCase()
const result = { method: normalizedMethod, path: String(path || '') }
if (normalizedMethod !== 'GET' && body !== undefined) result.body = body
return result
}
export const isWriteMethod = method => ['POST', 'PUT', 'PATCH', 'DELETE'].includes(String(method).toUpperCase())
+9 -4
View File
@@ -1,14 +1,19 @@
export class RequestCoordinator {
#versions = new Map()
async run(channel, ownerId, operation) {
next(channel) {
const version = (this.#versions.get(channel) || 0) + 1
this.#versions.set(channel, version)
return version
}
isCurrent(channel, version) { return this.#versions.get(channel) === version }
async run(channel, ownerId, operation) {
const version = this.next(channel)
try {
const value = await operation()
return { accepted: this.#versions.get(channel) === version, ownerId, value }
return { accepted: this.isCurrent(channel, version), ownerId, value }
} catch (error) {
return { accepted: this.#versions.get(channel) === version, ownerId, error }
return { accepted: this.isCurrent(channel, version), ownerId, error }
}
}
invalidate(channel) { this.#versions.set(channel, (this.#versions.get(channel) || 0) + 1) }
invalidate(channel) { return this.next(channel) }
}