mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-30 04:40:18 +08:00
fix: apply pending correctness fixes
Cherry-pick the still-relevant fixes from recent draft PRs without pulling in stale release/docs changes: - serialize dashboard data loads to avoid concurrent config self-heal writes - preserve valid per-model default blocks during dashboard model self-heal - pass structured humanizeError results directly to toast for model import scan failures - align frontend kernel isLatest with suffix-aware recommended version ordering Verification: - node --test tests/*.test.js - npm run build
This commit is contained in:
@@ -13,7 +13,7 @@ import { attachCliConflictBanner } from '../components/cli-conflict-banner.js'
|
||||
import { icon } from '../lib/icons.js'
|
||||
|
||||
let _unsubGw = null
|
||||
let _loadInFlight = false
|
||||
let _dashboardLoadChain = Promise.resolve()
|
||||
let _lastGwChangeLoad = 0
|
||||
let _detachCliConflict = null
|
||||
|
||||
@@ -193,16 +193,20 @@ function normalizeDefaultModelConfig(config) {
|
||||
for (const fallback of modelConfig.fallbacks) {
|
||||
nextMap[fallback] = currentMap[fallback] && typeof currentMap[fallback] === 'object' && !Array.isArray(currentMap[fallback]) ? currentMap[fallback] : {}
|
||||
}
|
||||
for (const [key, value] of Object.entries(currentMap)) {
|
||||
if (validModels.has(key) && !nextMap[key]) {
|
||||
nextMap[key] = value && typeof value === 'object' && !Array.isArray(value) ? value : {}
|
||||
}
|
||||
}
|
||||
config.agents.defaults.models = nextMap
|
||||
return modelConfig.primary
|
||||
}
|
||||
|
||||
async function loadDashboardData(page, fullRefresh = false) {
|
||||
// 并发保护:如果上一次加载仍在进行,跳过本次(fullRefresh 除外)
|
||||
if (_loadInFlight && !fullRefresh) return
|
||||
const loadSeq = ++_dashboardLoadSeq
|
||||
_loadInFlight = true
|
||||
try { await _loadDashboardDataInner(page, fullRefresh, loadSeq) } finally { if (loadSeq === _dashboardLoadSeq) _loadInFlight = false }
|
||||
_dashboardLoadChain = _dashboardLoadChain.catch(() => {}).then(() => _loadDashboardDataInner(page, fullRefresh, loadSeq))
|
||||
return _dashboardLoadChain
|
||||
}
|
||||
|
||||
async function _loadDashboardDataInner(page, fullRefresh, loadSeq) {
|
||||
|
||||
@@ -1308,7 +1308,7 @@ async function importClientConfigs(page, state) {
|
||||
const result = await api.scanModelClientConfigs()
|
||||
candidates = Array.isArray(result?.candidates) ? result.candidates : []
|
||||
} catch (e) {
|
||||
toast(`${t('models.importScanFailed')}: ${humanizeError(e)}`, 'error')
|
||||
toast(humanizeError(e, t('models.importScanFailed')), 'error')
|
||||
return
|
||||
} finally {
|
||||
if (btn) { btn.disabled = false; btn.textContent = oldText || t('models.importClientConfigs') }
|
||||
|
||||
Reference in New Issue
Block a user