import { useState, useEffect, useCallback } from 'react'; import { bypassApi, type BypassConfigRequest, type BypassConfigResponse, type CodeGenerationResult, type WebClientBeanInfo, } from '../api/bypassApi'; import { useToastContext } from '../contexts/ToastContext'; import BypassConfigModal from '../components/bypass/BypassConfigModal'; import ConfirmModal from '../components/ConfirmModal'; import InfoModal from '../components/InfoModal'; import LoadingSpinner from '../components/LoadingSpinner'; interface ConfirmAction { type: 'delete' | 'generate'; config: BypassConfigResponse; } const HTTP_METHOD_COLORS: Record = { GET: 'bg-emerald-100 text-emerald-700', POST: 'bg-blue-100 text-blue-700', PUT: 'bg-amber-100 text-amber-700', DELETE: 'bg-red-100 text-red-700', }; export default function BypassConfig() { const { showToast } = useToastContext(); const [configs, setConfigs] = useState([]); const [loading, setLoading] = useState(true); const [webclientBeans, setWebclientBeans] = useState([]); const [modalOpen, setModalOpen] = useState(false); const [editConfig, setEditConfig] = useState(null); const [confirmAction, setConfirmAction] = useState(null); const [generationResult, setGenerationResult] = useState(null); const loadConfigs = useCallback(async () => { try { const res = await bypassApi.getConfigs(); setConfigs(res.data ?? []); } catch (err) { showToast('Bypass API 목록 조회 실패', 'error'); console.error(err); } finally { setLoading(false); } }, [showToast]); useEffect(() => { loadConfigs(); bypassApi.getWebclientBeans() .then((res) => setWebclientBeans(res.data ?? [])) .catch((err) => console.error(err)); }, [loadConfigs]); const handleCreate = () => { setEditConfig(null); setModalOpen(true); }; const handleEdit = (config: BypassConfigResponse) => { setEditConfig(config); setModalOpen(true); }; const handleSave = async (data: BypassConfigRequest) => { if (editConfig) { await bypassApi.updateConfig(editConfig.id, data); showToast('Bypass API가 수정되었습니다.', 'success'); } else { await bypassApi.createConfig(data); showToast('Bypass API가 등록되었습니다.', 'success'); } await loadConfigs(); }; const handleDeleteConfirm = async () => { if (!confirmAction || confirmAction.type !== 'delete') return; try { await bypassApi.deleteConfig(confirmAction.config.id); showToast('Bypass API가 삭제되었습니다.', 'success'); await loadConfigs(); } catch (err) { showToast('삭제 실패', 'error'); console.error(err); } finally { setConfirmAction(null); } }; const handleGenerateConfirm = async () => { if (!confirmAction || confirmAction.type !== 'generate') return; const targetConfig = confirmAction.config; setConfirmAction(null); try { const res = await bypassApi.generateCode(targetConfig.id, targetConfig.generated); setGenerationResult(res.data); showToast('코드가 생성되었습니다.', 'success'); await loadConfigs(); } catch (err) { showToast('코드 생성 실패', 'error'); console.error(err); } }; if (loading) return ; return (
{/* 헤더 */}

Bypass API 관리

외부 Maritime API를 직접 프록시하는 Bypass API를 등록하고 코드를 생성합니다.

{/* 카드 그리드 */} {configs.length === 0 ? (

등록된 BYPASS API가 없습니다.

위 버튼을 눌러 새 API를 등록하세요.

) : (
{configs.map((config) => (
{/* 카드 헤더 */}

{config.displayName}

{config.domainName}

{config.generated ? '생성 완료' : '미생성'}
{/* 카드 정보 */}
{config.httpMethod} {config.externalPath}

WebClient:{' '} {config.webclientBean}

{config.description && (

{config.description}

)}
{/* 카드 액션 */}
))}
)} {/* 등록/수정 모달 */} setModalOpen(false)} /> {/* 삭제 확인 모달 */} setConfirmAction(null)} /> {/* 코드 생성 확인 모달 */} setConfirmAction(null)} /> {/* 코드 생성 결과 모달 */} setGenerationResult(null)} > {generationResult && (

{generationResult.message}

생성된 파일

{[ { label: 'Controller', path: generationResult.controllerPath }, { label: 'Service', path: generationResult.servicePath }, { label: 'DTO', path: generationResult.dtoPath }, ].map(({ label, path }) => (
{label} {path}
))}
서버를 재시작하면 새 API가 활성화됩니다.
)}
); }