feat: release OpsXShell 2.1.0 native Tauri edition

This commit is contained in:
Logan.Li committed 2026-07-30 23:32:51 +08:00
1 parent e9a0d21758
commit a3dba0c6ed
311 files changed
+31748 -14897

No files matched your search

+43 -24
View File
@@ -1,17 +1,15 @@
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 {
// 常规
restoreOnStart: boolean
autoSave: boolean
showNotifications: boolean
// 外观
theme: 'dark' | 'light' | 'system'
language: 'zh-CN' | 'en-US'
sidebarWidth: number
// 终端
@@ -21,7 +19,6 @@ export interface AppSettings {
// SSH
keepAlive: boolean
defaultPort: number
timeout: number
// 专业连接管理
@@ -29,36 +26,51 @@ export interface AppSettings {
maxBackgroundConnections: number
idleTimeoutMs: number
suspendTimeoutMs: number
enableSnapshots: boolean
autoReconnect: boolean
maxReconnectAttempts: number
reconnectBaseDelayMs: number
// 安全
encryptPasswords: boolean
lockOnSleep: boolean
// 终端增强
scrollback: number
keywordHighlightEnabled: boolean
keywordHighlightRules: KeywordHighlightRule[]
}
const defaultSettings: AppSettings = {
restoreOnStart: true,
autoSave: true,
showNotifications: false,
theme: 'dark',
language: 'zh-CN',
sidebarWidth: 256,
fontFamily: 'JetBrains Mono',
// Prefer Nerd Font so local zsh powerline prompts render correctly
fontFamily: 'MesloLGS NF',
fontSize: 14,
terminalTheme: 'dracula',
keepAlive: true,
defaultPort: 22,
timeout: 30,
// 专业连接管理默认值
maxConnections: 10,
maxBackgroundConnections: 5,
idleTimeoutMs: 5 * 60 * 1000, // 5 分钟
suspendTimeoutMs: 30 * 60 * 1000, // 30 分钟
enableSnapshots: true,
autoReconnect: true,
encryptPasswords: true,
lockOnSleep: false,
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 {
@@ -75,9 +87,16 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
loadSettings: async () => {
try {
const result = await window.electronAPI?.settingsGet('app-settings')
const result = await window.opsxApi?.settingsGet('app-settings')
if (result?.success && result.value) {
set({ settings: { ...defaultSettings, ...result.value }, isLoaded: true })
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 })
}
@@ -90,12 +109,12 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
setSetting: async (key, value) => {
const newSettings = { ...get().settings, [key]: value }
set({ settings: newSettings })
await window.electronAPI?.settingsSet('app-settings', newSettings)
await window.opsxApi?.settingsSet('app-settings', newSettings)
},
saveSettings: async (newSettings) => {
const merged = { ...get().settings, ...newSettings }
set({ settings: merged })
await window.electronAPI?.settingsSet('app-settings', merged)
await window.opsxApi?.settingsSet('app-settings', merged)
},
}))