mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 13:10:30 +08:00
open file
This commit is contained in:
parent
c5c90caa1b
commit
df41310237
@ -1,9 +1,17 @@
|
|||||||
import { exec, execFile, execSync } from 'child_process'
|
import { exec, execFile, execSync } from 'child_process'
|
||||||
import { dialog, nativeTheme } from 'electron'
|
import { dialog, nativeTheme, shell } from 'electron'
|
||||||
import { readFile } from 'fs/promises'
|
import { readFile } from 'fs/promises'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { promisify } from 'util'
|
import { promisify } from 'util'
|
||||||
import { exePath, mihomoCorePath, resourcesDir, resourcesFilesDir, taskDir } from '../utils/dirs'
|
import {
|
||||||
|
exePath,
|
||||||
|
mihomoCorePath,
|
||||||
|
overridePath,
|
||||||
|
profilePath,
|
||||||
|
resourcesDir,
|
||||||
|
resourcesFilesDir,
|
||||||
|
taskDir
|
||||||
|
} from '../utils/dirs'
|
||||||
import { copyFileSync, writeFileSync } from 'fs'
|
import { copyFileSync, writeFileSync } from 'fs'
|
||||||
|
|
||||||
export function getFilePath(ext: string[]): string[] | undefined {
|
export function getFilePath(ext: string[]): string[] | undefined {
|
||||||
@ -18,6 +26,15 @@ export async function readTextFile(filePath: string): Promise<string> {
|
|||||||
return await readFile(filePath, 'utf8')
|
return await readFile(filePath, 'utf8')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function openFile(type: 'profile' | 'override', id: string, ext?: 'yaml' | 'js'): void {
|
||||||
|
if (type === 'profile') {
|
||||||
|
shell.openPath(profilePath(id))
|
||||||
|
}
|
||||||
|
if (type === 'override') {
|
||||||
|
shell.openPath(overridePath(id, ext || 'js'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function openUWPTool(): Promise<void> {
|
export async function openUWPTool(): Promise<void> {
|
||||||
const execFilePromise = promisify(execFile)
|
const execFilePromise = promisify(execFile)
|
||||||
const uwpToolPath = path.join(resourcesDir(), 'files', 'enableLoopback.exe')
|
const uwpToolPath = path.join(resourcesDir(), 'files', 'enableLoopback.exe')
|
||||||
|
|||||||
@ -49,7 +49,14 @@ import {
|
|||||||
import { isEncryptionAvailable, manualGrantCorePermition, restartCore } from '../core/manager'
|
import { isEncryptionAvailable, manualGrantCorePermition, restartCore } from '../core/manager'
|
||||||
import { triggerSysProxy } from '../sys/sysproxy'
|
import { triggerSysProxy } from '../sys/sysproxy'
|
||||||
import { checkUpdate, downloadAndInstallUpdate } from '../resolve/autoUpdater'
|
import { checkUpdate, downloadAndInstallUpdate } from '../resolve/autoUpdater'
|
||||||
import { getFilePath, openUWPTool, readTextFile, setNativeTheme, setupFirewall } from '../sys/misc'
|
import {
|
||||||
|
getFilePath,
|
||||||
|
openFile,
|
||||||
|
openUWPTool,
|
||||||
|
readTextFile,
|
||||||
|
setNativeTheme,
|
||||||
|
setupFirewall
|
||||||
|
} from '../sys/misc'
|
||||||
import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory'
|
import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory'
|
||||||
import { isPortable, setPortable } from './dirs'
|
import { isPortable, setPortable } from './dirs'
|
||||||
import { listWebdavBackups, webdavBackup, webdavDelete, webdavRestore } from '../resolve/backup'
|
import { listWebdavBackups, webdavBackup, webdavDelete, webdavRestore } from '../resolve/backup'
|
||||||
@ -171,6 +178,7 @@ export function registerIpcMainHandlers(): void {
|
|||||||
ipcMain.handle('setNativeTheme', (_e, theme) => {
|
ipcMain.handle('setNativeTheme', (_e, theme) => {
|
||||||
setNativeTheme(theme)
|
setNativeTheme(theme)
|
||||||
})
|
})
|
||||||
|
ipcMain.handle('openFile', (_e, type, id, ext) => openFile(type, id, ext))
|
||||||
ipcMain.handle('copyEnv', ipcErrorWrapper(copyEnv))
|
ipcMain.handle('copyEnv', ipcErrorWrapper(copyEnv))
|
||||||
ipcMain.handle('alert', (_e, msg) => {
|
ipcMain.handle('alert', (_e, msg) => {
|
||||||
dialog.showErrorBox('Mihomo Party', msg)
|
dialog.showErrorBox('Mihomo Party', msg)
|
||||||
|
|||||||
@ -7,23 +7,7 @@ interface Props {
|
|||||||
connection: IMihomoConnectionDetail
|
connection: IMihomoConnectionDetail
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
}
|
}
|
||||||
// sourceIP: string
|
|
||||||
// destinationIP: string
|
|
||||||
// destinationGeoIP: string
|
|
||||||
// destinationIPASN: string
|
|
||||||
// sourcePort: string
|
|
||||||
// destinationPort: string
|
|
||||||
// inboundIP: string
|
|
||||||
// inboundPort: string
|
|
||||||
// inboundName: string
|
|
||||||
// inboundUser: string
|
|
||||||
// host: string
|
|
||||||
// dnsMode: string
|
|
||||||
// specialProxy: string
|
|
||||||
// specialRules: string
|
|
||||||
// remoteDestination: string
|
|
||||||
// dscp: number
|
|
||||||
// sniffHost: string
|
|
||||||
const ConnectionDetailModal: React.FC<Props> = (props) => {
|
const ConnectionDetailModal: React.FC<Props> = (props) => {
|
||||||
const { connection, onClose } = props
|
const { connection, onClose } = props
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import EditInfoModal from './edit-info-modal'
|
|||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import ExecLogModal from './exec-log-modal'
|
import ExecLogModal from './exec-log-modal'
|
||||||
|
import { openFile } from '@renderer/utils/ipc'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
info: IOverrideItem
|
info: IOverrideItem
|
||||||
@ -48,6 +49,13 @@ const menuItems: MenuItem[] = [
|
|||||||
color: 'default',
|
color: 'default',
|
||||||
className: ''
|
className: ''
|
||||||
} as MenuItem,
|
} as MenuItem,
|
||||||
|
{
|
||||||
|
key: 'open-file',
|
||||||
|
label: '打开文件',
|
||||||
|
showDivider: false,
|
||||||
|
color: 'default',
|
||||||
|
className: ''
|
||||||
|
} as MenuItem,
|
||||||
{
|
{
|
||||||
key: 'exec-log',
|
key: 'exec-log',
|
||||||
label: '执行日志',
|
label: '执行日志',
|
||||||
@ -68,8 +76,8 @@ const OverrideItem: React.FC<Props> = (props) => {
|
|||||||
const { info, addOverrideItem, removeOverrideItem, mutateOverrideConfig, updateOverrideItem } =
|
const { info, addOverrideItem, removeOverrideItem, mutateOverrideConfig, updateOverrideItem } =
|
||||||
props
|
props
|
||||||
const [updating, setUpdating] = useState(false)
|
const [updating, setUpdating] = useState(false)
|
||||||
const [openInfo, setOpenInfo] = useState(false)
|
const [openInfoEditor, setOpenInfoEditor] = useState(false)
|
||||||
const [openFile, setOpenFile] = useState(false)
|
const [openFileEditor, setOpenFileEditor] = useState(false)
|
||||||
const [openLog, setOpenLog] = useState(false)
|
const [openLog, setOpenLog] = useState(false)
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
@ -87,11 +95,15 @@ const OverrideItem: React.FC<Props> = (props) => {
|
|||||||
const onMenuAction = (key: Key): void => {
|
const onMenuAction = (key: Key): void => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'edit-info': {
|
case 'edit-info': {
|
||||||
setOpenInfo(true)
|
setOpenInfoEditor(true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'edit-file': {
|
case 'edit-file': {
|
||||||
setOpenFile(true)
|
setOpenFileEditor(true)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'open-file': {
|
||||||
|
openFile('override', info.id, info.ext)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'exec-log': {
|
case 'exec-log': {
|
||||||
@ -128,17 +140,17 @@ const OverrideItem: React.FC<Props> = (props) => {
|
|||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{openFile && (
|
{openFileEditor && (
|
||||||
<EditFileModal
|
<EditFileModal
|
||||||
id={info.id}
|
id={info.id}
|
||||||
language={info.ext === 'yaml' ? 'yaml' : 'javascript'}
|
language={info.ext === 'yaml' ? 'yaml' : 'javascript'}
|
||||||
onClose={() => setOpenFile(false)}
|
onClose={() => setOpenFileEditor(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{openInfo && (
|
{openInfoEditor && (
|
||||||
<EditInfoModal
|
<EditInfoModal
|
||||||
item={info}
|
item={info}
|
||||||
onClose={() => setOpenInfo(false)}
|
onClose={() => setOpenInfoEditor(false)}
|
||||||
updateOverrideItem={updateOverrideItem}
|
updateOverrideItem={updateOverrideItem}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -148,7 +160,7 @@ const OverrideItem: React.FC<Props> = (props) => {
|
|||||||
isPressable
|
isPressable
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (disableOpen) return
|
if (disableOpen) return
|
||||||
setOpenFile(true)
|
setOpenFileEditor(true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import EditFileModal from './edit-file-modal'
|
|||||||
import EditInfoModal from './edit-info-modal'
|
import EditInfoModal from './edit-info-modal'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
|
import { openFile } from '@renderer/utils/ipc'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
info: IProfileItem
|
info: IProfileItem
|
||||||
@ -51,8 +52,8 @@ const ProfileItem: React.FC<Props> = (props) => {
|
|||||||
const total = extra?.total ?? 0
|
const total = extra?.total ?? 0
|
||||||
const [updating, setUpdating] = useState(false)
|
const [updating, setUpdating] = useState(false)
|
||||||
const [selecting, setSelecting] = useState(false)
|
const [selecting, setSelecting] = useState(false)
|
||||||
const [openInfo, setOpenInfo] = useState(false)
|
const [openInfoEditor, setOpenInfoEditor] = useState(false)
|
||||||
const [openFile, setOpenFile] = useState(false)
|
const [openFileEditor, setOpenFileEditor] = useState(false)
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
listeners,
|
listeners,
|
||||||
@ -78,6 +79,13 @@ const ProfileItem: React.FC<Props> = (props) => {
|
|||||||
{
|
{
|
||||||
key: 'edit-file',
|
key: 'edit-file',
|
||||||
label: '编辑文件',
|
label: '编辑文件',
|
||||||
|
showDivider: false,
|
||||||
|
color: 'default',
|
||||||
|
className: ''
|
||||||
|
} as MenuItem,
|
||||||
|
{
|
||||||
|
key: 'open-file',
|
||||||
|
label: '打开文件',
|
||||||
showDivider: true,
|
showDivider: true,
|
||||||
color: 'default',
|
color: 'default',
|
||||||
className: ''
|
className: ''
|
||||||
@ -105,11 +113,15 @@ const ProfileItem: React.FC<Props> = (props) => {
|
|||||||
const onMenuAction = async (key: Key): Promise<void> => {
|
const onMenuAction = async (key: Key): Promise<void> => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'edit-info': {
|
case 'edit-info': {
|
||||||
setOpenInfo(true)
|
setOpenInfoEditor(true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'edit-file': {
|
case 'edit-file': {
|
||||||
setOpenFile(true)
|
setOpenFileEditor(true)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'open-file': {
|
||||||
|
openFile('profile', info.id)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'delete': {
|
case 'delete': {
|
||||||
@ -147,11 +159,11 @@ const ProfileItem: React.FC<Props> = (props) => {
|
|||||||
zIndex: isDragging ? 'calc(infinity)' : undefined
|
zIndex: isDragging ? 'calc(infinity)' : undefined
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{openFile && <EditFileModal id={info.id} onClose={() => setOpenFile(false)} />}
|
{openFileEditor && <EditFileModal id={info.id} onClose={() => setOpenFileEditor(false)} />}
|
||||||
{openInfo && (
|
{openInfoEditor && (
|
||||||
<EditInfoModal
|
<EditInfoModal
|
||||||
item={info}
|
item={info}
|
||||||
onClose={() => setOpenInfo(false)}
|
onClose={() => setOpenInfoEditor(false)}
|
||||||
updateProfileItem={updateProfileItem}
|
updateProfileItem={updateProfileItem}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -297,6 +297,14 @@ export async function setNativeTheme(theme: 'system' | 'light' | 'dark'): Promis
|
|||||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setNativeTheme', theme))
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setNativeTheme', theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function openFile(
|
||||||
|
type: 'profile' | 'override',
|
||||||
|
id: string,
|
||||||
|
ext?: 'yaml' | 'js'
|
||||||
|
): Promise<void> {
|
||||||
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('openFile', type, id, ext))
|
||||||
|
}
|
||||||
|
|
||||||
export async function registerShortcut(
|
export async function registerShortcut(
|
||||||
oldShortcut: string,
|
oldShortcut: string,
|
||||||
newShortcut: string,
|
newShortcut: string,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user