mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-24 04:32:07 +08:00
refactor(settings): route settings-domain commands through the mutate funnel
Ports port saving, webdav/local backup operations, core change/restart/ upgrade, service install/uninstall/repair flows, the system-proxy toggle queue, the DNS override toggle, and app lifecycle commands onto the single funnel. Bespoke flows keep their own error handling via errorNotice:false; simple flows gain the funnel's default error toast and revalidation.
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
restartCore,
|
||||
type ServiceInstallOutcome,
|
||||
} from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import { useAppDispatch, useRunState } from '@/store/app-store-context'
|
||||
|
||||
@@ -74,11 +75,23 @@ export const ServiceMigrationDialog = () => {
|
||||
let outcome: ServiceInstallOutcome | undefined
|
||||
try {
|
||||
if (remedy === 'install') {
|
||||
outcome = await installService()
|
||||
const result = await mutate(() => installService(), {
|
||||
id: 'install-service',
|
||||
errorNotice: false,
|
||||
})
|
||||
if (result.ok) outcome = result.value
|
||||
} else if (remedy === 'repair') {
|
||||
outcome = await repairService()
|
||||
const result = await mutate(() => repairService(), {
|
||||
id: 'repair-service',
|
||||
errorNotice: false,
|
||||
})
|
||||
if (result.ok) outcome = result.value
|
||||
} else {
|
||||
outcome = await reinstallService()
|
||||
const result = await mutate(() => reinstallService(), {
|
||||
id: 'reinstall-service',
|
||||
errorNotice: false,
|
||||
})
|
||||
if (result.ok) outcome = result.value
|
||||
}
|
||||
} catch (error) {
|
||||
showNotice.error(
|
||||
@@ -114,8 +127,11 @@ export const ServiceMigrationDialog = () => {
|
||||
|
||||
let restartSucceeded = false
|
||||
try {
|
||||
await restartCore()
|
||||
restartSucceeded = true
|
||||
const result = await mutate(() => restartCore(), {
|
||||
id: 'restart-core',
|
||||
errorNotice: false,
|
||||
})
|
||||
restartSucceeded = result.ok
|
||||
} catch (error) {
|
||||
showNotice.error(
|
||||
'layout.components.serviceMigration.errors.restartFailed',
|
||||
@@ -145,7 +161,10 @@ export const ServiceMigrationDialog = () => {
|
||||
setWorkflowIncomplete(true)
|
||||
let startupError: unknown
|
||||
try {
|
||||
await continueWithSidecar()
|
||||
await mutate(() => continueWithSidecar(), {
|
||||
id: 'continue-with-sidecar',
|
||||
errorNotice: false,
|
||||
})
|
||||
} catch (error) {
|
||||
startupError = error
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
type PendingFailure,
|
||||
type ServiceInstallOutcome,
|
||||
} from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import {
|
||||
clearServiceRequest,
|
||||
@@ -103,10 +104,18 @@ export const SysproxyPrivilegeDialog = () => {
|
||||
let outcome: ServiceInstallOutcome | undefined
|
||||
if (remedy === 'reinstallAndRestart') {
|
||||
setStep('installing')
|
||||
outcome = await reinstallService()
|
||||
const result = await mutate(() => reinstallService(), {
|
||||
id: 'reinstall-service',
|
||||
errorNotice: false,
|
||||
})
|
||||
if (result.ok) outcome = result.value
|
||||
} else if (remedy === 'installAndRestart') {
|
||||
setStep('installing')
|
||||
outcome = await installService()
|
||||
const result = await mutate(() => installService(), {
|
||||
id: 'install-service',
|
||||
errorNotice: false,
|
||||
})
|
||||
if (result.ok) outcome = result.value
|
||||
}
|
||||
if (outcome?.status === 'sidecar') {
|
||||
showNotice.warning(
|
||||
@@ -118,7 +127,10 @@ export const SysproxyPrivilegeDialog = () => {
|
||||
return
|
||||
}
|
||||
setStep('restarting')
|
||||
await restartCore()
|
||||
await mutate(() => restartCore(), {
|
||||
id: 'restart-core',
|
||||
errorNotice: false,
|
||||
})
|
||||
|
||||
const runState = await getRuntimeState()
|
||||
const usingAdminFallback =
|
||||
@@ -131,7 +143,10 @@ export const SysproxyPrivilegeDialog = () => {
|
||||
if (runState.mode === 'Service' || usingAdminFallback) {
|
||||
if (restoring !== undefined) {
|
||||
setStep('applying')
|
||||
await patchVergeConfig(restoring)
|
||||
await mutate(() => patchVergeConfig(restoring), {
|
||||
id: 'sysproxy-privilege-restore',
|
||||
errorNotice: false,
|
||||
})
|
||||
}
|
||||
if (!usingAdminFallback) {
|
||||
showNotice.success(
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useNavigate } from 'react-router'
|
||||
import { useSystemState } from '@/hooks/use-system-state'
|
||||
import { useAppRefreshers } from '@/providers/app-data-context'
|
||||
import { openLogsDir, restartCore } from '@/services/cmds'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import { mutate } from '@/services/mutate'
|
||||
|
||||
import type { ProxyEmptyStateReason } from './proxy-empty-state-model'
|
||||
|
||||
@@ -25,10 +25,10 @@ export const ProxyEmptyState = ({ reason }: Props) => {
|
||||
const handleRestart = useLockFn(async () => {
|
||||
setIsRestarting(true)
|
||||
try {
|
||||
await restartCore()
|
||||
await mutate(() => restartCore(), { id: 'restart-core' })
|
||||
await Promise.all([refreshProxy(), mutateSystemState()])
|
||||
} catch (error) {
|
||||
showNotice.error(error)
|
||||
} catch {
|
||||
// the funnel already notified
|
||||
} finally {
|
||||
setIsRestarting(false)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { useVerge } from '@/hooks/use-verge'
|
||||
import { saveWebdavConfig, createWebdavBackup } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { errorDetail, showNotice } from '@/services/notice-service'
|
||||
import {
|
||||
buildWebdavSignature,
|
||||
@@ -119,7 +120,13 @@ export const BackupConfigViewer = memo(
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
await saveWebdavConfig(trimmedUrl, trimmedUsername, data.password)
|
||||
await mutate(
|
||||
() => saveWebdavConfig(trimmedUrl, trimmedUsername, data.password),
|
||||
{
|
||||
id: 'save-webdav-config',
|
||||
errorNotice: false,
|
||||
},
|
||||
)
|
||||
await mutateVerge(
|
||||
(current) =>
|
||||
current
|
||||
@@ -156,7 +163,10 @@ export const BackupConfigViewer = memo(
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
await createWebdavBackup().then(async () => {
|
||||
await mutate(() => createWebdavBackup(), {
|
||||
id: 'create-webdav-backup',
|
||||
errorNotice: false,
|
||||
}).then(async () => {
|
||||
showNotice.success('settings.modals.backup.messages.backupCreated')
|
||||
await onBackupSuccess()
|
||||
})
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
restoreLocalBackup,
|
||||
restoreWebDavBackup,
|
||||
} from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import {
|
||||
buildWebdavSignature,
|
||||
@@ -228,17 +229,29 @@ export const BackupHistoryViewer = ({
|
||||
try {
|
||||
if (action === 'delete') {
|
||||
if (actionIsLocal) {
|
||||
await deleteLocalBackup(filename)
|
||||
await mutate(() => deleteLocalBackup(filename), {
|
||||
id: 'delete-local-backup',
|
||||
errorNotice: false,
|
||||
})
|
||||
} else {
|
||||
await deleteWebdavBackup(filename)
|
||||
await mutate(() => deleteWebdavBackup(filename), {
|
||||
id: 'delete-webdav-backup',
|
||||
errorNotice: false,
|
||||
})
|
||||
}
|
||||
setPendingConfirmation(null)
|
||||
await fetchRows()
|
||||
} else {
|
||||
if (actionIsLocal) {
|
||||
await restoreLocalBackup(filename)
|
||||
await mutate(() => restoreLocalBackup(filename), {
|
||||
id: 'restore-local-backup',
|
||||
errorNotice: false,
|
||||
})
|
||||
} else {
|
||||
await restoreWebDavBackup(filename)
|
||||
await mutate(() => restoreWebDavBackup(filename), {
|
||||
id: 'restore-webdav-backup',
|
||||
errorNotice: false,
|
||||
})
|
||||
}
|
||||
setPendingConfirmation(null)
|
||||
showNotice.success('settings.modals.backup.messages.restoreSuccess')
|
||||
@@ -265,8 +278,11 @@ export const BackupHistoryViewer = ({
|
||||
const savePath = await save({ defaultPath: filename })
|
||||
if (!savePath || Array.isArray(savePath)) return
|
||||
try {
|
||||
await exportLocalBackup(filename, savePath)
|
||||
showNotice.success('settings.modals.backup.messages.localBackupExported')
|
||||
await mutate(() => exportLocalBackup(filename, savePath), {
|
||||
id: 'export-local-backup',
|
||||
errorNotice: false,
|
||||
successNotice: 'settings.modals.backup.messages.localBackupExported',
|
||||
})
|
||||
} catch (ignoreError: unknown) {
|
||||
showNotice.error(
|
||||
'settings.modals.backup.messages.localBackupExportFailed',
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
createWebdavBackup,
|
||||
importLocalBackup,
|
||||
} from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { errorDetail, showNotice } from '@/services/notice-service'
|
||||
import { buildWebdavSignature, setWebdavStatus } from '@/services/webdav-status'
|
||||
|
||||
@@ -55,12 +56,18 @@ export function BackupViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
try {
|
||||
setBusyAction(target)
|
||||
if (target === 'local') {
|
||||
await createLocalBackup()
|
||||
showNotice.success('settings.modals.backup.messages.localBackupCreated')
|
||||
await mutate(() => createLocalBackup(), {
|
||||
id: 'create-local-backup',
|
||||
errorNotice: false,
|
||||
successNotice: 'settings.modals.backup.messages.localBackupCreated',
|
||||
})
|
||||
} else {
|
||||
await createWebdavBackup()
|
||||
showNotice.success('settings.modals.backup.messages.backupCreated')
|
||||
setWebdavStatus(webdavSignature, 'ready')
|
||||
await mutate(() => createWebdavBackup(), {
|
||||
id: 'create-webdav-backup',
|
||||
errorNotice: false,
|
||||
successNotice: 'settings.modals.backup.messages.backupCreated',
|
||||
onFulfilled: () => setWebdavStatus(webdavSignature, 'ready'),
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
@@ -86,8 +93,11 @@ export function BackupViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
if (!selected || Array.isArray(selected)) return
|
||||
try {
|
||||
setLocalImporting(true)
|
||||
await importLocalBackup(selected)
|
||||
showNotice.success('settings.modals.backup.messages.localBackupImported')
|
||||
await mutate(() => importLocalBackup(selected), {
|
||||
id: 'import-local-backup',
|
||||
errorNotice: false,
|
||||
successNotice: 'settings.modals.backup.messages.localBackupImported',
|
||||
})
|
||||
openHistory('local')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
||||
@@ -21,6 +21,7 @@ import { BaseDialog, DialogRef } from '@/components/base'
|
||||
import { useClash, useClashInfo } from '@/hooks/use-clash'
|
||||
import { useVerge } from '@/hooks/use-verge'
|
||||
import { changeClashCore, restartCore, upgradeClashCore } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
|
||||
const VALID_CORE = [
|
||||
@@ -60,8 +61,16 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
try {
|
||||
setChangingCore(core)
|
||||
closeAllConnections()
|
||||
const errorMsg = await changeClashCore(core)
|
||||
void mutate(() => closeAllConnections(), {
|
||||
id: 'close-all-connections',
|
||||
errorNotice: false,
|
||||
})
|
||||
const result = await mutate(() => changeClashCore(core), {
|
||||
id: 'change-clash-core',
|
||||
errorNotice: false,
|
||||
})
|
||||
if (!result.ok) return
|
||||
const errorMsg = result.value
|
||||
|
||||
if (errorMsg) {
|
||||
showNotice.error(errorMsg)
|
||||
@@ -83,28 +92,33 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
const onRestart = useLockFn(async () => {
|
||||
try {
|
||||
setRestarting(true)
|
||||
await restartCore()
|
||||
showNotice.success(
|
||||
t('settings.feedback.notifications.clash.restartSuccess'),
|
||||
)
|
||||
await mutate(() => restartCore(), {
|
||||
id: 'restart-core',
|
||||
successNotice: t(
|
||||
'settings.feedback.notifications.clash.restartSuccess',
|
||||
),
|
||||
})
|
||||
setRestarting(false)
|
||||
} catch (err) {
|
||||
} catch {
|
||||
setRestarting(false)
|
||||
showNotice.error(err)
|
||||
}
|
||||
})
|
||||
|
||||
const onUpgrade = useLockFn(async () => {
|
||||
try {
|
||||
setUpgrading(true)
|
||||
const report = await upgradeClashCore()
|
||||
showNotice.success(
|
||||
report.upgraded
|
||||
? t('settings.feedback.notifications.clash.versionUpdated')
|
||||
: t('settings.feedback.notifications.clash.alreadyLatestVersion'),
|
||||
)
|
||||
} catch (err) {
|
||||
showNotice.error(err)
|
||||
await mutate(() => upgradeClashCore(), {
|
||||
id: 'upgrade-clash-core',
|
||||
onFulfilled: (report) => {
|
||||
showNotice.success(
|
||||
report.upgraded
|
||||
? t('settings.feedback.notifications.clash.versionUpdated')
|
||||
: t('settings.feedback.notifications.clash.alreadyLatestVersion'),
|
||||
)
|
||||
},
|
||||
})
|
||||
} catch {
|
||||
// the funnel already notified
|
||||
} finally {
|
||||
setUpgrading(false)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ import { useTranslation } from 'react-i18next'
|
||||
import { BaseDialog, Switch } from '@/components/base'
|
||||
import { useDisplayedMixedPort } from '@/hooks/use-displayed-mixed-port'
|
||||
import { useVerge } from '@/hooks/use-verge'
|
||||
import { saveProxyPorts } from '@/services/cmds'
|
||||
import { saveProxyPorts, type ProxyPortSettings } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import getSystem from '@/utils/get-system'
|
||||
|
||||
@@ -57,22 +58,31 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
)
|
||||
|
||||
// 添加保存请求,防止GUI卡死
|
||||
const { loading, runAsync: saveSettings } = useRequest(saveProxyPorts, {
|
||||
manual: true,
|
||||
onSuccess: (outcome) => {
|
||||
if (outcome.status === 'conflict') {
|
||||
showNotice.error('settings.modals.clashPort.messages.portInUse', {
|
||||
port: outcome.port,
|
||||
})
|
||||
return
|
||||
}
|
||||
setOpen(false)
|
||||
showNotice.success('settings.modals.clashPort.messages.saved')
|
||||
const { loading, runAsync: saveSettings } = useRequest(
|
||||
async (settings: ProxyPortSettings) =>
|
||||
mutate(() => saveProxyPorts(settings), {
|
||||
id: 'save-proxy-ports',
|
||||
errorNotice: false,
|
||||
}),
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: (result) => {
|
||||
if (!result.ok) return
|
||||
const outcome = result.value
|
||||
if (outcome.status === 'conflict') {
|
||||
showNotice.error('settings.modals.clashPort.messages.portInUse', {
|
||||
port: outcome.port,
|
||||
})
|
||||
return
|
||||
}
|
||||
setOpen(false)
|
||||
showNotice.success('settings.modals.clashPort.messages.saved')
|
||||
},
|
||||
onError: (error) => {
|
||||
showNotice.error('settings.modals.clashPort.messages.saveFailed', error)
|
||||
},
|
||||
},
|
||||
onError: (error) => {
|
||||
showNotice.error('settings.modals.clashPort.messages.saveFailed', error)
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { BaseDialog, Switch } from '@/components/base'
|
||||
import { useClash } from '@/hooks/use-clash'
|
||||
import { restartCore } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
|
||||
// Development origins must never be persisted into production configuration.
|
||||
@@ -135,7 +136,10 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
),
|
||||
},
|
||||
})
|
||||
await restartCore()
|
||||
await mutate(() => restartCore(), {
|
||||
id: 'restart-core',
|
||||
errorNotice: false,
|
||||
})
|
||||
await mutateClash()
|
||||
},
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { Options as ReactMarkdownOptions } from 'react-markdown'
|
||||
import { BaseDialog, DialogRef } from '@/components/base'
|
||||
import { useUpdate } from '@/hooks/use-update'
|
||||
import { restartApp } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import { useSetUpdateState, useUpdateState } from '@/services/states'
|
||||
import { openExternalUrl } from '@/utils/open-external-url'
|
||||
@@ -270,8 +271,14 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}
|
||||
|
||||
try {
|
||||
await updateInfo.downloadAndInstall(onDownloadEvent)
|
||||
await restartApp()
|
||||
await mutate(() => updateInfo.downloadAndInstall(onDownloadEvent), {
|
||||
id: 'install-app-update',
|
||||
errorNotice: false,
|
||||
})
|
||||
await mutate(() => restartApp(), {
|
||||
id: 'restart-app',
|
||||
errorNotice: false,
|
||||
})
|
||||
} catch (err: any) {
|
||||
showNotice.error(err)
|
||||
} finally {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useDisplayedMixedPort } from '@/hooks/use-displayed-mixed-port'
|
||||
import { useProfiles } from '@/hooks/use-profiles'
|
||||
import { useVerge } from '@/hooks/use-verge'
|
||||
import { invoke_uwp_tool, setDnsOverride } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import getSystem from '@/utils/get-system'
|
||||
|
||||
@@ -74,7 +75,10 @@ const SettingClash = ({ onError }: Props) => {
|
||||
}
|
||||
const onUpdateGeo = async () => {
|
||||
try {
|
||||
await updateGeo()
|
||||
await mutate(() => updateGeo(), {
|
||||
id: 'update-geo',
|
||||
errorNotice: false,
|
||||
})
|
||||
showNotice.success('settings.feedback.notifications.clash.geoDataUpdated')
|
||||
} catch (err: any) {
|
||||
showNotice.error(err)
|
||||
@@ -90,7 +94,15 @@ const SettingClash = ({ onError }: Props) => {
|
||||
if (!profileUid) return
|
||||
setDnsUpdating(true)
|
||||
try {
|
||||
const outcome = await setDnsOverride(profileUid, enable, confirmation)
|
||||
const result = await mutate(
|
||||
() => setDnsOverride(profileUid, enable, confirmation),
|
||||
{
|
||||
id: 'set-dns-override',
|
||||
errorNotice: false,
|
||||
},
|
||||
)
|
||||
if (!result.ok) return
|
||||
const outcome = result.value
|
||||
if (outcome.status === 'confirmation_required') {
|
||||
setDnsConfirmation({ profileUid, source: outcome.source })
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
openDevTools,
|
||||
openLogsDir,
|
||||
} from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
import { checkUpdateSafe as checkUpdate } from '@/services/update'
|
||||
import { version } from '@root/package.json'
|
||||
@@ -61,7 +62,10 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
}
|
||||
|
||||
const onExportDiagnosticInfo = useCallback(async () => {
|
||||
await exportDiagnosticInfo()
|
||||
await mutate(() => exportDiagnosticInfo(), {
|
||||
id: 'export-diagnostic-info',
|
||||
errorNotice: false,
|
||||
})
|
||||
showNotice.success('shared.feedback.notifications.common.copySuccess', 1000)
|
||||
}, [])
|
||||
|
||||
@@ -128,7 +132,12 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={openDevTools}
|
||||
onClick={() => {
|
||||
void mutate(() => openDevTools(), {
|
||||
id: 'open-devtools',
|
||||
errorNotice: false,
|
||||
}).catch(() => {})
|
||||
}}
|
||||
label={t('settings.components.verge.advanced.fields.openDevTools')}
|
||||
/>
|
||||
|
||||
@@ -145,7 +154,10 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
|
||||
<SettingItem
|
||||
onClick={() => {
|
||||
exitApp()
|
||||
void mutate(() => exitApp(), {
|
||||
id: 'exit-app',
|
||||
errorNotice: false,
|
||||
}).catch(() => {})
|
||||
}}
|
||||
label={t('settings.components.verge.advanced.fields.exit')}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { installService, restartCore } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
|
||||
const executeWithErrorHandling = async <T>(
|
||||
@@ -23,14 +24,19 @@ const executeWithErrorHandling = async <T>(
|
||||
|
||||
export const useServiceInstaller = () => {
|
||||
const installServiceAndRestartCore = useCallback(async () => {
|
||||
const outcome = await executeWithErrorHandling(
|
||||
() => installService(),
|
||||
const installResult = await executeWithErrorHandling(
|
||||
() =>
|
||||
mutate(() => installService(), {
|
||||
id: 'install-service',
|
||||
errorNotice: false,
|
||||
}),
|
||||
'settings.statuses.clashService.installing',
|
||||
)
|
||||
if (outcome.status === 'sidecar') {
|
||||
if (!installResult.ok) return
|
||||
if (installResult.value.status === 'sidecar') {
|
||||
showNotice.warning(
|
||||
'settings.feedback.notifications.clashService.permissionFallback',
|
||||
{ reason: outcome.reason },
|
||||
{ reason: installResult.value.reason },
|
||||
0,
|
||||
)
|
||||
return
|
||||
@@ -40,7 +46,11 @@ export const useServiceInstaller = () => {
|
||||
)
|
||||
|
||||
await executeWithErrorHandling(
|
||||
() => restartCore(),
|
||||
() =>
|
||||
mutate(() => restartCore(), {
|
||||
id: 'restart-core',
|
||||
errorNotice: false,
|
||||
}),
|
||||
'settings.statuses.clash.restarting',
|
||||
'settings.feedback.notifications.clash.restartSuccess',
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { uninstallService } from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import { showNotice } from '@/services/notice-service'
|
||||
|
||||
import { useSystemState } from './use-system-state'
|
||||
@@ -12,10 +13,15 @@ export const useServiceUninstaller = () => {
|
||||
let uninstallError: unknown
|
||||
showNotice.info('settings.statuses.clashService.uninstalling')
|
||||
try {
|
||||
await uninstallService()
|
||||
showNotice.success(
|
||||
'settings.feedback.notifications.clashService.uninstallSuccess',
|
||||
)
|
||||
const result = await mutate(() => uninstallService(), {
|
||||
id: 'uninstall-service',
|
||||
errorNotice: false,
|
||||
})
|
||||
if (result.ok) {
|
||||
showNotice.success(
|
||||
'settings.feedback.notifications.clashService.uninstallSuccess',
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
uninstallError = error
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getEmbeddedServerPort,
|
||||
patchVergeConfig,
|
||||
} from '@/services/cmds'
|
||||
import { mutate } from '@/services/mutate'
|
||||
import {
|
||||
removeCacheData,
|
||||
revalidateQueries,
|
||||
@@ -64,10 +65,16 @@ export const useSystemProxyState = () => {
|
||||
while (pendingRef.current !== null) {
|
||||
const target = pendingRef.current
|
||||
pendingRef.current = null
|
||||
await patchVergeConfig({ enable_system_proxy: target })
|
||||
await mutate(() => patchVergeConfig({ enable_system_proxy: target }), {
|
||||
id: 'toggle-system-proxy',
|
||||
errorNotice: false,
|
||||
})
|
||||
confirmed = target
|
||||
if (!target && verge?.auto_close_connection) {
|
||||
await closeAllConnections().catch(() => {})
|
||||
await mutate(() => closeAllConnections(), {
|
||||
id: 'close-all-connections',
|
||||
errorNotice: false,
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user