feat(proxies): add empty-state troubleshooting guidance

This commit is contained in:
wonfen
2026-07-26 01:28:49 +08:00
parent f86a591597
commit ece3c71f38
20 changed files with 567 additions and 17 deletions
@@ -0,0 +1,88 @@
import type { ProxyViewV1 } from '@/types/proxy-view'
export type ProxyEmptyStateReason =
| 'no-subscriptions'
| 'inactive-subscription'
| 'core-unavailable'
| 'no-proxy-info'
type ProfileSummary = {
current?: string
items?: Array<{
uid?: string
type?: string
}>
}
interface ProxyEmptyStateInput {
mode: string
isChainMode: boolean
profiles?: ProfileSummary
isProfilesPending: boolean
proxyView?: ProxyViewV1
isProxyViewPending: boolean
isProxyViewError: boolean
runningMode?: string
isRunningModePending: boolean
}
const isSubscriptionProfile = (item: { type?: string }): boolean =>
item.type === 'remote' || item.type === 'local'
export const hasRenderableProxyContent = (
proxyView: ProxyViewV1 | undefined,
mode: string,
isChainMode: boolean,
) => {
if (!proxyView) return false
if (isChainMode) {
return proxyView.groups.some(
(group) => group.type === 'Selector' || group.type === 'URLTest',
)
}
if (mode === 'rule' || mode === 'script') {
return proxyView.groups.some((group) => !group.hidden)
}
return proxyView.global !== null
}
export const resolveProxyEmptyState = ({
mode,
isChainMode,
profiles,
isProfilesPending,
proxyView,
isProxyViewPending,
isProxyViewError,
runningMode,
isRunningModePending,
}: ProxyEmptyStateInput): ProxyEmptyStateReason | 'loading' | null => {
if (mode === 'direct') return null
if (isProfilesPending || isProxyViewPending || isRunningModePending) {
return 'loading'
}
if (profiles) {
const subscriptions = (profiles.items ?? []).filter(isSubscriptionProfile)
if (subscriptions.length === 0) return 'no-subscriptions'
const hasActiveSubscription = subscriptions.some(
(item) => item.uid === profiles.current,
)
if (!hasActiveSubscription) return 'inactive-subscription'
}
if (hasRenderableProxyContent(proxyView, mode, isChainMode)) {
return null
}
if (runningMode === 'NotRunning' || isProxyViewError) {
return 'core-unavailable'
}
return 'no-proxy-info'
}
+118
View File
@@ -0,0 +1,118 @@
import { Alert, AlertTitle, Box, Button, Stack } from '@mui/material'
import { useLockFn } from 'ahooks'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router'
import { useAppRefreshers } from '@/providers/app-data-context'
import { openLogsDir, restartCore } from '@/services/cmds'
import { showNotice } from '@/services/notice-service'
import { revalidateQuery } from '@/services/query-client'
import type { ProxyEmptyStateReason } from './proxy-empty-state-model'
interface Props {
reason: ProxyEmptyStateReason
}
export const ProxyEmptyState = ({ reason }: Props) => {
const { t } = useTranslation()
const navigate = useNavigate()
const { refreshProxy } = useAppRefreshers()
const [isRestarting, setIsRestarting] = useState(false)
const handleRestart = useLockFn(async () => {
setIsRestarting(true)
try {
await restartCore()
await Promise.all([refreshProxy(), revalidateQuery(['getRunningMode'])])
} catch (error) {
showNotice.error(error)
} finally {
setIsRestarting(false)
}
})
const title =
reason === 'no-subscriptions'
? t('proxies.page.empty.noSubscriptions.title')
: reason === 'inactive-subscription'
? t('proxies.page.empty.inactiveSubscription.title')
: reason === 'core-unavailable'
? t('proxies.page.empty.coreUnavailable.title')
: t('proxies.page.empty.noProxyInfo.title')
const description =
reason === 'no-subscriptions'
? t('proxies.page.empty.noSubscriptions.description')
: reason === 'inactive-subscription'
? t('proxies.page.empty.inactiveSubscription.description')
: reason === 'core-unavailable'
? t('proxies.page.empty.coreUnavailable.description')
: t('proxies.page.empty.noProxyInfo.description')
const showProfiles =
reason === 'no-subscriptions' ||
reason === 'inactive-subscription' ||
reason === 'no-proxy-info'
const showCoreActions =
reason === 'core-unavailable' || reason === 'no-proxy-info'
return (
<Box
sx={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
p: 2,
}}
>
<Alert
severity="warning"
variant="outlined"
sx={{ width: '100%', maxWidth: 640 }}
>
<AlertTitle>{title}</AlertTitle>
{description}
<Stack
direction="row"
spacing={1}
useFlexGap
sx={{ mt: 2, flexWrap: 'wrap' }}
>
{showProfiles && (
<Button
size="small"
variant="contained"
onClick={() => navigate('/profile')}
>
{t('proxies.page.empty.actions.openProfiles')}
</Button>
)}
{showCoreActions && (
<>
<Button
size="small"
variant="contained"
loading={isRestarting}
onClick={() => void handleRestart()}
>
{t('proxies.page.empty.actions.restartCore')}
</Button>
<Button
size="small"
variant="outlined"
disabled={isRestarting}
onClick={() => void openLogsDir()}
>
{t('proxies.page.empty.actions.openLogs')}
</Button>
</>
)}
</Stack>
</Alert>
</Box>
)
}
+27 -1
View File
@@ -18,9 +18,10 @@ import {
StickyVirtualList,
type StickyVirtualListHandle,
} from '@/components/base'
import { useProfiles } from '@/hooks/use-profiles'
import { useProxySelection } from '@/hooks/use-proxy-selection'
import { useVerge } from '@/hooks/use-verge'
import { useProxiesData } from '@/providers/app-data-context'
import { useProxiesData, useSystemData } from '@/providers/app-data-context'
import delayManager from '@/services/delay'
import {
isInteractableMember,
@@ -30,6 +31,8 @@ import {
} from '@/types/proxy-view'
import { debugLog } from '@/utils/debug'
import { ProxyEmptyState } from './proxy-empty-state'
import { resolveProxyEmptyState } from './proxy-empty-state-model'
import {
DEFAULT_HOVER_DELAY,
ProxyGroupNavigator,
@@ -598,11 +601,34 @@ function NormalProxyGroups(props: { mode: string }) {
export const ProxyGroups = (props: Props) => {
const { mode, isChainMode = false, chainConfigData } = props
const { profiles, isLoading: isProfilesLoading } = useProfiles()
const { proxyView, isProxyViewPending, isProxyViewError } = useProxiesData()
const { runningMode, isRunningModePending } = useSystemData()
const emptyState = resolveProxyEmptyState({
mode,
isChainMode,
profiles,
isProfilesPending: !profiles && isProfilesLoading,
proxyView,
isProxyViewPending,
isProxyViewError,
runningMode,
isRunningModePending,
})
if (mode === 'direct') {
return <BaseEmpty textKey="proxies.page.messages.directMode" />
}
if (emptyState === 'loading') {
return <BaseLoading />
}
if (emptyState) {
return <ProxyEmptyState reason={emptyState} />
}
if (isChainMode) {
return <ChainProxyGroups mode={mode} chainConfigData={chainConfigData} />
}
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "لا توجد مجموعات وكيل متاحة",
"noProxies": "لا توجد وكلاء"
"noProxies": "لا توجد وكلاء",
"noSubscriptions": {
"title": "لم يتم استيراد أي اشتراك",
"description": "لا يوجد محتوى لعرضه في صفحة الوكلاء. انتقل إلى صفحة «الملفات الشخصية» لاستيراد اشتراك وتفعيله."
},
"inactiveSubscription": {
"title": "لا يوجد اشتراك مفعّل",
"description": "تم العثور على اشتراكات، لكن لا يوجد أي اشتراك مفعّل حاليًا. انتقل إلى صفحة «الملفات الشخصية» واختر اشتراكًا لتفعيله."
},
"coreUnavailable": {
"title": "النواة غير متاحة مؤقتًا",
"description": "تعذر الحصول على معلومات الوكلاء من النواة. حاول إعادة تشغيل النواة. إذا استمرت المشكلة، افتح مجلد السجلات وتحقق من سجلات النواة."
},
"noProxyInfo": {
"title": "معلومات الوكلاء غير متاحة",
"description": "لا توجد مجموعات أو عقد وكلاء لعرضها. تحقق من أن الاشتراك المفعّل يحتوي على مجموعات وعقد صالحة، أو أعد تشغيل النواة وراجع السجلات."
},
"actions": {
"openProfiles": "الانتقال إلى الملفات الشخصية",
"restartCore": "إعادة تشغيل النواة",
"openLogs": "فتح مجلد السجلات"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "Keine Proxy-Gruppen verfügbar",
"noProxies": "Keine Proxys"
"noProxies": "Keine Proxys",
"noSubscriptions": {
"title": "Kein Abonnement importiert",
"description": "Auf der Proxy-Seite gibt es nichts anzuzeigen. Öffnen Sie „Abonnement“, um ein Abonnement zu importieren und zu aktivieren."
},
"inactiveSubscription": {
"title": "Kein aktives Abonnement",
"description": "Es wurden Abonnements gefunden, aber keines ist derzeit aktiv. Öffnen Sie „Abonnement“, wählen Sie eines aus und aktivieren Sie es."
},
"coreUnavailable": {
"title": "Kern vorübergehend nicht verfügbar",
"description": "Die Proxy-Informationen konnten nicht vom Kern abgerufen werden. Starten Sie den Kern neu. Falls das Problem weiterhin besteht, öffnen Sie den Protokollordner und prüfen Sie die Kernprotokolle."
},
"noProxyInfo": {
"title": "Keine Proxy-Informationen verfügbar",
"description": "Es gibt keine Proxy-Gruppen oder -Knoten zum Anzeigen. Prüfen Sie, ob das aktive Abonnement gültige Proxy-Gruppen und -Knoten enthält, oder starten Sie den Kern neu und prüfen Sie die Protokolle."
},
"actions": {
"openProfiles": "Zum Abonnement",
"restartCore": "Kern neu starten",
"openLogs": "Protokollordner öffnen"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "No proxy groups are available",
"noProxies": "No proxies"
"noProxies": "No proxies",
"noSubscriptions": {
"title": "No subscription imported",
"description": "There is nothing to display on the Proxies page. Go to Profiles to import and activate a subscription."
},
"inactiveSubscription": {
"title": "No active subscription",
"description": "Subscriptions were found, but none is currently active. Go to Profiles and select one to activate."
},
"coreUnavailable": {
"title": "Core temporarily unavailable",
"description": "Proxy information could not be retrieved from the core. Try restarting the core. If the problem persists, open the logs folder and check the core logs."
},
"noProxyInfo": {
"title": "No proxy information available",
"description": "There are no proxy groups or nodes to display. Check that the active subscription contains valid proxy groups and nodes, or restart the core and review the logs."
},
"actions": {
"openProfiles": "Go to Profiles",
"restartCore": "Restart Core",
"openLogs": "Open Logs Folder"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "No hay grupos de proxy disponibles",
"noProxies": "Sin proxies"
"noProxies": "Sin proxies",
"noSubscriptions": {
"title": "No se ha importado ninguna suscripción",
"description": "No hay contenido para mostrar en la página de proxies. Ve a Perfiles para importar y activar una suscripción."
},
"inactiveSubscription": {
"title": "No hay ninguna suscripción activa",
"description": "Se encontraron suscripciones, pero ninguna está activa. Ve a Perfiles, selecciona una suscripción y actívala."
},
"coreUnavailable": {
"title": "El núcleo no está disponible temporalmente",
"description": "No se pudo obtener la información de proxies del núcleo. Intenta reiniciar el núcleo. Si el problema continúa, abre la carpeta de registros y revisa los registros del núcleo."
},
"noProxyInfo": {
"title": "No hay información de proxies disponible",
"description": "No hay grupos ni nodos de proxy para mostrar. Comprueba que la suscripción activa contenga grupos y nodos válidos, o reinicia el núcleo y revisa los registros."
},
"actions": {
"openProfiles": "Ir a Perfiles",
"restartCore": "Reiniciar núcleo",
"openLogs": "Abrir carpeta de registros"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "هیچ گروه پروکسی در دسترس نیست",
"noProxies": "پروکسی‌ای وجود ندارد"
"noProxies": "پروکسی‌ای وجود ندارد",
"noSubscriptions": {
"title": "هیچ اشتراکی وارد نشده است",
"description": "چیزی برای نمایش در صفحه پروکسی وجود ندارد. برای وارد کردن و فعال‌سازی اشتراک به صفحه «پروفایل‌ها» بروید."
},
"inactiveSubscription": {
"title": "هیچ اشتراک فعالی وجود ندارد",
"description": "اشتراک‌هایی پیدا شدند، اما در حال حاضر هیچ‌کدام فعال نیستند. به صفحه «پروفایل‌ها» بروید، یک اشتراک را انتخاب و فعال کنید."
},
"coreUnavailable": {
"title": "هسته موقتاً در دسترس نیست",
"description": "دریافت اطلاعات پروکسی از هسته ممکن نشد. هسته را دوباره راه‌اندازی کنید. اگر مشکل ادامه داشت، پوشه گزارش‌ها را باز کرده و گزارش‌های هسته را بررسی کنید."
},
"noProxyInfo": {
"title": "اطلاعات پروکسی در دسترس نیست",
"description": "هیچ گروه یا گره پروکسی برای نمایش وجود ندارد. بررسی کنید که اشتراک فعال دارای گروه‌ها و گره‌های معتبر باشد، یا هسته را دوباره راه‌اندازی کرده و گزارش‌ها را ببینید."
},
"actions": {
"openProfiles": "رفتن به پروفایل‌ها",
"restartCore": "راه‌اندازی مجدد هسته",
"openLogs": "باز کردن پوشه گزارش‌ها"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "Tidak ada grup proxy yang tersedia",
"noProxies": "Tidak ada proxy"
"noProxies": "Tidak ada proxy",
"noSubscriptions": {
"title": "Belum ada langganan yang diimpor",
"description": "Tidak ada yang dapat ditampilkan di halaman Proksi. Buka halaman Profil untuk mengimpor dan mengaktifkan langganan."
},
"inactiveSubscription": {
"title": "Tidak ada langganan aktif",
"description": "Langganan ditemukan, tetapi tidak ada yang sedang aktif. Buka halaman Profil, lalu pilih dan aktifkan langganan."
},
"coreUnavailable": {
"title": "Inti sementara tidak tersedia",
"description": "Informasi proksi tidak dapat diambil dari inti. Coba mulai ulang inti. Jika masalah berlanjut, buka folder log dan periksa log inti."
},
"noProxyInfo": {
"title": "Informasi proksi tidak tersedia",
"description": "Tidak ada grup atau node proksi yang dapat ditampilkan. Pastikan langganan aktif berisi grup dan node yang valid, atau mulai ulang inti dan periksa log."
},
"actions": {
"openProfiles": "Buka Profil",
"restartCore": "Mulai Ulang Inti",
"openLogs": "Buka Folder Log"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "利用可能なプロキシグループがありません",
"noProxies": "プロキシがありません"
"noProxies": "プロキシがありません",
"noSubscriptions": {
"title": "サブスクリプションがインポートされていません",
"description": "プロキシページに表示する内容がありません。プロファイルページでサブスクリプションをインポートして有効化してください。"
},
"inactiveSubscription": {
"title": "有効なサブスクリプションがありません",
"description": "サブスクリプションは見つかりましたが、現在有効なものがありません。プロファイルページで選択して有効化してください。"
},
"coreUnavailable": {
"title": "コアを一時的に利用できません",
"description": "コアからプロキシ情報を取得できませんでした。コアを再起動してください。問題が解決しない場合は、ログフォルダーを開いてコアのログを確認してください。"
},
"noProxyInfo": {
"title": "プロキシ情報を取得できませんでした",
"description": "表示できるプロキシグループまたはノードがありません。有効なサブスクリプションに正しいプロキシグループとノードが含まれているか確認するか、コアを再起動してログを確認してください。"
},
"actions": {
"openProfiles": "プロファイルへ移動",
"restartCore": "コアを再起動",
"openLogs": "ログフォルダーを開く"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "사용 가능한 프록시 그룹이 없습니다",
"noProxies": "프록시 없음"
"noProxies": "프록시 없음",
"noSubscriptions": {
"title": "가져온 구독이 없습니다",
"description": "프록시 페이지에 표시할 내용이 없습니다. 프로필 페이지에서 구독을 가져와 활성화하세요."
},
"inactiveSubscription": {
"title": "활성화된 구독이 없습니다",
"description": "구독이 있지만 현재 활성화된 구독이 없습니다. 프로필 페이지에서 구독을 선택하고 활성화하세요."
},
"coreUnavailable": {
"title": "코어를 일시적으로 사용할 수 없습니다",
"description": "코어에서 프록시 정보를 가져오지 못했습니다. 코어를 재시작해 보세요. 문제가 계속되면 로그 폴더를 열어 코어 로그를 확인하세요."
},
"noProxyInfo": {
"title": "프록시 정보를 가져오지 못했습니다",
"description": "표시할 프록시 그룹이나 노드가 없습니다. 활성 구독에 유효한 프록시 그룹과 노드가 포함되어 있는지 확인하거나 코어를 재시작하고 로그를 확인하세요."
},
"actions": {
"openProfiles": "프로필로 이동",
"restartCore": "코어 재시작",
"openLogs": "로그 폴더 열기"
}
},
"chain": {
"header": "체인 프록시 구성",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "Нет доступных групп прокси",
"noProxies": "Нет прокси"
"noProxies": "Нет прокси",
"noSubscriptions": {
"title": "Нет импортированных подписок",
"description": "На странице прокси нечего отображать. Перейдите в раздел «Профили», чтобы импортировать и активировать подписку."
},
"inactiveSubscription": {
"title": "Нет активной подписки",
"description": "Подписки найдены, но ни одна из них сейчас не активна. Перейдите в раздел «Профили», выберите подписку и активируйте её."
},
"coreUnavailable": {
"title": "Ядро временно недоступно",
"description": "Не удалось получить информацию о прокси от ядра. Попробуйте перезапустить ядро. Если проблема сохраняется, откройте папку журналов и проверьте журналы ядра."
},
"noProxyInfo": {
"title": "Нет информации о прокси",
"description": "Нет групп или узлов прокси для отображения. Убедитесь, что активная подписка содержит допустимые группы и узлы, либо перезапустите ядро и проверьте журналы."
},
"actions": {
"openProfiles": "Перейти к профилям",
"restartCore": "Перезапустить ядро",
"openLogs": "Открыть папку журналов"
}
},
"chain": {
"header": "Цепочка прокси",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "Kullanılabilir proxy grubu yok",
"noProxies": "Proxy yok"
"noProxies": "Proxy yok",
"noSubscriptions": {
"title": "İçe aktarılmış abonelik yok",
"description": "Proxy sayfasında görüntülenecek içerik yok. Bir aboneliği içe aktarmak ve etkinleştirmek için Profiller sayfasına gidin."
},
"inactiveSubscription": {
"title": "Etkin abonelik yok",
"description": "Abonelikler bulundu ancak hiçbiri şu anda etkin değil. Profiller sayfasına gidip bir abonelik seçin ve etkinleştirin."
},
"coreUnavailable": {
"title": "Çekirdek geçici olarak kullanılamıyor",
"description": "Proxy bilgileri çekirdekten alınamadı. Çekirdeği yeniden başlatmayı deneyin. Sorun devam ederse günlükler klasörünü açıp çekirdek günlüklerini kontrol edin."
},
"noProxyInfo": {
"title": "Proxy bilgisi yok",
"description": "Görüntülenecek proxy grubu veya düğümü yok. Etkin aboneliğin geçerli proxy grupları ve düğümleri içerdiğini doğrulayın ya da çekirdeği yeniden başlatıp günlükleri inceleyin."
},
"actions": {
"openProfiles": "Profillere Git",
"restartCore": "Çekirdeği Yeniden Başlat",
"openLogs": "Günlükler Klasörünü Aç"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "Кулланырлык прокси төркемнәре юк",
"noProxies": "Проксилар юк"
"noProxies": "Проксилар юк",
"noSubscriptions": {
"title": "Язылу импортланмаган",
"description": "Прокси битендә күрсәтерлек мәгълүмат юк. Язылуны импортлау һәм активлаштыру өчен «Профильләр» битенә күчегез."
},
"inactiveSubscription": {
"title": "Актив язылу юк",
"description": "Язылулар табылды, ләкин хәзер берсе дә актив түгел. «Профильләр» битенә күчеп, язылуны сайлагыз һәм активлаштырыгыз."
},
"coreUnavailable": {
"title": "Ядро вакытлыча кулланылмый",
"description": "Ядродан прокси мәгълүматын алып булмады. Ядроны яңадан эшләтеп карагыз. Мәсьәлә чишелмәсә, журналлар папкасын ачып, ядро журналларын тикшерегез."
},
"noProxyInfo": {
"title": "Прокси мәгълүматы юк",
"description": "Күрсәтү өчен прокси төркемнәре яки төеннәре юк. Актив язылуда дөрес төркемнәр һәм төеннәр булуын тикшерегез, яки ядроны яңадан эшләтеп журналларны карагыз."
},
"actions": {
"openProfiles": "Профильләргә күчү",
"restartCore": "Ядроны яңадан эшләтү",
"openLogs": "Журналлар папкасын ачу"
}
},
"chain": {
"header": "Chain Proxy Config",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "暂无可用代理组",
"noProxies": "暂无代理"
"noProxies": "暂无代理",
"noSubscriptions": {
"title": "尚未导入订阅",
"description": "代理页没有可展示的内容。请先前往“订阅”页面导入并启用订阅。"
},
"inactiveSubscription": {
"title": "尚未激活订阅",
"description": "检测到已有订阅,但当前没有有效订阅被激活。请前往“订阅”页面选择并激活一个订阅。"
},
"coreUnavailable": {
"title": "内核暂不可用",
"description": "无法从内核获取代理信息。请尝试重启内核;若问题仍然存在,请打开日志目录检查内核日志。"
},
"noProxyInfo": {
"title": "未获取到代理信息",
"description": "当前没有可展示的代理组或节点。请检查当前订阅是否包含有效的代理组和节点,或尝试重启内核并查看日志。"
},
"actions": {
"openProfiles": "前往订阅",
"restartCore": "重启内核",
"openLogs": "打开日志目录"
}
},
"chain": {
"header": "代理链配置",
+22 -1
View File
@@ -44,7 +44,28 @@
},
"empty": {
"noAvailableGroups": "目前沒有可用的代理群組",
"noProxies": "目前沒有代理"
"noProxies": "目前沒有代理",
"noSubscriptions": {
"title": "尚未匯入訂閱",
"description": "代理頁沒有可顯示的內容。請先前往「訂閱」頁面匯入並啟用訂閱。"
},
"inactiveSubscription": {
"title": "尚未啟用訂閱",
"description": "偵測到已有訂閱,但目前沒有有效訂閱被啟用。請前往「訂閱」頁面選擇並啟用一個訂閱。"
},
"coreUnavailable": {
"title": "核心暫時無法使用",
"description": "無法從核心取得代理資訊。請嘗試重新啟動核心;若問題仍然存在,請開啟日誌目錄檢查核心日誌。"
},
"noProxyInfo": {
"title": "未取得代理資訊",
"description": "目前沒有可顯示的代理群組或節點。請檢查目前訂閱是否包含有效的代理群組和節點,或嘗試重新啟動核心並查看日誌。"
},
"actions": {
"openProfiles": "前往訂閱",
"restartCore": "重新啟動核心",
"openLogs": "開啟日誌目錄"
}
},
"chain": {
"header": "鏈式代理設定",
+2
View File
@@ -6,6 +6,7 @@ import type { ProxyViewV1 } from '@/types/proxy-view'
export interface ProxiesContextType {
proxyView: ProxyViewV1 | undefined
isProxyViewPending: boolean
isProxyViewError: boolean
}
export interface RulesContextType {
@@ -21,6 +22,7 @@ export interface ClashConfigContextType {
export interface SystemContextType {
sysproxy: any
runningMode?: string
isRunningModePending: boolean
systemProxyAddress: string
}
+14 -3
View File
@@ -60,6 +60,7 @@ export const AppDataProvider = ({
const {
data: proxyView,
error: proxyViewError,
isPending: isProxyViewPending,
refetch: _refetchProxyView,
} = useQuery({
@@ -99,7 +100,7 @@ export const AppDataProvider = ({
...TQ_DEFAULTS,
})
const { data: runningMode } = useQuery({
const { data: runningMode, isPending: isRunningModePending } = useQuery({
queryKey: ['getRunningMode'],
queryFn: getRunningMode,
...TQ_DEFAULTS,
@@ -216,8 +217,9 @@ export const AppDataProvider = ({
() => ({
proxyView,
isProxyViewPending,
isProxyViewError: Boolean(proxyViewError),
}),
[proxyView, isProxyViewPending],
[proxyView, isProxyViewPending, proxyViewError],
)
const rulesValue = useMemo(
@@ -273,9 +275,18 @@ export const AppDataProvider = ({
return {
sysproxy,
runningMode,
isRunningModePending,
systemProxyAddress: calculateSystemProxyAddress(),
}
}, [sysproxy, runningMode, verge, clashConfig, runtimeConfig, clashInfo])
}, [
sysproxy,
runningMode,
isRunningModePending,
verge,
clashConfig,
runtimeConfig,
clashInfo,
])
const uptimeValue = useMemo(() => ({ uptime: uptimeData || 0 }), [uptimeData])
+11
View File
@@ -288,6 +288,17 @@ export const translationKeys = [
'proxies.page.placeholders.delayCheckUrl',
'proxies.page.empty.noAvailableGroups',
'proxies.page.empty.noProxies',
'proxies.page.empty.noSubscriptions.title',
'proxies.page.empty.noSubscriptions.description',
'proxies.page.empty.inactiveSubscription.title',
'proxies.page.empty.inactiveSubscription.description',
'proxies.page.empty.coreUnavailable.title',
'proxies.page.empty.coreUnavailable.description',
'proxies.page.empty.noProxyInfo.title',
'proxies.page.empty.noProxyInfo.description',
'proxies.page.empty.actions.openProfiles',
'proxies.page.empty.actions.restartCore',
'proxies.page.empty.actions.openLogs',
'proxies.page.chain.header',
'proxies.page.chain.warning',
'proxies.page.chain.empty',
+21
View File
@@ -508,8 +508,29 @@ export interface TranslationResources {
warning: string
}
empty: {
actions: {
openLogs: string
openProfiles: string
restartCore: string
}
coreUnavailable: {
description: string
title: string
}
inactiveSubscription: {
description: string
title: string
}
noAvailableGroups: string
noProxies: string
noProxyInfo: {
description: string
title: string
}
noSubscriptions: {
description: string
title: string
}
}
labels: {
delayCheckReset: string