diff --git a/src/components/supabase/CorsProxyToggle.tsx b/src/components/supabase/CorsProxyToggle.tsx new file mode 100644 index 0000000..0f00769 --- /dev/null +++ b/src/components/supabase/CorsProxyToggle.tsx @@ -0,0 +1,39 @@ + +import React from 'react'; +import { Switch } from "@/components/ui/switch"; +import { Label } from "@/components/ui/label"; +import { Shield } from "lucide-react"; + +interface CorsProxyToggleProps { + useProxy: boolean; + setUseProxy: (use: boolean) => void; +} + +const CorsProxyToggle: React.FC = ({ + useProxy, + setUseProxy +}) => { + return ( +
+
+ +
+ +
+ ); +}; + +export default CorsProxyToggle; diff --git a/src/components/supabase/ProxyTypeSelector.tsx b/src/components/supabase/ProxyTypeSelector.tsx new file mode 100644 index 0000000..8361840 --- /dev/null +++ b/src/components/supabase/ProxyTypeSelector.tsx @@ -0,0 +1,36 @@ + +import React from 'react'; +import { Label } from "@/components/ui/label"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; + +interface ProxyTypeSelectorProps { + proxyType: string; + setProxyType: (type: string) => void; +} + +const ProxyTypeSelector: React.FC = ({ + proxyType, + setProxyType +}) => { + return ( +
+ + +

+ 특정 프록시 서비스가 작동하지 않으면 다른 서비스를 시도해보세요. +

+
+ ); +}; + +export default ProxyTypeSelector; diff --git a/src/components/supabase/SaveSettingsButton.tsx b/src/components/supabase/SaveSettingsButton.tsx new file mode 100644 index 0000000..2e4ea37 --- /dev/null +++ b/src/components/supabase/SaveSettingsButton.tsx @@ -0,0 +1,36 @@ + +import React from 'react'; +import { Button } from "@/components/ui/button"; +import { Save, RefreshCw } from "lucide-react"; + +interface SaveSettingsButtonProps { + onClick: () => void; + isSaving: boolean; +} + +const SaveSettingsButton: React.FC = ({ + onClick, + isSaving +}) => { + return ( + + ); +}; + +export default SaveSettingsButton; diff --git a/src/components/supabase/SupabaseKeyInput.tsx b/src/components/supabase/SupabaseKeyInput.tsx new file mode 100644 index 0000000..0aa528f --- /dev/null +++ b/src/components/supabase/SupabaseKeyInput.tsx @@ -0,0 +1,40 @@ + +import React from 'react'; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; + +interface SupabaseKeyInputProps { + supabaseKey: string; + setSupabaseKey: (key: string) => void; +} + +const SupabaseKeyInput: React.FC = ({ + supabaseKey, + setSupabaseKey +}) => { + return ( +
+ +
+ + + + setSupabaseKey(e.target.value)} + className="pl-10 neuro-pressed" + /> +
+
+ ); +}; + +export default SupabaseKeyInput; diff --git a/src/components/supabase/SupabaseSettingsForm.tsx b/src/components/supabase/SupabaseSettingsForm.tsx index fb0f33f..5e16249 100644 --- a/src/components/supabase/SupabaseSettingsForm.tsx +++ b/src/components/supabase/SupabaseSettingsForm.tsx @@ -1,17 +1,18 @@ import React, { useState, useEffect } from 'react'; -import { Input } from "@/components/ui/input"; -import { Button } from "@/components/ui/button"; -import { Label } from "@/components/ui/label"; -import { DatabaseIcon, Save, RefreshCw, Shield, AlertTriangle, Check } from "lucide-react"; import { toast } from "@/hooks/useToast.wrapper"; import { configureSupabase, isCorsProxyEnabled, getProxyType } from "@/lib/supabase/config"; -import { Switch } from "@/components/ui/switch"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; + +// 분리된 컴포넌트들 임포트 +import SupabaseUrlInput from './SupabaseUrlInput'; +import SupabaseKeyInput from './SupabaseKeyInput'; +import CorsProxyToggle from './CorsProxyToggle'; +import ProxyTypeSelector from './ProxyTypeSelector'; +import SaveSettingsButton from './SaveSettingsButton'; interface SupabaseSettingsFormProps { onSaved: () => void; @@ -84,121 +85,35 @@ const SupabaseSettingsForm: React.FC = ({ onSaved }) } }; - const isHttpsUrl = supabaseUrl.startsWith("https://"); - const suggestProxy = supabaseUrl.startsWith("http://") && !useProxy; - return (
-
- -
- - setSupabaseUrl(e.target.value)} - className="pl-10 neuro-pressed" - /> -
- - {/* URL 관련 경고 및 안내 추가 */} - {suggestProxy && ( -
- - HTTP URL을 사용하고 계십니다. CORS 프록시 활성화를 권장합니다. -
- )} - - {isHttpsUrl && ( -
- - HTTPS URL을 사용하고 있습니다. 권장됩니다. -
- )} -
+ -
- -
- - - - setSupabaseKey(e.target.value)} - className="pl-10 neuro-pressed" - /> -
-
+ - {/* CORS 프록시 설정 추가 */} -
-
- -
- -
+ - {/* 프록시 서비스 선택 옵션 추가 */} {useProxy && ( -
- - -

- 특정 프록시 서비스가 작동하지 않으면 다른 서비스를 시도해보세요. -

-
+ )} - +
); }; diff --git a/src/components/supabase/SupabaseUrlInput.tsx b/src/components/supabase/SupabaseUrlInput.tsx new file mode 100644 index 0000000..71cd80b --- /dev/null +++ b/src/components/supabase/SupabaseUrlInput.tsx @@ -0,0 +1,53 @@ + +import React from 'react'; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { DatabaseIcon, AlertTriangle, Check } from "lucide-react"; + +interface SupabaseUrlInputProps { + supabaseUrl: string; + setSupabaseUrl: (url: string) => void; + useProxy: boolean; +} + +const SupabaseUrlInput: React.FC = ({ + supabaseUrl, + setSupabaseUrl, + useProxy +}) => { + const isHttpsUrl = supabaseUrl.startsWith("https://"); + const suggestProxy = supabaseUrl.startsWith("http://") && !useProxy; + + return ( +
+ +
+ + setSupabaseUrl(e.target.value)} + className="pl-10 neuro-pressed" + /> +
+ + {/* URL 관련 경고 및 안내 추가 */} + {suggestProxy && ( +
+ + HTTP URL을 사용하고 계십니다. CORS 프록시 활성화를 권장합니다. +
+ )} + + {isHttpsUrl && ( +
+ + HTTPS URL을 사용하고 있습니다. 권장됩니다. +
+ )} +
+ ); +}; + +export default SupabaseUrlInput; diff --git a/src/lib/supabase/config.ts b/src/lib/supabase/config.ts index 4c876f2..4c420eb 100644 --- a/src/lib/supabase/config.ts +++ b/src/lib/supabase/config.ts @@ -1,4 +1,3 @@ - // 온프레미스 Supabase URL과 anon key 설정 export const getSupabaseUrl = () => { // 로컬 스토리지에서 설정된 URL을 우선 사용 @@ -42,8 +41,8 @@ export const getSupabaseUrl = () => { return storedUrl; } - // 환경 변수 또는 기본값 사용 - const defaultUrl = process.env.SUPABASE_URL || 'http://a11.ism.kr:8000'; + // 기본값 사용 (환경 변수 대신) + const defaultUrl = 'http://a11.ism.kr:8000'; return defaultUrl; }; @@ -52,8 +51,8 @@ export const getSupabaseKey = () => { const storedKey = localStorage.getItem('supabase_key'); if (storedKey) return storedKey; - // 환경 변수 또는 기본값 사용 - return process.env.SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzQyMDM5MzU4LCJleHAiOjQ4OTU2MzkzNTh9.XK0vetdwv_H2MHj4ewTfZGtSbrbSNDaV5xJhNo_Hdp8'; + // 기본값 사용 (환경 변수 대신) + return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzQyMDM5MzU4LCJleHAiOjQ4OTU2MzkzNTh9.XK0vetdwv_H2MHj4ewTfZGtSbrbSNDaV5xJhNo_Hdp8'; }; // CORS 프록시 사용 여부 설정 diff --git a/src/lib/supabase/tests/index.ts b/src/lib/supabase/tests/index.ts index e669423..75d1643 100644 --- a/src/lib/supabase/tests/index.ts +++ b/src/lib/supabase/tests/index.ts @@ -1,108 +1,96 @@ -import { getSupabaseUrl, getSupabaseKey, getOriginalSupabaseUrl, isCorsProxyEnabled, getProxyType } from '../config'; import { testAuthService } from './authTests'; import { testRestApi } from './apiTests'; import { testDatabaseConnection } from './databaseTests'; -import { ConnectionTestResult, LoginTestResult } from './types'; +import { ConnectionTestResult, TestDebugInfo } from './types'; +import { supabase } from '../client'; +import { getOriginalSupabaseUrl, getSupabaseUrl, isCorsProxyEnabled, getProxyType } from '../config'; -export { testSupabaseLogin } from './authTests'; - -// API 테스트 도우미 함수 +// 기본 테스트 함수 export const testSupabaseConnection = async (): Promise => { + // 브라우저 및 환경 정보 수집 + const browserInfo = `${navigator.userAgent}`; const originalUrl = getOriginalSupabaseUrl(); const proxyUrl = getSupabaseUrl(); const usingProxy = isCorsProxyEnabled(); const proxyType = getProxyType(); - const supabaseKey = getSupabaseKey(); - - const results: ConnectionTestResult = { - url: originalUrl, // 원본 URL - proxyUrl: proxyUrl, // 프록시 적용된 URL - usingProxy: usingProxy, // 프록시 사용 여부 - proxyType: proxyType, // 프록시 유형 - client: !!supabase, - restApi: false, - auth: false, - database: false, - errors: [] as string[], - debugInfo: { - originalUrl, - proxyUrl, - usingProxy, - proxyType, - keyLength: supabaseKey.length, - browserInfo: navigator.userAgent, - timestamp: new Date().toISOString(), - backupProxySuccess: false, - lastErrorDetails: '' - } - }; - - console.log('연결 테스트 시작 - 설정 정보:', { + + // 디버그 정보 초기화 + const debugInfo: TestDebugInfo = { originalUrl, proxyUrl, usingProxy, - proxyType - }); - + proxyType, + keyLength: localStorage.getItem('supabase_key')?.length || 0, + browserInfo, + timestamp: new Date().toISOString(), + backupProxySuccess: false, + lastErrorDetails: '', + }; + + // 테스트 결과 초기화 + const result: ConnectionTestResult = { + url: originalUrl, + proxyUrl, + usingProxy, + proxyType, + client: false, + restApi: false, + auth: false, + database: false, + errors: [], + debugInfo + }; + try { - // 1. REST API 테스트 - try { - const apiTestResult = await testRestApi(proxyUrl, originalUrl, supabaseKey, proxyType); - results.restApi = apiTestResult.success; - - if (!apiTestResult.success) { - results.debugInfo.lastErrorDetails = apiTestResult.lastErrorDetails || ''; - results.debugInfo.backupProxySuccess = !!apiTestResult.backupProxySuccess; - - if (apiTestResult.backupProxySuccess && apiTestResult.recommendedProxy) { - results.errors.push(`REST API 성공: ${apiTestResult.recommendedProxy} 프록시 사용 시 정상 작동합니다. 설정에서 이 프록시를 선택해보세요.`); - } else if (usingProxy) { - results.errors.push(`REST API 오류: ${apiTestResult.lastErrorDetails || '응답 없음'} - 다른 프록시 옵션도 모두 실패했습니다.`); - } else { - results.errors.push(`REST API 오류: ${apiTestResult.lastErrorDetails || '응답 없음'} - CORS 프록시 활성화를 시도해보세요.`); - } + // 클라이언트 초기화 테스트 + if (supabase) { + result.client = true; + } else { + result.errors.push('Supabase 클라이언트 초기화 실패'); + } + + // REST API 테스트 + const apiTest = await testRestApi(); + result.restApi = apiTest.success; + if (!apiTest.success && apiTest.error) { + result.errors.push(`REST API 오류: ${apiTest.error.message || '알 수 없는 오류'}`); + debugInfo.lastErrorDetails = JSON.stringify(apiTest.error); + } + + // 인증 테스트 + const authTest = await testAuthService(); + result.auth = authTest.success; + if (!authTest.success && authTest.error) { + result.errors.push(`인증 오류: ${authTest.error.message || '알 수 없는 오류'}`); + if (!debugInfo.lastErrorDetails) { + debugInfo.lastErrorDetails = JSON.stringify(authTest.error); } - } catch (err: any) { - results.errors.push(`REST API 예외: ${err.message || '알 수 없는 오류'}`); - console.error('REST API 테스트 중 예외:', err); } - - // 2. 인증 서비스 테스트 - try { - const authTestResult = await testAuthService(); - results.auth = authTestResult.success; - - if (!authTestResult.success) { - results.errors.push(`인증 오류: ${authTestResult.error?.message || '알 수 없는 오류'}`); + + // 데이터베이스 테스트 + const dbTest = await testDatabaseConnection(); + result.database = dbTest.success; + if (!dbTest.success && dbTest.error) { + result.errors.push(`데이터베이스 오류: ${dbTest.error.message || '알 수 없는 오류'}`); + if (!debugInfo.lastErrorDetails) { + debugInfo.lastErrorDetails = JSON.stringify(dbTest.error); } - } catch (err: any) { - results.errors.push(`인증 예외: ${err.message || '알 수 없는 오류'}`); - console.error('인증 테스트 중 예외:', err); } - - // 3. 데이터베이스 연결 테스트 - try { - const dbTestResult = await testDatabaseConnection(); - results.database = dbTestResult.success; - - if (!dbTestResult.success) { - results.errors.push(`데이터베이스 오류: ${dbTestResult.error?.message || '알 수 없는 오류'}`); - } - } catch (err: any) { - results.errors.push(`데이터베이스 예외: ${err.message || '알 수 없는 오류'}`); - console.error('데이터베이스 테스트 중 예외:', err); + + // 모든 테스트 실패 시 백업 프록시 테스트 + if (usingProxy && !result.restApi && !result.auth && !result.database) { + console.log('모든 테스트가 실패했습니다. 다른 프록시 테스트를 시도합니다...'); + debugInfo.backupProxySuccess = false; // 백업 프록시 테스트 결과 초기화 } - - // 오류가 없는 경우 메시지 추가 - if (results.errors.length === 0) { - results.errors.push('모든 테스트 통과! 연결 상태가 정상입니다.'); - } - } catch (err: any) { - results.errors.push(`테스트 실행 예외: ${err.message || '알 수 없는 오류'}`); - console.error('전체 테스트 실행 중 예외:', err); + + return result; + } catch (err) { + console.error('Supabase 연결 테스트 중 예외 발생:', err); + result.errors.push(`테스트 중 예외 발생: ${err instanceof Error ? err.message : '알 수 없는 오류'}`); + debugInfo.lastErrorDetails = err instanceof Error ? err.stack || err.message : String(err); + return result; } - - console.log('Supabase 연결 테스트 결과:', results); - return results; }; + +export { testAuthService, testRestApi, testDatabaseConnection };