mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
revert(web,hub): drop the connection switch button, keep a read-only environment display
This commit is contained in:
@@ -21,7 +21,6 @@ export interface ServerSettings {
|
||||
listenPort: number
|
||||
publicUrl: string
|
||||
corsOrigins: string[]
|
||||
lanUrl: string | null
|
||||
}
|
||||
|
||||
export interface ServerSettingsResult {
|
||||
@@ -34,7 +33,6 @@ export interface ServerSettingsResult {
|
||||
listenHost: 'env' | 'file' | 'default'
|
||||
listenPort: 'env' | 'file' | 'default'
|
||||
publicUrl: 'env' | 'file' | 'default'
|
||||
lanUrl: 'file' | 'default'
|
||||
corsOrigins: 'env' | 'file' | 'default'
|
||||
}
|
||||
savedToFile: boolean
|
||||
@@ -112,7 +110,6 @@ export async function loadServerSettings(dataDir: string): Promise<ServerSetting
|
||||
listenHost: 'default',
|
||||
listenPort: 'default',
|
||||
publicUrl: 'default',
|
||||
lanUrl: 'default',
|
||||
corsOrigins: 'default',
|
||||
}
|
||||
// telegramBotToken: env > file > null
|
||||
@@ -217,15 +214,6 @@ export async function loadServerSettings(dataDir: string): Promise<ServerSetting
|
||||
sources.publicUrl = 'file'
|
||||
}
|
||||
|
||||
// lanUrl: file only (optional alternative access URL, e.g. LAN direct)
|
||||
let lanUrl: string | null = null
|
||||
if (typeof settings.lanUrl === 'string' && settings.lanUrl.trim()) {
|
||||
lanUrl = settings.lanUrl.trim()
|
||||
sources.lanUrl = 'file'
|
||||
} else {
|
||||
sources.lanUrl = 'default'
|
||||
}
|
||||
|
||||
// corsOrigins: env > file > derived from publicUrl
|
||||
let corsOrigins: string[]
|
||||
if (process.env.CORS_ORIGINS) {
|
||||
@@ -256,7 +244,6 @@ export async function loadServerSettings(dataDir: string): Promise<ServerSetting
|
||||
listenHost,
|
||||
listenPort,
|
||||
publicUrl,
|
||||
lanUrl,
|
||||
corsOrigins,
|
||||
},
|
||||
sources,
|
||||
|
||||
@@ -40,7 +40,6 @@ export interface ConfigSources {
|
||||
listenHost: ConfigSource
|
||||
listenPort: ConfigSource
|
||||
publicUrl: ConfigSource
|
||||
lanUrl: ConfigSource
|
||||
corsOrigins: ConfigSource
|
||||
cliApiToken: 'env' | 'file' | 'generated'
|
||||
}
|
||||
@@ -88,9 +87,6 @@ class Configuration {
|
||||
/** Public URL for external access (e.g., Telegram Mini App) */
|
||||
public readonly publicUrl: string
|
||||
|
||||
/** Optional alternative access URL (e.g. LAN direct) */
|
||||
public readonly lanUrl: string | null
|
||||
|
||||
/** Allowed CORS origins for Mini App + Socket.IO (comma-separated env override) */
|
||||
public readonly corsOrigins: string[]
|
||||
|
||||
@@ -117,7 +113,6 @@ class Configuration {
|
||||
this.listenHost = serverSettings.listenHost
|
||||
this.listenPort = serverSettings.listenPort
|
||||
this.publicUrl = serverSettings.publicUrl
|
||||
this.lanUrl = serverSettings.lanUrl
|
||||
this.corsOrigins = serverSettings.corsOrigins
|
||||
|
||||
// CLI API token - will be set by _setCliApiToken() before create() returns
|
||||
|
||||
+1
-10
@@ -232,16 +232,7 @@ function createWebApp(options: {
|
||||
|
||||
const configuration = getConfiguration()
|
||||
const corsOrigins = options.corsOrigins ?? configuration.corsOrigins
|
||||
const mergedCorsOrigins = configuration.lanUrl
|
||||
? (() => {
|
||||
try {
|
||||
return [...new Set([...corsOrigins, new URL(configuration.lanUrl).origin])]
|
||||
} catch {
|
||||
return corsOrigins
|
||||
}
|
||||
})()
|
||||
: corsOrigins
|
||||
const corsOriginOption = mergedCorsOrigins.includes('*') ? '*' : mergedCorsOrigins
|
||||
const corsOriginOption = corsOrigins.includes('*') ? '*' : corsOrigins
|
||||
const corsMiddleware = cors({
|
||||
origin: corsOriginOption,
|
||||
allowMethods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
|
||||
+1
-12
@@ -162,17 +162,6 @@ function AppInner() {
|
||||
queryClient.clear()
|
||||
}, [baseUrl, queryClient])
|
||||
|
||||
// Self-heal: when authentication fails against a stored hub URL that is
|
||||
// not the page's own origin (e.g. a LAN address that is no longer
|
||||
// reachable), drop it so the app falls back to the page origin instead of
|
||||
// being stuck on a dead endpoint.
|
||||
const pageOrigin = typeof window !== 'undefined' ? window.location.origin : null
|
||||
useEffect(() => {
|
||||
if (authError && serverUrl && pageOrigin && serverUrl !== pageOrigin) {
|
||||
clearServerUrl()
|
||||
}
|
||||
}, [authError, serverUrl, pageOrigin, clearServerUrl])
|
||||
|
||||
// Clean up URL params after successful auth (for direct access links)
|
||||
useEffect(() => {
|
||||
if (!token || !api) return
|
||||
@@ -460,7 +449,7 @@ function AppInner() {
|
||||
}
|
||||
|
||||
return (
|
||||
<AppContextProvider value={{ api, token, baseUrl, setServerUrl }}>
|
||||
<AppContextProvider value={{ api, token, baseUrl }}>
|
||||
<VoiceProvider>
|
||||
<PwaUpdateBannerWithStatusOffset
|
||||
isSyncing={isSyncing}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { createContext, useContext, type ReactNode } from 'react'
|
||||
import type { ApiClient } from '@/api/client'
|
||||
|
||||
import type { ServerUrlResult } from '@/hooks/useServerUrl'
|
||||
|
||||
type AppContextValue = {
|
||||
api: ApiClient
|
||||
token: string
|
||||
baseUrl: string
|
||||
setServerUrl: (input: string) => ServerUrlResult
|
||||
}
|
||||
|
||||
const AppContext = createContext<AppContextValue | null>(null)
|
||||
|
||||
@@ -78,10 +78,9 @@ export default {
|
||||
'settings.connection.title': 'Connection',
|
||||
'settings.connection.hint': 'When on the same network you can connect straight to the hub on your Mac for lower latency.',
|
||||
'settings.connection.current': 'Current',
|
||||
'settings.connection.mode': 'Environment',
|
||||
'settings.connection.lan': 'LAN direct',
|
||||
'settings.connection.public': 'Public domain',
|
||||
'settings.connection.switchToLan': 'Switch to LAN (faster)',
|
||||
'settings.connection.switchToPublic': 'Switch to public domain',
|
||||
'sessions.group.new': 'New session in this directory',
|
||||
'sessions.machineFilter.label': 'Filter sessions by machine',
|
||||
'sessions.machineFilter.all': 'All',
|
||||
|
||||
@@ -78,10 +78,9 @@ export default {
|
||||
'settings.connection.title': '连接方式',
|
||||
'settings.connection.hint': '同一局域网内可直连 Mac 上的 hub,速度更快。',
|
||||
'settings.connection.current': '当前连接',
|
||||
'settings.connection.mode': '当前环境',
|
||||
'settings.connection.lan': '局域网直连',
|
||||
'settings.connection.public': '公网域名',
|
||||
'settings.connection.switchToLan': '切换到局域网直连(更快)',
|
||||
'settings.connection.switchToPublic': '切换到公网域名',
|
||||
'sessions.group.new': '在此目录新建会话',
|
||||
'sessions.machineFilter.label': '按机器筛选会话',
|
||||
'sessions.machineFilter.all': '全部',
|
||||
|
||||
@@ -9,9 +9,9 @@ const locales: ReadonlyArray<{ value: Locale; label: string }> = [
|
||||
{ value: 'zh-CN', label: '简体中文' },
|
||||
]
|
||||
|
||||
function ConnectionSwitch() {
|
||||
function ConnectionInfo() {
|
||||
const { t } = useTranslation()
|
||||
const { api, baseUrl, setServerUrl } = useAppContext()
|
||||
const { api, baseUrl } = useAppContext()
|
||||
const [info, setInfo] = useState<{ publicUrl: string | null; lanUrl: string | null } | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -35,26 +35,19 @@ function ConnectionSwitch() {
|
||||
}
|
||||
}, [api])
|
||||
|
||||
if (!info?.lanUrl) {
|
||||
return null
|
||||
}
|
||||
|
||||
let publicOrigin: string | null = null
|
||||
try {
|
||||
publicOrigin = info.publicUrl ? new URL(info.publicUrl).origin : null
|
||||
} catch {
|
||||
publicOrigin = null
|
||||
if (info?.publicUrl) {
|
||||
try {
|
||||
publicOrigin = new URL(info.publicUrl).origin
|
||||
} catch {
|
||||
publicOrigin = null
|
||||
}
|
||||
}
|
||||
// Anything other than the public domain counts as the alternative
|
||||
// (LAN) connection — this also covers IP-based access like
|
||||
// http://192.168.x.x:3006 even when the configured lanUrl uses a
|
||||
// hostname. baseUrl is the hub the app is actually talking to — it
|
||||
// updates in place after setServerUrl() without a page reload.
|
||||
// hostname. baseUrl is the hub the app is actually talking to.
|
||||
const isOnLan = baseUrl !== '' && baseUrl !== publicOrigin
|
||||
const target = isOnLan ? info.publicUrl : info.lanUrl
|
||||
if (!target) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsSection title={t('settings.connection.title')} description={t('settings.connection.hint')}>
|
||||
@@ -62,33 +55,16 @@ function ConnectionSwitch() {
|
||||
label={t('settings.connection.current')}
|
||||
trailing={<span className="max-w-[60%] truncate text-xs text-[var(--app-hint)]">{baseUrl}</span>}
|
||||
/>
|
||||
<SettingsRow
|
||||
label={isOnLan ? t('settings.connection.public') : t('settings.connection.lan')}
|
||||
trailing={
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
// Browsers block in-place requests from an HTTPS
|
||||
// page to an HTTP hub (mixed content), so an
|
||||
// HTTPS→HTTP switch must navigate instead. The
|
||||
// loaded page is then HTTP same-origin and works.
|
||||
const pageIsHttps = typeof window !== 'undefined'
|
||||
&& window.location.protocol === 'https:'
|
||||
const targetIsHttps = target.startsWith('https://')
|
||||
if (pageIsHttps && !targetIsHttps) {
|
||||
window.location.href = target
|
||||
return
|
||||
}
|
||||
// Otherwise switch the hub connection in place —
|
||||
// the app reconnects without a full navigation.
|
||||
setServerUrl(target)
|
||||
}}
|
||||
className="shrink-0 rounded-md border border-[var(--app-border)] bg-[var(--app-subtle-bg)] px-2 py-1.5 text-xs text-[var(--app-fg)] hover:bg-[var(--app-secondary-bg)]"
|
||||
>
|
||||
{isOnLan ? t('settings.connection.switchToPublic') : t('settings.connection.switchToLan')}
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
{info ? (
|
||||
<SettingsRow
|
||||
label={t('settings.connection.mode')}
|
||||
trailing={
|
||||
<span className="text-xs text-[var(--app-hint)]">
|
||||
{isOnLan ? t('settings.connection.lan') : t('settings.connection.public')}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</SettingsSection>
|
||||
)
|
||||
}
|
||||
@@ -98,7 +74,7 @@ export default function SettingsGeneralPage() {
|
||||
const { baseUrl } = useAppContext()
|
||||
return (
|
||||
<SettingsPageContent description={t('settings.general.description')}>
|
||||
<ConnectionSwitch />
|
||||
<ConnectionInfo />
|
||||
<SettingsSection title={t('settings.language.label')}>
|
||||
<SettingsChoiceGroup hideLabel label={t('settings.language.label')} value={locale} options={locales} onChange={setLocale} />
|
||||
</SettingsSection>
|
||||
|
||||
Reference in New Issue
Block a user