Document on-premise Supabase setup
Adds documentation on how to connect to an on-premise Supabase instance.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { CloudUpload, RefreshCw } from "lucide-react";
|
import { CloudUpload, RefreshCw, Database } from "lucide-react";
|
||||||
import { isSyncEnabled, setSyncEnabled, syncAllData, getLastSyncTime } from "@/utils/syncUtils";
|
import { isSyncEnabled, setSyncEnabled, syncAllData, getLastSyncTime } from "@/utils/syncUtils";
|
||||||
import { toast } from "@/hooks/useToast.wrapper";
|
import { toast } from "@/hooks/useToast.wrapper";
|
||||||
import { useAuth } from "@/contexts/auth";
|
import { useAuth } from "@/contexts/auth";
|
||||||
@@ -139,6 +139,18 @@ const SyncSettings = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 온프레미스 Supabase 설정 버튼 추가 */}
|
||||||
|
<div className="pt-4 border-t border-gray-200">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => navigate('/supabase-settings')}
|
||||||
|
className="w-full flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<Database className="h-4 w-4" />
|
||||||
|
<span>온프레미스 Supabase 설정</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
import { createClient } from '@supabase/supabase-js';
|
import { createClient } from '@supabase/supabase-js';
|
||||||
|
|
||||||
// Supabase URL과 anon key 설정
|
// 온프레미스 Supabase URL과 anon key 설정
|
||||||
const supabaseUrl = 'https://tzmywjqtluhwemhuflhi.supabase.co';
|
const supabaseUrl = process.env.SUPABASE_URL || 'http://your-onpremise-supabase-url.com';
|
||||||
// 올바른 anon key 설정 - 유효한 JWT 형식이어야 함
|
// 온프레미스 anon key 설정
|
||||||
const supabaseAnonKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InR6bXl3anF0bHVod2VtaHVmbGhpIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDk1NDUzMTUsImV4cCI6MjAyNTEyMTMxNX0.iCPZvMm9KeRjxh2cE-rkpAIxf9XpZzGIpSZBXBSRfoU';
|
const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || 'your-onpremise-anon-key';
|
||||||
|
|
||||||
// 유효한 URL이 설정되었는지 확인
|
// 유효한 URL이 설정되었는지 확인
|
||||||
const isValidUrl = supabaseUrl && supabaseAnonKey &&
|
const isValidUrl = supabaseUrl && supabaseAnonKey &&
|
||||||
@@ -21,9 +21,25 @@ try {
|
|||||||
auth: {
|
auth: {
|
||||||
autoRefreshToken: true,
|
autoRefreshToken: true,
|
||||||
persistSession: true,
|
persistSession: true,
|
||||||
|
// 온프레미스 설치를 위한 추가 설정
|
||||||
|
flowType: 'implicit',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Supabase 연결 테스트
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const { data, error } = await supabaseClient.auth.getSession();
|
||||||
|
if (error) {
|
||||||
|
console.warn('Supabase 연결 테스트 실패:', error.message);
|
||||||
|
} else {
|
||||||
|
console.log('Supabase 연결 성공!');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Supabase 연결 확인 중 오류:', err);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Supabase 연결 로그
|
// Supabase 연결 로그
|
||||||
console.log('Supabase 클라이언트가 생성되었습니다.');
|
console.log('Supabase 클라이언트가 생성되었습니다.');
|
||||||
|
|
||||||
@@ -53,3 +69,14 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const supabase = supabaseClient;
|
export const supabase = supabaseClient;
|
||||||
|
|
||||||
|
// 온프레미스 연결을 위한 설정 도우미 함수
|
||||||
|
export const configureSupabase = (url: string, key: string) => {
|
||||||
|
// 로컬 스토리지에 설정 저장
|
||||||
|
localStorage.setItem('supabase_url', url);
|
||||||
|
localStorage.setItem('supabase_key', key);
|
||||||
|
|
||||||
|
// 페이지 새로고침 - 새로운 설정으로 Supabase 클라이언트 초기화
|
||||||
|
window.location.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
146
src/pages/SupabaseSettings.tsx
Normal file
146
src/pages/SupabaseSettings.tsx
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
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 } from "lucide-react";
|
||||||
|
import { toast } from "@/hooks/useToast.wrapper";
|
||||||
|
import { configureSupabase } from "@/lib/supabase";
|
||||||
|
import NavBar from '@/components/NavBar';
|
||||||
|
|
||||||
|
const SupabaseSettings = () => {
|
||||||
|
const [supabaseUrl, setSupabaseUrl] = useState('');
|
||||||
|
const [supabaseKey, setSupabaseKey] = useState('');
|
||||||
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
|
|
||||||
|
// 저장된 설정 불러오기
|
||||||
|
useEffect(() => {
|
||||||
|
const savedUrl = localStorage.getItem('supabase_url');
|
||||||
|
const savedKey = localStorage.getItem('supabase_key');
|
||||||
|
|
||||||
|
if (savedUrl) setSupabaseUrl(savedUrl);
|
||||||
|
if (savedKey) setSupabaseKey(savedKey);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
if (!supabaseUrl || !supabaseKey) {
|
||||||
|
toast({
|
||||||
|
title: "입력 오류",
|
||||||
|
description: "Supabase URL과 Anon Key를 모두 입력해주세요.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsSaving(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Supabase 설정 적용
|
||||||
|
configureSupabase(supabaseUrl, supabaseKey);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "설정 저장 완료",
|
||||||
|
description: "Supabase 설정이 저장되었습니다. 변경사항을 적용합니다.",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Supabase 설정 저장 오류:', error);
|
||||||
|
toast({
|
||||||
|
title: "설정 저장 실패",
|
||||||
|
description: "Supabase 설정을 저장하는 중 오류가 발생했습니다.",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
setIsSaving(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-neuro-background pb-24">
|
||||||
|
<div className="max-w-md mx-auto px-6">
|
||||||
|
<header className="py-8">
|
||||||
|
<h1 className="text-2xl font-bold neuro-text mb-5">Supabase 설정</h1>
|
||||||
|
<p className="text-gray-500 mb-8">
|
||||||
|
온프레미스 Supabase 인스턴스와 연결하기 위한 설정을 입력해주세요.
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="neuro-card p-6 mb-6">
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="supabase-url" className="text-base">Supabase URL</Label>
|
||||||
|
<div className="relative">
|
||||||
|
<DatabaseIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 h-5 w-5" />
|
||||||
|
<Input
|
||||||
|
id="supabase-url"
|
||||||
|
placeholder="http://your-supabase-url.com"
|
||||||
|
value={supabaseUrl}
|
||||||
|
onChange={(e) => setSupabaseUrl(e.target.value)}
|
||||||
|
className="pl-10 neuro-pressed"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="supabase-key" className="text-base">Supabase Anon Key</Label>
|
||||||
|
<div className="relative">
|
||||||
|
<svg
|
||||||
|
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 h-5 w-5"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
|
||||||
|
</svg>
|
||||||
|
<Input
|
||||||
|
id="supabase-key"
|
||||||
|
placeholder="your-anon-key"
|
||||||
|
value={supabaseKey}
|
||||||
|
onChange={(e) => setSupabaseKey(e.target.value)}
|
||||||
|
className="pl-10 neuro-pressed"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={handleSave}
|
||||||
|
disabled={isSaving}
|
||||||
|
className="w-full bg-neuro-income text-white"
|
||||||
|
>
|
||||||
|
{isSaving ? (
|
||||||
|
<>
|
||||||
|
<RefreshCw className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
저장 중...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Save className="mr-2 h-4 w-4" />
|
||||||
|
설정 저장
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="neuro-card p-6">
|
||||||
|
<h2 className="text-lg font-semibold mb-2">도움말</h2>
|
||||||
|
<p className="text-gray-500 text-sm mb-4">
|
||||||
|
온프레미스 Supabase 설정은 다음과 같이 구성됩니다:
|
||||||
|
</p>
|
||||||
|
<ul className="list-disc pl-5 text-sm text-gray-500 space-y-2">
|
||||||
|
<li>
|
||||||
|
<strong>Supabase URL</strong>: 온프레미스로 설치한 Supabase 인스턴스의 URL을 입력합니다.
|
||||||
|
(예: http://192.168.1.100:8000)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Anon Key</strong>: Supabase 대시보드의 API 설정에서 찾을 수 있는 anon/public 키를 입력합니다.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NavBar />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SupabaseSettings;
|
||||||
Reference in New Issue
Block a user