fix(ui): use current input values for test connection and persist across tabs

- handleTestConnection now accepts params with current display values
  instead of reading from stale persisted config
- Lifted proxy input state (host, port, authToken, localPort) to parent
  SettingsPage component to persist across tab switches
- Updated ProxyContentProps interface to pass state and setters

Fixes the root cause where typing in inputs but not blurring before
clicking "Test Connection" would use old persisted values.

Closes #142
Related: #163, #164, #165
This commit is contained in:
kaitranntt committed 2025-12-20 19:12:36 -05:00
1 parent 55464c5c5c
commit 12b534cc49
1 file changed
+55 -14
+55 -14
View File
@@ -124,6 +124,11 @@ export function SettingsPage() {
const [proxySuccess, setProxySuccess] = useState(false); const [proxySuccess, setProxySuccess] = useState(false);
const [testResult, setTestResult] = useState<RemoteProxyStatus | null>(null); const [testResult, setTestResult] = useState<RemoteProxyStatus | null>(null);
const [testing, setTesting] = useState(false); const [testing, setTesting] = useState(false);
// Proxy input state (lifted from ProxyContent to persist across tab switches)
const [proxyEditedHost, setProxyEditedHost] = useState<string | null>(null);
const [proxyEditedPort, setProxyEditedPort] = useState<string | null>(null);
const [proxyEditedAuthToken, setProxyEditedAuthToken] = useState<string | null>(null);
const [proxyEditedLocalPort, setProxyEditedLocalPort] = useState<string | null>(null);
// Load config and status on mount // Load config and status on mount
useEffect(() => { useEffect(() => {
@@ -459,10 +464,13 @@ export function SettingsPage() {
} }
}; };
const handleTestConnection = async () => { const handleTestConnection = async (params: {
if (!proxyConfig) return; host: string;
port: string;
const { host, port, protocol, auth_token } = proxyConfig.remote; protocol: 'http' | 'https';
authToken: string;
}) => {
const { host, port, protocol, authToken } = params;
if (!host) { if (!host) {
setProxyError('Host is required'); setProxyError('Host is required');
return; return;
@@ -473,11 +481,13 @@ export function SettingsPage() {
setProxyError(null); setProxyError(null);
setTestResult(null); setTestResult(null);
// Parse port - empty string means use protocol default
const portNum = port ? parseInt(port, 10) : undefined;
const result = await api.cliproxyServer.test({ const result = await api.cliproxyServer.test({
host, host,
port: port || undefined, // Empty/0 means use protocol default port: portNum || undefined, // Empty/0 means use protocol default
protocol, protocol,
authToken: auth_token || undefined, authToken: authToken || undefined,
}); });
setTestResult(result); setTestResult(result);
} catch (err) { } catch (err) {
@@ -590,6 +600,14 @@ export function SettingsPage() {
handleTestConnection={handleTestConnection} handleTestConnection={handleTestConnection}
fetchCliproxyServerConfig={fetchCliproxyServerConfig} fetchCliproxyServerConfig={fetchCliproxyServerConfig}
fetchRawConfig={fetchRawConfig} fetchRawConfig={fetchRawConfig}
editedHost={proxyEditedHost}
setEditedHost={setProxyEditedHost}
editedPort={proxyEditedPort}
setEditedPort={setProxyEditedPort}
editedAuthToken={proxyEditedAuthToken}
setEditedAuthToken={setProxyEditedAuthToken}
editedLocalPort={proxyEditedLocalPort}
setEditedLocalPort={setProxyEditedLocalPort}
/> />
)} )}
</div> </div>
@@ -1292,9 +1310,23 @@ interface ProxyContentProps {
testResult: RemoteProxyStatus | null; testResult: RemoteProxyStatus | null;
testing: boolean; testing: boolean;
saveCliproxyServerConfig: (updates: Partial<CliproxyServerConfig>) => void; saveCliproxyServerConfig: (updates: Partial<CliproxyServerConfig>) => void;
handleTestConnection: () => void; handleTestConnection: (params: {
host: string;
port: string;
protocol: 'http' | 'https';
authToken: string;
}) => void;
fetchCliproxyServerConfig: () => void; fetchCliproxyServerConfig: () => void;
fetchRawConfig: () => void; fetchRawConfig: () => void;
// Lifted input state for persistence across tab switches
editedHost: string | null;
setEditedHost: (value: string | null) => void;
editedPort: string | null;
setEditedPort: (value: string | null) => void;
editedAuthToken: string | null;
setEditedAuthToken: (value: string | null) => void;
editedLocalPort: string | null;
setEditedLocalPort: (value: string | null) => void;
} }
function ProxyContent({ function ProxyContent({
@@ -1309,6 +1341,14 @@ function ProxyContent({
handleTestConnection, handleTestConnection,
fetchCliproxyServerConfig, fetchCliproxyServerConfig,
fetchRawConfig, fetchRawConfig,
editedHost,
setEditedHost,
editedPort,
setEditedPort,
editedAuthToken,
setEditedAuthToken,
editedLocalPort,
setEditedLocalPort,
}: ProxyContentProps) { }: ProxyContentProps) {
// Default configs for fallback // Default configs for fallback
const defaultRemote = { const defaultRemote = {
@@ -1332,12 +1372,6 @@ function ProxyContent({
const authTokenInput = config?.remote.auth_token ?? ''; const authTokenInput = config?.remote.auth_token ?? '';
const localPortInput = (config?.local.port ?? 8317).toString(); const localPortInput = (config?.local.port ?? 8317).toString();
// Track edited values separately
const [editedHost, setEditedHost] = useState<string | null>(null);
const [editedPort, setEditedPort] = useState<string | null>(null);
const [editedAuthToken, setEditedAuthToken] = useState<string | null>(null);
const [editedLocalPort, setEditedLocalPort] = useState<string | null>(null);
// Get display values (edited or from config) // Get display values (edited or from config)
const displayHost = editedHost ?? hostInput; const displayHost = editedHost ?? hostInput;
const displayPort = editedPort ?? portInput; const displayPort = editedPort ?? portInput;
@@ -1559,7 +1593,14 @@ function ProxyContent({
{/* Test Connection */} {/* Test Connection */}
<div className="space-y-3 pt-2"> <div className="space-y-3 pt-2">
<Button <Button
onClick={handleTestConnection} onClick={() =>
handleTestConnection({
host: displayHost,
port: displayPort,
protocol: config?.remote.protocol || 'http',
authToken: displayAuthToken,
})
}
disabled={testing || !displayHost} disabled={testing || !displayHost}
variant="outline" variant="outline"
className="w-full" className="w-full"