Files
opsxshell/src/stores/settingsStore.ts
T

121 lines
3.4 KiB
TypeScript

import { create } from 'zustand'
import { createLogger } from '../utils/logger'
import {
DEFAULT_KEYWORD_HIGHLIGHT_RULES,
type KeywordHighlightRule,
} from '../utils/keywordHighlight'
const logger = createLogger('SettingsStore')
export interface AppSettings {
// 外观
theme: 'dark' | 'light' | 'system'
sidebarWidth: number
// 终端
fontFamily: string
fontSize: number
terminalTheme: 'dracula' | 'monokai' | 'solarized' | 'one-dark'
// SSH
keepAlive: boolean
timeout: number
// 专业连接管理
maxConnections: number
maxBackgroundConnections: number
idleTimeoutMs: number
suspendTimeoutMs: number
autoReconnect: boolean
maxReconnectAttempts: number
reconnectBaseDelayMs: number
// 终端增强
scrollback: number
keywordHighlightEnabled: boolean
keywordHighlightRules: KeywordHighlightRule[]
}
const defaultSettings: AppSettings = {
theme: 'dark',
sidebarWidth: 256,
// Prefer Nerd Font so local zsh powerline prompts render correctly
fontFamily: 'MesloLGS NF',
fontSize: 14,
terminalTheme: 'dracula',
keepAlive: true,
timeout: 30,
// 专业连接管理默认值
maxConnections: 10,
maxBackgroundConnections: 5,
idleTimeoutMs: 5 * 60 * 1000, // 5 分钟
suspendTimeoutMs: 30 * 60 * 1000, // 30 分钟
autoReconnect: true,
maxReconnectAttempts: 5,
reconnectBaseDelayMs: 1500,
scrollback: 10000,
keywordHighlightEnabled: true,
keywordHighlightRules: DEFAULT_KEYWORD_HIGHLIGHT_RULES,
}
export function normalizeAppSettings(value: unknown): AppSettings {
const source = value && typeof value === 'object'
? value as Record<string, unknown>
: {}
const normalized: Record<string, unknown> = {}
for (const key of Object.keys(defaultSettings) as Array<keyof AppSettings>) {
const candidate = source[key]
const fallback = defaultSettings[key]
normalized[key] = typeof candidate === typeof fallback ? candidate : fallback
}
return normalized as unknown as AppSettings
}
interface SettingsState {
settings: AppSettings
isLoaded: boolean
setSetting: <K extends keyof AppSettings>(key: K, value: AppSettings[K]) => Promise<void>
loadSettings: () => Promise<void>
saveSettings: (settings: Partial<AppSettings>) => Promise<void>
}
export const useSettingsStore = create<SettingsState>((set, get) => ({
settings: defaultSettings,
isLoaded: false,
loadSettings: async () => {
try {
const result = await window.opsxApi?.settingsGet('app-settings')
if (result?.success && result.value) {
const settings = normalizeAppSettings(result.value)
set({ settings, isLoaded: true })
const storedKeys = Object.keys(result.value as Record<string, unknown>)
const currentKeys = new Set(Object.keys(defaultSettings))
if (storedKeys.some((key) => !currentKeys.has(key))) {
await window.opsxApi?.settingsSet('app-settings', settings)
}
} else {
set({ isLoaded: true })
}
} catch (error) {
logger.error('Failed to load settings:', error)
set({ isLoaded: true })
}
},
setSetting: async (key, value) => {
const newSettings = { ...get().settings, [key]: value }
set({ settings: newSettings })
await window.opsxApi?.settingsSet('app-settings', newSettings)
},
saveSettings: async (newSettings) => {
const merged = { ...get().settings, ...newSettings }
set({ settings: merged })
await window.opsxApi?.settingsSet('app-settings', merged)
},
}))