Refactor SupabaseConnectionTest component
The SupabaseConnectionTest component was refactored into smaller, more manageable components to improve readability and maintainability.
This commit is contained in:
34
src/components/supabase/ConnectionTestButton.tsx
Normal file
34
src/components/supabase/ConnectionTestButton.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { RefreshCw } from "lucide-react";
|
||||||
|
|
||||||
|
interface ConnectionTestButtonProps {
|
||||||
|
onClick: () => void;
|
||||||
|
isTesting: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConnectionTestButton: React.FC<ConnectionTestButtonProps> = ({ onClick, isTesting }) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
onClick={onClick}
|
||||||
|
disabled={isTesting}
|
||||||
|
variant="outline"
|
||||||
|
className="w-full mb-4"
|
||||||
|
>
|
||||||
|
{isTesting ? (
|
||||||
|
<>
|
||||||
|
<RefreshCw className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
테스트 중...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<RefreshCw className="mr-2 h-4 w-4" />
|
||||||
|
연결 테스트 실행
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConnectionTestButton;
|
||||||
99
src/components/supabase/DebugInfoCollapsible.tsx
Normal file
99
src/components/supabase/DebugInfoCollapsible.tsx
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Info } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { TestResults } from '@/lib/supabase/tests/types';
|
||||||
|
import {
|
||||||
|
Collapsible,
|
||||||
|
CollapsibleContent,
|
||||||
|
CollapsibleTrigger
|
||||||
|
} from "@/components/ui/collapsible";
|
||||||
|
|
||||||
|
interface DebugInfoCollapsibleProps {
|
||||||
|
testResults: TestResults;
|
||||||
|
showDebug: boolean;
|
||||||
|
setShowDebug: (show: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DebugInfoCollapsible: React.FC<DebugInfoCollapsibleProps> = ({
|
||||||
|
testResults,
|
||||||
|
showDebug,
|
||||||
|
setShowDebug
|
||||||
|
}) => {
|
||||||
|
if (!testResults.debugInfo) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Collapsible
|
||||||
|
open={showDebug}
|
||||||
|
onOpenChange={setShowDebug}
|
||||||
|
className="border border-gray-200 rounded-md mt-4"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between px-4 py-2 bg-gray-50">
|
||||||
|
<h4 className="text-sm font-medium">고급 진단 정보</h4>
|
||||||
|
<CollapsibleTrigger asChild>
|
||||||
|
<Button variant="ghost" size="sm" className="h-7 w-7 p-0">
|
||||||
|
<Info className="h-4 w-4" />
|
||||||
|
<span className="sr-only">
|
||||||
|
{showDebug ? '진단 정보 숨기기' : '진단 정보 표시'}
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
</CollapsibleTrigger>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CollapsibleContent className="px-4 py-2 text-xs">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">Supabase URL:</span>
|
||||||
|
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
||||||
|
{testResults.url}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{testResults.usingProxy && (
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">프록시 URL:</span>
|
||||||
|
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
||||||
|
{testResults.proxyUrl}
|
||||||
|
</div>
|
||||||
|
<div className="mt-1">
|
||||||
|
프록시 유형: {testResults.proxyType || 'corsproxy.io'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">클라이언트 초기화:</span>
|
||||||
|
<div className="mt-1 text-green-600">
|
||||||
|
{testResults.client ? '성공' : '실패'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{testResults.debugInfo.lastErrorDetails && (
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">마지막 오류 상세:</span>
|
||||||
|
<div className="mt-1 bg-red-50 p-1 rounded break-all text-red-600">
|
||||||
|
{testResults.debugInfo.lastErrorDetails}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">브라우저 정보:</span>
|
||||||
|
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
||||||
|
{testResults.debugInfo.browserInfo}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">테스트 시간:</span>
|
||||||
|
<div className="mt-1">
|
||||||
|
{new Date(testResults.debugInfo.timestamp).toLocaleString()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CollapsibleContent>
|
||||||
|
</Collapsible>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DebugInfoCollapsible;
|
||||||
20
src/components/supabase/ErrorMessageCard.tsx
Normal file
20
src/components/supabase/ErrorMessageCard.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface ErrorMessageCardProps {
|
||||||
|
errors: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ErrorMessageCard: React.FC<ErrorMessageCardProps> = ({ errors }) => {
|
||||||
|
if (errors.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-red-50 border border-red-200 rounded p-2 mt-2">
|
||||||
|
{errors.map((error: string, index: number) => (
|
||||||
|
<p key={index} className="text-xs text-red-600 mb-1">{error}</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ErrorMessageCard;
|
||||||
20
src/components/supabase/ProxyInfoCard.tsx
Normal file
20
src/components/supabase/ProxyInfoCard.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { TestResults } from '@/lib/supabase/tests/types';
|
||||||
|
|
||||||
|
interface ProxyInfoCardProps {
|
||||||
|
testResults: TestResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProxyInfoCard: React.FC<ProxyInfoCardProps> = ({ testResults }) => {
|
||||||
|
if (!testResults.usingProxy) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-blue-50 border border-blue-200 rounded p-2 mt-2">
|
||||||
|
<p className="text-xs">CORS 프록시 사용 중: {testResults.proxyType || 'corsproxy.io'}</p>
|
||||||
|
<p className="text-xs break-all mt-1">{testResults.proxyUrl}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProxyInfoCard;
|
||||||
34
src/components/supabase/ProxyRecommendationAlert.tsx
Normal file
34
src/components/supabase/ProxyRecommendationAlert.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { AlertCircle } from "lucide-react";
|
||||||
|
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
|
||||||
|
|
||||||
|
interface ProxyRecommendationAlertProps {
|
||||||
|
errors: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProxyRecommendationAlert: React.FC<ProxyRecommendationAlertProps> = ({ errors }) => {
|
||||||
|
const hasProxyRecommendation = errors.some(err =>
|
||||||
|
err.includes('프록시 사용 시 정상 작동합니다') ||
|
||||||
|
err.includes('프록시를 선택해보세요')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasProxyRecommendation || errors.length === 0) return null;
|
||||||
|
|
||||||
|
const recommendationMessage = errors.find(err =>
|
||||||
|
err.includes('프록시 사용 시 정상 작동합니다') ||
|
||||||
|
err.includes('프록시를 선택해보세요')
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert className="bg-amber-50 border-amber-200 mt-3">
|
||||||
|
<AlertCircle className="h-4 w-4 text-amber-600" />
|
||||||
|
<AlertTitle className="text-amber-800 text-xs font-medium">프록시 변경 권장</AlertTitle>
|
||||||
|
<AlertDescription className="text-amber-700 text-xs">
|
||||||
|
{recommendationMessage}
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProxyRecommendationAlert;
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { RefreshCw, Info, HelpCircle, AlertCircle } from "lucide-react";
|
|
||||||
import { toast } from "@/hooks/useToast.wrapper";
|
import { toast } from "@/hooks/useToast.wrapper";
|
||||||
import { testSupabaseConnection } from '@/lib/supabase';
|
import { testSupabaseConnection } from '@/lib/supabase';
|
||||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
|
||||||
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
|
|
||||||
import { TestResults } from '@/lib/supabase/tests/types';
|
import { TestResults } from '@/lib/supabase/tests/types';
|
||||||
|
|
||||||
|
// 분리된 컴포넌트들 임포트
|
||||||
|
import ConnectionTestButton from './ConnectionTestButton';
|
||||||
|
import TestResultItem from './TestResultItem';
|
||||||
|
import ProxyInfoCard from './ProxyInfoCard';
|
||||||
|
import ProxyRecommendationAlert from './ProxyRecommendationAlert';
|
||||||
|
import ErrorMessageCard from './ErrorMessageCard';
|
||||||
|
import TroubleshootingTips from './TroubleshootingTips';
|
||||||
|
import DebugInfoCollapsible from './DebugInfoCollapsible';
|
||||||
|
|
||||||
const SupabaseConnectionTest: React.FC = () => {
|
const SupabaseConnectionTest: React.FC = () => {
|
||||||
const [testResults, setTestResults] = useState<TestResults | null>(null);
|
const [testResults, setTestResults] = useState<TestResults | null>(null);
|
||||||
const [isTesting, setIsTesting] = useState(false);
|
const [isTesting, setIsTesting] = useState(false);
|
||||||
@@ -42,175 +48,34 @@ const SupabaseConnectionTest: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasProxyRecommendation = (errors: string[]) => {
|
|
||||||
return errors.some(err =>
|
|
||||||
err.includes('프록시 사용 시 정상 작동합니다') ||
|
|
||||||
err.includes('프록시를 선택해보세요')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold mb-4">연결 테스트</h2>
|
<h2 className="text-lg font-semibold mb-4">연결 테스트</h2>
|
||||||
|
|
||||||
<Button
|
<ConnectionTestButton
|
||||||
onClick={runConnectionTest}
|
onClick={runConnectionTest}
|
||||||
disabled={isTesting}
|
isTesting={isTesting}
|
||||||
variant="outline"
|
/>
|
||||||
className="w-full mb-4"
|
|
||||||
>
|
|
||||||
{isTesting ? (
|
|
||||||
<>
|
|
||||||
<RefreshCw className="mr-2 h-4 w-4 animate-spin" />
|
|
||||||
테스트 중...
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<RefreshCw className="mr-2 h-4 w-4" />
|
|
||||||
연결 테스트 실행
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{testResults && (
|
{testResults && (
|
||||||
<div className="mt-4 space-y-3 text-sm">
|
<div className="mt-4 space-y-3 text-sm">
|
||||||
<div className="flex justify-between">
|
<TestResultItem label="REST API" success={testResults.restApi} />
|
||||||
<span className="font-medium">REST API:</span>
|
<TestResultItem label="인증" success={testResults.auth} />
|
||||||
<span className={testResults.restApi ? 'text-green-500' : 'text-red-500'}>
|
<TestResultItem label="데이터베이스" success={testResults.database} />
|
||||||
{testResults.restApi ? '✅ 성공' : '❌ 실패'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="font-medium">인증:</span>
|
|
||||||
<span className={testResults.auth ? 'text-green-500' : 'text-red-500'}>
|
|
||||||
{testResults.auth ? '✅ 성공' : '❌ 실패'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="font-medium">데이터베이스:</span>
|
|
||||||
<span className={testResults.database ? 'text-green-500' : 'text-red-500'}>
|
|
||||||
{testResults.database ? '✅ 성공' : '❌ 실패'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{testResults.usingProxy && (
|
<ProxyInfoCard testResults={testResults} />
|
||||||
<div className="bg-blue-50 border border-blue-200 rounded p-2 mt-2">
|
|
||||||
<p className="text-xs">CORS 프록시 사용 중: {testResults.proxyType || 'corsproxy.io'}</p>
|
|
||||||
<p className="text-xs break-all mt-1">{testResults.proxyUrl}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{testResults.errors.length > 0 && hasProxyRecommendation(testResults.errors) && (
|
<ProxyRecommendationAlert errors={testResults.errors} />
|
||||||
<Alert className="bg-amber-50 border-amber-200 mt-3">
|
|
||||||
<AlertCircle className="h-4 w-4 text-amber-600" />
|
|
||||||
<AlertTitle className="text-amber-800 text-xs font-medium">프록시 변경 권장</AlertTitle>
|
|
||||||
<AlertDescription className="text-amber-700 text-xs">
|
|
||||||
{testResults.errors.find(err =>
|
|
||||||
err.includes('프록시 사용 시 정상 작동합니다') ||
|
|
||||||
err.includes('프록시를 선택해보세요')
|
|
||||||
)}
|
|
||||||
</AlertDescription>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{testResults.errors.length > 0 && (
|
<ErrorMessageCard errors={testResults.errors} />
|
||||||
<div className="bg-red-50 border border-red-200 rounded p-2 mt-2">
|
|
||||||
{testResults.errors.map((error: string, index: number) => (
|
|
||||||
<p key={index} className="text-xs text-red-600 mb-1">{error}</p>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 오류 해결 팁 */}
|
<TroubleshootingTips testResults={testResults} />
|
||||||
{!testResults.restApi && testResults.auth && (
|
|
||||||
<div className="bg-yellow-50 border border-yellow-200 rounded p-2 mt-2">
|
|
||||||
<div className="flex items-start gap-1">
|
|
||||||
<HelpCircle className="h-4 w-4 text-yellow-600 mt-0.5 flex-shrink-0" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-yellow-800 font-medium">인증은 성공했지만 API/DB 연결에 실패했습니다</p>
|
|
||||||
<ul className="list-disc text-xs text-yellow-700 pl-4 mt-1">
|
|
||||||
<li>다른 CORS 프록시 옵션을 시도해보세요</li>
|
|
||||||
<li>Supabase 서버의 CORS 설정을 확인하세요</li>
|
|
||||||
<li>브라우저 개발자 도구에서 네트워크 탭을 확인하세요</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 디버그 정보 섹션 추가 */}
|
<DebugInfoCollapsible
|
||||||
{testResults.debugInfo && (
|
testResults={testResults}
|
||||||
<Collapsible
|
showDebug={showDebug}
|
||||||
open={showDebug}
|
setShowDebug={setShowDebug}
|
||||||
onOpenChange={setShowDebug}
|
/>
|
||||||
className="border border-gray-200 rounded-md mt-4"
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-between px-4 py-2 bg-gray-50">
|
|
||||||
<h4 className="text-sm font-medium">고급 진단 정보</h4>
|
|
||||||
<CollapsibleTrigger asChild>
|
|
||||||
<Button variant="ghost" size="sm" className="h-7 w-7 p-0">
|
|
||||||
<Info className="h-4 w-4" />
|
|
||||||
<span className="sr-only">
|
|
||||||
{showDebug ? '진단 정보 숨기기' : '진단 정보 표시'}
|
|
||||||
</span>
|
|
||||||
</Button>
|
|
||||||
</CollapsibleTrigger>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<CollapsibleContent className="px-4 py-2 text-xs">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">Supabase URL:</span>
|
|
||||||
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
|
||||||
{testResults.url}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{testResults.usingProxy && (
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">프록시 URL:</span>
|
|
||||||
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
|
||||||
{testResults.proxyUrl}
|
|
||||||
</div>
|
|
||||||
<div className="mt-1">
|
|
||||||
프록시 유형: {testResults.proxyType || 'corsproxy.io'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">클라이언트 초기화:</span>
|
|
||||||
<div className="mt-1 text-green-600">
|
|
||||||
{testResults.client ? '성공' : '실패'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{testResults.debugInfo.lastErrorDetails && (
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">마지막 오류 상세:</span>
|
|
||||||
<div className="mt-1 bg-red-50 p-1 rounded break-all text-red-600">
|
|
||||||
{testResults.debugInfo.lastErrorDetails}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">브라우저 정보:</span>
|
|
||||||
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
|
||||||
{testResults.debugInfo.browserInfo}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">테스트 시간:</span>
|
|
||||||
<div className="mt-1">
|
|
||||||
{new Date(testResults.debugInfo.timestamp).toLocaleString()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CollapsibleContent>
|
|
||||||
</Collapsible>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
20
src/components/supabase/TestResultItem.tsx
Normal file
20
src/components/supabase/TestResultItem.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface TestResultItemProps {
|
||||||
|
label: string;
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TestResultItem: React.FC<TestResultItemProps> = ({ label, success }) => {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="font-medium">{label}:</span>
|
||||||
|
<span className={success ? 'text-green-500' : 'text-red-500'}>
|
||||||
|
{success ? '✅ 성공' : '❌ 실패'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TestResultItem;
|
||||||
30
src/components/supabase/TroubleshootingTips.tsx
Normal file
30
src/components/supabase/TroubleshootingTips.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
|
import { TestResults } from '@/lib/supabase/tests/types';
|
||||||
|
|
||||||
|
interface TroubleshootingTipsProps {
|
||||||
|
testResults: TestResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TroubleshootingTips: React.FC<TroubleshootingTipsProps> = ({ testResults }) => {
|
||||||
|
if (!(!testResults.restApi && testResults.auth)) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-yellow-50 border border-yellow-200 rounded p-2 mt-2">
|
||||||
|
<div className="flex items-start gap-1">
|
||||||
|
<HelpCircle className="h-4 w-4 text-yellow-600 mt-0.5 flex-shrink-0" />
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-yellow-800 font-medium">인증은 성공했지만 API/DB 연결에 실패했습니다</p>
|
||||||
|
<ul className="list-disc text-xs text-yellow-700 pl-4 mt-1">
|
||||||
|
<li>다른 CORS 프록시 옵션을 시도해보세요</li>
|
||||||
|
<li>Supabase 서버의 CORS 설정을 확인하세요</li>
|
||||||
|
<li>브라우저 개발자 도구에서 네트워크 탭을 확인하세요</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TroubleshootingTips;
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
import { testAuth } from './authTests';
|
import { testAuth } from './authTests';
|
||||||
import { testRestApi } from './apiTests';
|
import { testRestApi } from './apiTests';
|
||||||
import { testDatabaseConnection } from './databaseTests';
|
import { testDatabaseConnection } from './databaseTests';
|
||||||
import { TestResults } from './types';
|
import { TestResults, TestDebugInfo } from './types';
|
||||||
import { supabase, isValidUrl } from '../client';
|
import { supabase, isValidUrl } from '../client';
|
||||||
import { getSupabaseUrl, getSupabaseKey, isCorsProxyEnabled, getProxyType } from '../config';
|
import { getSupabaseUrl, getSupabaseKey, isCorsProxyEnabled, getProxyType } from '../config';
|
||||||
|
|
||||||
@@ -17,7 +17,18 @@ export const testSupabaseConnection = async (): Promise<TestResults> => {
|
|||||||
restApi: false,
|
restApi: false,
|
||||||
auth: false,
|
auth: false,
|
||||||
database: false,
|
database: false,
|
||||||
errors: []
|
errors: [],
|
||||||
|
debugInfo: {
|
||||||
|
originalUrl: getSupabaseUrl(),
|
||||||
|
proxyUrl: '',
|
||||||
|
usingProxy: isCorsProxyEnabled(),
|
||||||
|
proxyType: getProxyType(),
|
||||||
|
keyLength: getSupabaseKey().length,
|
||||||
|
browserInfo: navigator.userAgent,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
backupProxySuccess: false,
|
||||||
|
lastErrorDetails: ''
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -40,12 +51,16 @@ export const testSupabaseConnection = async (): Promise<TestResults> => {
|
|||||||
} else {
|
} else {
|
||||||
results.proxyUrl = baseUrl; // 기본값
|
results.proxyUrl = baseUrl; // 기본값
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debugInfo에도 proxyUrl 설정
|
||||||
|
results.debugInfo.proxyUrl = results.proxyUrl;
|
||||||
} else {
|
} else {
|
||||||
results.proxyUrl = results.url; // 프록시 사용 안 함
|
results.proxyUrl = results.url; // 프록시 사용 안 함
|
||||||
|
results.debugInfo.proxyUrl = results.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 테스트 실행
|
// 테스트 실행
|
||||||
const authResults = await testAuth(supabase, results.url);
|
const authResults = await testAuth(supabase);
|
||||||
const apiResults = await testRestApi(supabase);
|
const apiResults = await testRestApi(supabase);
|
||||||
const dbResults = await testDatabaseConnection(supabase);
|
const dbResults = await testDatabaseConnection(supabase);
|
||||||
|
|
||||||
@@ -57,15 +72,20 @@ export const testSupabaseConnection = async (): Promise<TestResults> => {
|
|||||||
// 오류 수집
|
// 오류 수집
|
||||||
if (!authResults.success && authResults.error) {
|
if (!authResults.success && authResults.error) {
|
||||||
results.errors.push(`인증 테스트 실패: ${authResults.error}`);
|
results.errors.push(`인증 테스트 실패: ${authResults.error}`);
|
||||||
|
results.debugInfo.lastErrorDetails += `인증: ${authResults.error}; `;
|
||||||
}
|
}
|
||||||
if (!apiResults.success && apiResults.error) {
|
if (!apiResults.success && apiResults.error) {
|
||||||
results.errors.push(`REST API 테스트 실패: ${apiResults.error}`);
|
results.errors.push(`REST API 테스트 실패: ${apiResults.error}`);
|
||||||
|
results.debugInfo.lastErrorDetails += `API: ${apiResults.error}; `;
|
||||||
}
|
}
|
||||||
if (!dbResults.success && dbResults.error) {
|
if (!dbResults.success && dbResults.error) {
|
||||||
results.errors.push(`DB 테스트 실패: ${dbResults.error}`);
|
results.errors.push(`DB 테스트 실패: ${dbResults.error}`);
|
||||||
|
results.debugInfo.lastErrorDetails += `DB: ${dbResults.error}; `;
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
results.errors.push(`테스트 실행 오류: ${error.message || '알 수 없는 오류'}`);
|
const errorMsg = `테스트 실행 오류: ${error.message || '알 수 없는 오류'}`;
|
||||||
|
results.errors.push(errorMsg);
|
||||||
|
results.debugInfo.lastErrorDetails = errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
|||||||
@@ -6,18 +6,6 @@ export interface TestResult {
|
|||||||
error: string | null;
|
error: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TestResults {
|
|
||||||
url: string;
|
|
||||||
proxyUrl: string; // 추가된 필드
|
|
||||||
usingProxy: boolean;
|
|
||||||
proxyType: string;
|
|
||||||
client: boolean;
|
|
||||||
restApi: boolean;
|
|
||||||
auth: boolean;
|
|
||||||
database: boolean;
|
|
||||||
errors: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TestDebugInfo {
|
export interface TestDebugInfo {
|
||||||
originalUrl: string;
|
originalUrl: string;
|
||||||
proxyUrl: string;
|
proxyUrl: string;
|
||||||
@@ -30,6 +18,19 @@ export interface TestDebugInfo {
|
|||||||
lastErrorDetails: string;
|
lastErrorDetails: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TestResults {
|
||||||
|
url: string;
|
||||||
|
proxyUrl: string;
|
||||||
|
usingProxy: boolean;
|
||||||
|
proxyType: string;
|
||||||
|
client: boolean;
|
||||||
|
restApi: boolean;
|
||||||
|
auth: boolean;
|
||||||
|
database: boolean;
|
||||||
|
errors: string[];
|
||||||
|
debugInfo: TestDebugInfo;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ConnectionTestResult {
|
export interface ConnectionTestResult {
|
||||||
url: string;
|
url: string;
|
||||||
proxyUrl: string;
|
proxyUrl: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user