mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-26 20:50:30 +08:00
fix format and lint
This commit is contained in:
parent
b7d6ea8e7a
commit
54bb819e28
@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
out
|
||||
.gitignore
|
||||
@ -1,9 +0,0 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react/jsx-runtime',
|
||||
'@electron-toolkit/eslint-config-ts/recommended',
|
||||
'@electron-toolkit/eslint-config-prettier'
|
||||
]
|
||||
}
|
||||
48
eslint.config.cjs
Normal file
48
eslint.config.cjs
Normal file
@ -0,0 +1,48 @@
|
||||
const js = require('@eslint/js')
|
||||
const react = require('eslint-plugin-react')
|
||||
const { configs } = require('@electron-toolkit/eslint-config-ts')
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
ignores: ['**/node_modules/**', '**/dist/**', '**/out/**', '**/extra/**']
|
||||
},
|
||||
|
||||
js.configs.recommended,
|
||||
...configs.recommended,
|
||||
|
||||
{
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
plugins: {
|
||||
react: react
|
||||
},
|
||||
rules: {
|
||||
...react.configs.recommended.rules,
|
||||
...react.configs['jsx-runtime'].rules
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
},
|
||||
languageOptions: {
|
||||
...react.configs.recommended.languageOptions
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
files: ['**/*.cjs', '**/*.mjs', '**/tailwind.config.js', '**/postcss.config.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': 0,
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn'
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import fs from 'fs'
|
||||
import AdmZip from 'adm-zip'
|
||||
import path from 'path'
|
||||
|
||||
@ -9,9 +9,7 @@ import {
|
||||
} from './version-utils.mjs'
|
||||
|
||||
const chat_id = '@MihomoPartyChannel'
|
||||
const pkg = readFileSync('package.json', 'utf-8')
|
||||
const changelog = readFileSync('changelog.md', 'utf-8')
|
||||
const { version: packageVersion } = JSON.parse(pkg)
|
||||
|
||||
// 获取处理后的版本号
|
||||
const version = getProcessedVersion()
|
||||
|
||||
@ -7,9 +7,7 @@ import {
|
||||
generateDownloadLinksMarkdown
|
||||
} from './version-utils.mjs'
|
||||
|
||||
const pkg = readFileSync('package.json', 'utf-8')
|
||||
let changelog = readFileSync('changelog.md', 'utf-8')
|
||||
const { version: packageVersion } = JSON.parse(pkg)
|
||||
|
||||
// 获取处理后的版本号
|
||||
const version = getProcessedVersion()
|
||||
|
||||
@ -78,7 +78,7 @@ export async function createOverride(item: Partial<IOverrideItem>): Promise<IOve
|
||||
},
|
||||
responseType: 'text'
|
||||
})
|
||||
const data = res.data
|
||||
const data = res.data as string
|
||||
await setOverride(id, newItem.ext, data)
|
||||
break
|
||||
}
|
||||
|
||||
@ -418,7 +418,9 @@ export async function convertMrsRuleset(filePath: string, behavior: string): Pro
|
||||
} catch (error) {
|
||||
try {
|
||||
await unlink(tempFilePath)
|
||||
} catch {}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ let runtimeConfig: IMihomoConfig
|
||||
// 辅助函数:处理带偏移量的规则
|
||||
function processRulesWithOffset(ruleStrings: string[], currentRules: string[], isAppend = false) {
|
||||
const normalRules: string[] = []
|
||||
let rules = [...currentRules]
|
||||
const rules = [...currentRules]
|
||||
|
||||
ruleStrings.forEach((ruleStr) => {
|
||||
const parts = ruleStr.split(',')
|
||||
@ -65,7 +65,7 @@ export async function generateProfile(): Promise<void> {
|
||||
controlSniff = true,
|
||||
useNameserverPolicy
|
||||
} = await getAppConfig()
|
||||
let currentProfile = await overrideProfile(current, await getProfile(current))
|
||||
const currentProfile = await overrideProfile(current, await getProfile(current))
|
||||
let controledMihomoConfig = await getControledMihomoConfig()
|
||||
|
||||
// 根据开关状态过滤控制配置
|
||||
@ -132,7 +132,7 @@ export async function generateProfile(): Promise<void> {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('读取或应用规则文件时出错:', error)
|
||||
console.error('读取或应用规则文件时出错:', error)
|
||||
}
|
||||
|
||||
const profile = deepMerge(currentProfile, controledMihomoConfig)
|
||||
|
||||
@ -330,8 +330,8 @@ async function cleanupWindowsNamedPipes(): Promise<void> {
|
||||
process.kill(pid, 0)
|
||||
process.kill(pid, 'SIGTERM')
|
||||
await managerLogger.info(`Terminated process ${pid} to free pipe`)
|
||||
} catch (error: any) {
|
||||
if (error.code !== 'ESRCH') {
|
||||
} catch (error: unknown) {
|
||||
if ((error as { code?: string })?.code !== 'ESRCH') {
|
||||
await managerLogger.warn(`Failed to terminate process ${pid}:`, error)
|
||||
}
|
||||
}
|
||||
@ -351,8 +351,8 @@ async function cleanupWindowsNamedPipes(): Promise<void> {
|
||||
process.kill(pid, 0)
|
||||
process.kill(pid, 'SIGTERM')
|
||||
await managerLogger.info(`Terminated process ${pid} to free pipe`)
|
||||
} catch (error: any) {
|
||||
if (error.code !== 'ESRCH') {
|
||||
} catch (error: unknown) {
|
||||
if ((error as { code?: string })?.code !== 'ESRCH') {
|
||||
await managerLogger.warn(`Failed to terminate process ${pid}:`, error)
|
||||
}
|
||||
}
|
||||
@ -589,8 +589,8 @@ export async function checkAdminPrivileges(): Promise<boolean> {
|
||||
await execPromise('chcp 65001 >nul 2>&1 && fltmc', { encoding: 'utf8' })
|
||||
await managerLogger.info('Admin privileges confirmed via fltmc')
|
||||
return true
|
||||
} catch (fltmcError: any) {
|
||||
const errorCode = fltmcError?.code || 0
|
||||
} catch (fltmcError: unknown) {
|
||||
const errorCode = (fltmcError as { code?: number })?.code || 0
|
||||
await managerLogger.debug(`fltmc failed with code ${errorCode}, trying net session as fallback`)
|
||||
|
||||
try {
|
||||
@ -598,8 +598,8 @@ export async function checkAdminPrivileges(): Promise<boolean> {
|
||||
await execPromise('chcp 65001 >nul 2>&1 && net session', { encoding: 'utf8' })
|
||||
await managerLogger.info('Admin privileges confirmed via net session')
|
||||
return true
|
||||
} catch (netSessionError: any) {
|
||||
const netErrorCode = netSessionError?.code || 0
|
||||
} catch (netSessionError: unknown) {
|
||||
const netErrorCode = (netSessionError as { code?: number })?.code || 0
|
||||
await managerLogger.debug(
|
||||
`Both fltmc and net session failed, no admin privileges. Error codes: fltmc=${errorCode}, net=${netErrorCode}`
|
||||
)
|
||||
@ -618,7 +618,8 @@ export async function showTunPermissionDialog(): Promise<boolean> {
|
||||
|
||||
const title = i18next.t('tun.permissions.title') || '需要管理员权限'
|
||||
const message =
|
||||
i18next.t('tun.permissions.message') || '启用TUN模式需要管理员权限,是否现在重启应用获取权限?'
|
||||
i18next.t('tun.permissions.message') ||
|
||||
'启用 TUN 模式需要管理员权限,是否现在重启应用获取权限?'
|
||||
const confirmText = i18next.t('common.confirm') || '确认'
|
||||
const cancelText = i18next.t('common.cancel') || '取消'
|
||||
|
||||
@ -834,7 +835,9 @@ async function checkHighPrivilegeMihomoProcess(): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundProcesses) {
|
||||
|
||||
@ -5,13 +5,13 @@ import { getAppConfig } from '../config'
|
||||
export async function subStoreSubs(): Promise<ISubStoreSub[]> {
|
||||
const { useCustomSubStore = false, customSubStoreUrl = '' } = await getAppConfig()
|
||||
const baseUrl = useCustomSubStore ? customSubStoreUrl : `http://127.0.0.1:${subStorePort}`
|
||||
const res = await chromeRequest.get(`${baseUrl}/api/subs`, { responseType: 'json' })
|
||||
return res.data.data as ISubStoreSub[]
|
||||
const res = await chromeRequest.get<{ data: ISubStoreSub[] }>(`${baseUrl}/api/subs`, { responseType: 'json' })
|
||||
return res.data.data
|
||||
}
|
||||
|
||||
export async function subStoreCollections(): Promise<ISubStoreSub[]> {
|
||||
const { useCustomSubStore = false, customSubStoreUrl = '' } = await getAppConfig()
|
||||
const baseUrl = useCustomSubStore ? customSubStoreUrl : `http://127.0.0.1:${subStorePort}`
|
||||
const res = await chromeRequest.get(`${baseUrl}/api/collections`, { responseType: 'json' })
|
||||
return res.data.data as ISubStoreSub[]
|
||||
const res = await chromeRequest.get<{ data: ISubStoreSub[] }>(`${baseUrl}/api/collections`, { responseType: 'json' })
|
||||
return res.data.data
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ export async function checkUpdate(): Promise<IAppVersion | undefined> {
|
||||
responseType: 'text'
|
||||
}
|
||||
)
|
||||
const latest = parse(res.data) as IAppVersion
|
||||
const latest = parse(res.data as string) as IAppVersion
|
||||
const currentVersion = app.getVersion()
|
||||
if (compareVersions(latest.version, currentVersion) > 0) {
|
||||
return latest
|
||||
@ -94,7 +94,7 @@ export async function downloadAndInstallUpdate(version: string): Promise<void> {
|
||||
'Content-Type': 'application/octet-stream'
|
||||
}
|
||||
})
|
||||
await writeFile(path.join(dataDir(), file), res.data)
|
||||
await writeFile(path.join(dataDir(), file), res.data as string | Buffer)
|
||||
}
|
||||
if (file.endsWith('.exe')) {
|
||||
try {
|
||||
|
||||
@ -9,7 +9,7 @@ import { floatingWindowLogger } from '../utils/logger'
|
||||
|
||||
export let floatingWindow: BrowserWindow | null = null
|
||||
|
||||
function logError(message: string, error?: any): void {
|
||||
function logError(message: string, error?: unknown): void {
|
||||
floatingWindowLogger.log(`FloatingWindow Error: ${message}`, error).catch(() => {})
|
||||
}
|
||||
|
||||
|
||||
@ -395,7 +395,7 @@ export async function createTray(): Promise<void> {
|
||||
image.setTemplateImage(true)
|
||||
tray?.setImage(image)
|
||||
})
|
||||
// macOS 默认行为: 左键显示窗口, 右键显示菜单
|
||||
// macOS 默认行为:左键显示窗口,右键显示菜单
|
||||
tray?.addListener('click', async () => {
|
||||
if (swapTrayClick) {
|
||||
await updateTrayMenu()
|
||||
@ -537,7 +537,7 @@ export function updateTrayIconImmediate(sysProxyEnabled: boolean, tunEnabled: bo
|
||||
tray.setImage(iconPath)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新托盘图标失败:', error)
|
||||
console.error('更新托盘图标失败:', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -560,6 +560,6 @@ export async function updateTrayIcon(): Promise<void> {
|
||||
tray.setImage(iconPath)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新托盘图标失败:', error)
|
||||
console.error('更新托盘图标失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import { triggerAutoProxy, triggerManualProxy } from '@mihomo-party/sysproxy'
|
||||
import { getAppConfig, getControledMihomoConfig } from '../config'
|
||||
import { pacPort, startPacServer, stopPacServer } from '../resolve/server'
|
||||
import { promisify } from 'util'
|
||||
import { execFile } from 'child_process'
|
||||
import { exec, execFile } from 'child_process'
|
||||
import path from 'path'
|
||||
import { resourcesFilesDir } from '../utils/dirs'
|
||||
import { net } from 'electron'
|
||||
@ -164,8 +164,6 @@ function isSocketFileExists(): boolean {
|
||||
async function requestSocketRecreation(): Promise<void> {
|
||||
try {
|
||||
// Send SIGUSR1 signal to helper process to recreate socket
|
||||
const { exec } = require('child_process')
|
||||
const { promisify } = require('util')
|
||||
const execPromise = promisify(exec)
|
||||
|
||||
// Use osascript with administrator privileges (same pattern as grantTunPermissions)
|
||||
|
||||
@ -17,7 +17,7 @@ export interface RequestOptions {
|
||||
maxRedirects?: number
|
||||
}
|
||||
|
||||
export interface Response<T = any> {
|
||||
export interface Response<T = unknown> {
|
||||
data: T
|
||||
status: number
|
||||
statusText: string
|
||||
@ -29,7 +29,7 @@ export interface Response<T = any> {
|
||||
* Make HTTP request using Chromium's network stack (via electron.net)
|
||||
* This provides better compatibility, HTTP/2 support, and system certificate integration
|
||||
*/
|
||||
export async function request<T = any>(
|
||||
export async function request<T = unknown>(
|
||||
url: string,
|
||||
options: RequestOptions = {}
|
||||
): Promise<Response<T>> {
|
||||
@ -45,7 +45,7 @@ export async function request<T = any>(
|
||||
} = options
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let sessionToUse = session.defaultSession
|
||||
let sessionToUse: Electron.Session | undefined = session.defaultSession
|
||||
let tempPartition: string | null = null
|
||||
|
||||
// Set up proxy if specified
|
||||
@ -64,7 +64,7 @@ export async function request<T = any>(
|
||||
if (tempPartition) {
|
||||
// Note: Electron doesn't provide session.destroy(), but temporary sessions
|
||||
// will be garbage collected when no longer referenced
|
||||
sessionToUse = null as any
|
||||
sessionToUse = undefined
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ export async function request<T = any>(
|
||||
if (timeoutId) clearTimeout(timeoutId)
|
||||
|
||||
const buffer = Buffer.concat(chunks)
|
||||
let data: any
|
||||
let data: unknown
|
||||
|
||||
try {
|
||||
switch (responseType) {
|
||||
@ -141,25 +141,25 @@ export async function request<T = any>(
|
||||
}
|
||||
|
||||
resolve({
|
||||
data,
|
||||
data: data as T,
|
||||
status: statusCode,
|
||||
statusText: statusMessage,
|
||||
headers: responseHeaders,
|
||||
url: url
|
||||
})
|
||||
} catch (error) {
|
||||
reject(new Error(`Failed to parse response: ${error}`))
|
||||
} catch (error: unknown) {
|
||||
reject(new Error(`Failed to parse response: ${String(error)}`))
|
||||
}
|
||||
})
|
||||
|
||||
res.on('error', (error) => {
|
||||
res.on('error', (error: unknown) => {
|
||||
cleanup()
|
||||
if (timeoutId) clearTimeout(timeoutId)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
|
||||
req.on('error', (error) => {
|
||||
req.on('error', (error: unknown) => {
|
||||
cleanup()
|
||||
if (timeoutId) clearTimeout(timeoutId)
|
||||
reject(error)
|
||||
@ -182,9 +182,9 @@ export async function request<T = any>(
|
||||
|
||||
req.end()
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: unknown) => {
|
||||
cleanup()
|
||||
reject(new Error(`Failed to setup proxy: ${error}`))
|
||||
reject(new Error(`Failed to setup proxy: ${String(error)}`))
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -192,7 +192,7 @@ export async function request<T = any>(
|
||||
/**
|
||||
* Convenience method for GET requests
|
||||
*/
|
||||
export const get = <T = any>(
|
||||
export const get = <T = unknown>(
|
||||
url: string,
|
||||
options?: Omit<RequestOptions, 'method' | 'body'>
|
||||
): Promise<Response<T>> => request<T>(url, { ...options, method: 'GET' })
|
||||
@ -200,9 +200,9 @@ export const get = <T = any>(
|
||||
/**
|
||||
* Convenience method for POST requests
|
||||
*/
|
||||
export const post = <T = any>(
|
||||
export const post = <T = unknown>(
|
||||
url: string,
|
||||
data: any,
|
||||
data: unknown,
|
||||
options?: Omit<RequestOptions, 'method' | 'body'>
|
||||
): Promise<Response<T>> => {
|
||||
const body = typeof data === 'string' ? data : JSON.stringify(data)
|
||||
@ -216,9 +216,9 @@ export const post = <T = any>(
|
||||
/**
|
||||
* Convenience method for PUT requests
|
||||
*/
|
||||
export const put = <T = any>(
|
||||
export const put = <T = unknown>(
|
||||
url: string,
|
||||
data: any,
|
||||
data: unknown,
|
||||
options?: Omit<RequestOptions, 'method' | 'body'>
|
||||
): Promise<Response<T>> => {
|
||||
const body = typeof data === 'string' ? data : JSON.stringify(data)
|
||||
@ -232,7 +232,7 @@ export const put = <T = any>(
|
||||
/**
|
||||
* Convenience method for DELETE requests
|
||||
*/
|
||||
export const del = <T = any>(
|
||||
export const del = <T = unknown>(
|
||||
url: string,
|
||||
options?: Omit<RequestOptions, 'method' | 'body'>
|
||||
): Promise<Response<T>> => request<T>(url, { ...options, method: 'DELETE' })
|
||||
@ -240,9 +240,9 @@ export const del = <T = any>(
|
||||
/**
|
||||
* Convenience method for PATCH requests
|
||||
*/
|
||||
export const patch = <T = any>(
|
||||
export const patch = <T = unknown>(
|
||||
url: string,
|
||||
data: any,
|
||||
data: unknown,
|
||||
options?: Omit<RequestOptions, 'method' | 'body'>
|
||||
): Promise<Response<T>> => {
|
||||
const body = typeof data === 'string' ? data : JSON.stringify(data)
|
||||
|
||||
@ -141,7 +141,7 @@ export async function installMihomoCore(version: string): Promise<void> {
|
||||
console.log(`[GitHub] Installing mihomo core version ${version}`)
|
||||
|
||||
const plat = platform()
|
||||
let arch = process.arch
|
||||
const arch = process.arch
|
||||
|
||||
// 映射平台和架构到 GitHub Release 文件名
|
||||
const key = `${plat}-${arch}`
|
||||
|
||||
@ -14,13 +14,13 @@ class Logger {
|
||||
return new Date().toISOString()
|
||||
}
|
||||
|
||||
private formatLogMessage(level: LogLevel, message: string, error?: any): string {
|
||||
private formatLogMessage(level: LogLevel, message: string, error?: unknown): string {
|
||||
const timestamp = this.formatTimestamp()
|
||||
const errorStr = error ? `: ${error}` : ''
|
||||
const errorStr = error ? `: ${String(error)}` : ''
|
||||
return `[${timestamp}] [${level.toUpperCase()}] [${this.moduleName}] ${message}${errorStr}\n`
|
||||
}
|
||||
|
||||
private async writeToFile(level: LogLevel, message: string, error?: any): Promise<void> {
|
||||
private async writeToFile(level: LogLevel, message: string, error?: unknown): Promise<void> {
|
||||
try {
|
||||
const appLogPath = logPath()
|
||||
const logMessage = this.formatLogMessage(level, message, error)
|
||||
@ -35,7 +35,7 @@ class Logger {
|
||||
}
|
||||
}
|
||||
|
||||
private logToConsole(level: LogLevel, message: string, error?: any): void {
|
||||
private logToConsole(level: LogLevel, message: string, error?: unknown): void {
|
||||
const prefix = `[${this.moduleName}] ${message}`
|
||||
|
||||
switch (level) {
|
||||
@ -54,28 +54,28 @@ class Logger {
|
||||
}
|
||||
}
|
||||
|
||||
async debug(message: string, error?: any): Promise<void> {
|
||||
async debug(message: string, error?: unknown): Promise<void> {
|
||||
await this.writeToFile('debug', message, error)
|
||||
this.logToConsole('debug', message, error)
|
||||
}
|
||||
|
||||
async info(message: string, error?: any): Promise<void> {
|
||||
async info(message: string, error?: unknown): Promise<void> {
|
||||
await this.writeToFile('info', message, error)
|
||||
this.logToConsole('info', message, error)
|
||||
}
|
||||
|
||||
async warn(message: string, error?: any): Promise<void> {
|
||||
async warn(message: string, error?: unknown): Promise<void> {
|
||||
await this.writeToFile('warn', message, error)
|
||||
this.logToConsole('warn', message, error)
|
||||
}
|
||||
|
||||
async error(message: string, error?: any): Promise<void> {
|
||||
async error(message: string, error?: unknown): Promise<void> {
|
||||
await this.writeToFile('error', message, error)
|
||||
this.logToConsole('error', message, error)
|
||||
}
|
||||
|
||||
// 兼容原有的 logFloatingWindow 函数签名
|
||||
async log(message: string, error?: any): Promise<void> {
|
||||
async log(message: string, error?: unknown): Promise<void> {
|
||||
if (error) {
|
||||
await this.error(message, error)
|
||||
} else {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import { GenIcon } from 'react-icons'
|
||||
import { GenIcon, IconBaseProps } from 'react-icons'
|
||||
|
||||
function MihomoIcon(props: any): React.JSX.Element {
|
||||
function MihomoIcon(props: IconBaseProps): React.JSX.Element {
|
||||
return GenIcon({
|
||||
tag: 'svg',
|
||||
attr: { viewBox: '0 0 58 61.53' },
|
||||
|
||||
@ -332,7 +332,7 @@ const ConnectionTable: React.FC<Props> = ({
|
||||
const handleSort = useCallback(
|
||||
(columnKey: string) => {
|
||||
let newDirection: 'asc' | 'desc' = 'asc'
|
||||
let newColumn = columnKey
|
||||
const newColumn = columnKey
|
||||
|
||||
if (sortColumn === columnKey) {
|
||||
newDirection = sortDirection === 'asc' ? 'desc' : 'asc'
|
||||
|
||||
@ -140,7 +140,7 @@ const EditInfoModal: React.FC<Props> = (props) => {
|
||||
value={values.interval?.toString() ?? ''}
|
||||
onValueChange={(v) => {
|
||||
// 输入限制
|
||||
if (/^[\d\s*\-,\/]*$/.test(v)) {
|
||||
if (/^[\d\s*\-,/]*$/.test(v)) {
|
||||
// 纯数字
|
||||
if (/^\d+$/.test(v)) {
|
||||
setValues({ ...values, interval: parseInt(v, 10) || 0 })
|
||||
|
||||
@ -411,8 +411,7 @@ interface RuleListItemProps {
|
||||
onRemove: (index: number) => void
|
||||
}
|
||||
|
||||
const RuleListItem = memo<RuleListItemProps>(
|
||||
({
|
||||
const RuleListItemBase: React.FC<RuleListItemProps> = ({
|
||||
rule,
|
||||
originalIndex,
|
||||
isDeleted,
|
||||
@ -496,8 +495,9 @@ const RuleListItem = memo<RuleListItemProps>(
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
(prevProps, nextProps) => {
|
||||
}
|
||||
|
||||
const RuleListItem = memo(RuleListItemBase, (prevProps, nextProps) => {
|
||||
return (
|
||||
prevProps.rule === nextProps.rule &&
|
||||
prevProps.originalIndex === nextProps.originalIndex &&
|
||||
@ -505,8 +505,9 @@ const RuleListItem = memo<RuleListItemProps>(
|
||||
prevProps.isPrependOrAppend === nextProps.isPrependOrAppend &&
|
||||
prevProps.rulesLength === nextProps.rulesLength
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
RuleListItem.displayName = 'RuleListItem'
|
||||
|
||||
const EditRulesModal: React.FC<Props> = (props) => {
|
||||
const { id, onClose } = props
|
||||
@ -563,7 +564,7 @@ const EditRulesModal: React.FC<Props> = (props) => {
|
||||
const content = await getProfileStr(id)
|
||||
setProfileContent(content)
|
||||
|
||||
const parsed = yaml.load(content) as any
|
||||
const parsed = yaml.load(content) as Record<string, unknown> | undefined
|
||||
let initialRules: RuleItem[] = []
|
||||
|
||||
if (parsed && parsed.rules && Array.isArray(parsed.rules)) {
|
||||
@ -593,11 +594,19 @@ const EditRulesModal: React.FC<Props> = (props) => {
|
||||
|
||||
// 添加代理组和代理名称
|
||||
if (Array.isArray(parsed['proxy-groups'])) {
|
||||
groups.push(...parsed['proxy-groups'].map((group: any) => group?.name).filter(Boolean))
|
||||
groups.push(
|
||||
...((parsed['proxy-groups'] as Array<Record<string, unknown>>)
|
||||
.map((group) => (group && typeof group['name'] === 'string' ? (group['name'] as string) : ''))
|
||||
.filter(Boolean) as string[])
|
||||
)
|
||||
}
|
||||
|
||||
if (Array.isArray(parsed['proxies'])) {
|
||||
groups.push(...parsed['proxies'].map((proxy: any) => proxy?.name).filter(Boolean))
|
||||
groups.push(
|
||||
...((parsed['proxies'] as Array<Record<string, unknown>>)
|
||||
.map((proxy) => (proxy && typeof proxy['name'] === 'string' ? (proxy['name'] as string) : ''))
|
||||
.filter(Boolean) as string[])
|
||||
)
|
||||
}
|
||||
|
||||
// 预置出站 https://wiki.metacubex.one/config/proxies/built-in/
|
||||
@ -710,7 +719,7 @@ const EditRulesModal: React.FC<Props> = (props) => {
|
||||
}
|
||||
} catch (ruleError) {
|
||||
// 规则文件读取失败
|
||||
console.debug('规则文件读取失败:', ruleError)
|
||||
console.debug('规则文件读取失败:', ruleError)
|
||||
setRules(initialRules)
|
||||
// 清空规则标记
|
||||
setPrependRules(new Set())
|
||||
|
||||
@ -22,8 +22,7 @@ function delayColor(delay: number): 'primary' | 'success' | 'warning' | 'danger'
|
||||
return 'warning'
|
||||
}
|
||||
|
||||
const ProxyItem: React.FC<Props> = React.memo(
|
||||
(props) => {
|
||||
const ProxyItemBase: React.FC<Props> = (props) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
mutateProxies,
|
||||
@ -61,10 +60,7 @@ const ProxyItem: React.FC<Props> = React.memo(
|
||||
})
|
||||
}, [proxy.name, group.testUrl, onProxyDelay, mutateProxies])
|
||||
|
||||
const fixed = useMemo(
|
||||
() => group.fixed && group.fixed === proxy.name,
|
||||
[group.fixed, proxy.name]
|
||||
)
|
||||
const fixed = useMemo(() => group.fixed && group.fixed === proxy.name, [group.fixed, proxy.name])
|
||||
|
||||
return (
|
||||
<Card
|
||||
@ -177,8 +173,9 @@ const ProxyItem: React.FC<Props> = React.memo(
|
||||
</CardBody>
|
||||
</Card>
|
||||
)
|
||||
},
|
||||
(prevProps, nextProps) => {
|
||||
}
|
||||
|
||||
const ProxyItem = React.memo(ProxyItemBase, (prevProps, nextProps) => {
|
||||
// 必要时重新渲染
|
||||
return (
|
||||
prevProps.proxy.name === nextProps.proxy.name &&
|
||||
@ -188,8 +185,7 @@ const ProxyItem: React.FC<Props> = React.memo(
|
||||
prevProps.group.fixed === nextProps.group.fixed &&
|
||||
prevProps.isGroupTesting === nextProps.isGroupTesting
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
ProxyItem.displayName = 'ProxyItem'
|
||||
|
||||
|
||||
@ -208,7 +208,7 @@ const GeneralConfig: React.FC = () => {
|
||||
type="number"
|
||||
value={autoQuitWithoutCoreDelay.toString()}
|
||||
onValueChange={async (v: string) => {
|
||||
let num = parseInt(v)
|
||||
const num = parseInt(v)
|
||||
await patchAppConfig({ autoQuitWithoutCoreDelay: num })
|
||||
}}
|
||||
onBlur={async (e) => {
|
||||
|
||||
@ -59,7 +59,7 @@ const MihomoConfig: React.FC = () => {
|
||||
type="number"
|
||||
value={(subscriptionTimeout / 1000)?.toString()}
|
||||
onValueChange={async (v: string) => {
|
||||
let num = parseInt(v)
|
||||
const num = parseInt(v)
|
||||
await patchAppConfig({ subscriptionTimeout: num * 1000 })
|
||||
}}
|
||||
onBlur={async (e) => {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import React, { createContext, ReactNode, useContext } from 'react'
|
||||
import { showError } from '@renderer/utils/error-display'
|
||||
import { toast } from '@renderer/components/base/toast'
|
||||
import useSWR from 'swr'
|
||||
import {
|
||||
addProfileItem as add,
|
||||
@ -104,7 +103,7 @@ export const ProfileConfigProvider: React.FC<{ children: ReactNode }> = ({ child
|
||||
// 异步执行后台切换,不阻塞 UI
|
||||
await pendingTask.current
|
||||
} catch (e) {
|
||||
const errorMsg = (e as any)?.message || String(e)
|
||||
const errorMsg = (e as { message?: string })?.message || String(e)
|
||||
// 处理 IPC 超时错误
|
||||
if (errorMsg.includes('reply was never sent')) {
|
||||
setTimeout(() => mutateProfileConfig(), 1000)
|
||||
|
||||
@ -363,7 +363,7 @@
|
||||
"sysproxy.pacEditor.title": "编辑 PAC 脚本",
|
||||
"sysproxy.bypass.title": "代理绕过",
|
||||
"sysproxy.bypass.addDefault": "添加默认代理绕过",
|
||||
"sysproxy.bypass.placeholder": "例: *.baidu.com",
|
||||
"sysproxy.bypass.placeholder": "例:*.baidu.com",
|
||||
"tun.title": "虚拟网卡",
|
||||
"tun.firewall.title": "重设防火墙",
|
||||
"tun.firewall.reset": "重设防火墙",
|
||||
@ -378,7 +378,7 @@
|
||||
"tun.autoDetectInterface": "自动选择流量出口接口",
|
||||
"tun.dnsHijack": "DNS 劫持",
|
||||
"tun.excludeAddress.title": "排除自定义网段",
|
||||
"tun.excludeAddress.placeholder": "例: 172.20.0.0/16",
|
||||
"tun.excludeAddress.placeholder": "例:172.20.0.0/16",
|
||||
"tun.notifications.coreAuthSuccess": "内核授权成功",
|
||||
"tun.notifications.firewallResetSuccess": "防火墙重设成功",
|
||||
"tun.permissions.title": "需要管理员权限",
|
||||
|
||||
@ -363,7 +363,7 @@
|
||||
"sysproxy.pacEditor.title": "編輯 PAC 腳本",
|
||||
"sysproxy.bypass.title": "代理繞過",
|
||||
"sysproxy.bypass.addDefault": "添加默認代理繞過",
|
||||
"sysproxy.bypass.placeholder": "例: *.baidu.com",
|
||||
"sysproxy.bypass.placeholder": "例:*.baidu.com",
|
||||
"tun.title": "虛擬網卡",
|
||||
"tun.firewall.title": "重設防火牆",
|
||||
"tun.firewall.reset": "重設防火牆",
|
||||
@ -378,7 +378,7 @@
|
||||
"tun.autoDetectInterface": "自動選擇流量出口接口",
|
||||
"tun.dnsHijack": "DNS 劫持",
|
||||
"tun.excludeAddress.title": "排除自定義網段",
|
||||
"tun.excludeAddress.placeholder": "例: 172.20.0.0/16",
|
||||
"tun.excludeAddress.placeholder": "例:172.20.0.0/16",
|
||||
"tun.notifications.coreAuthSuccess": "內核授權成功",
|
||||
"tun.notifications.firewallResetSuccess": "防火牆重設成功",
|
||||
"tun.permissions.title": "需要系統管理員權限",
|
||||
|
||||
@ -314,7 +314,7 @@ const Mihomo: React.FC = () => {
|
||||
await restartCore()
|
||||
}
|
||||
|
||||
const handleConfigChangeWithRestart = async (key: string, value: any) => {
|
||||
const handleConfigChangeWithRestart = async (key: string, value: unknown) => {
|
||||
try {
|
||||
await patchAppConfig({ [key]: value })
|
||||
await restartCore()
|
||||
@ -334,8 +334,8 @@ const Mihomo: React.FC = () => {
|
||||
try {
|
||||
const data = await fetchMihomoTags(forceRefresh)
|
||||
setTags(Array.isArray(data) ? data : [])
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch tags:', error)
|
||||
} catch (error: unknown) {
|
||||
console.error('Failed to fetch tags:', String(error))
|
||||
setTags([])
|
||||
toast.error(t('mihomo.error.fetchTagsFailed'))
|
||||
} finally {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { getPlatform, getVersion } from './ipc'
|
||||
// const originError = console.error
|
||||
// const originWarn = console.warn
|
||||
|
||||
@ -11,10 +11,10 @@
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"@renderer/*": [
|
||||
"src/renderer/src/*"
|
||||
"./src/renderer/src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user