/** * 테이블 생성 모달 컴포넌트 * 새로운 테이블을 생성하기 위한 모달 */ "use client"; import { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Checkbox } from "@/components/ui/checkbox"; import { Loader2, Info, AlertCircle, CheckCircle2, Plus, Activity } from "lucide-react"; import { toast } from "sonner"; import { ColumnDefinitionTable } from "./ColumnDefinitionTable"; import { ddlApi } from "../../lib/api/ddl"; import { tableManagementApi } from "../../lib/api/tableManagement"; import { CreateTableModalProps, CreateColumnDefinition, VALIDATION_RULES, SYSTEM_TABLES, RESERVED_WORDS, } from "../../types/ddl"; export function CreateTableModal({ isOpen, onClose, onSuccess }: CreateTableModalProps) { const [tableName, setTableName] = useState(""); const [description, setDescription] = useState(""); const [columns, setColumns] = useState([ { name: "", label: "", inputType: "text", nullable: true, order: 1, }, ]); const [loading, setLoading] = useState(false); const [validating, setValidating] = useState(false); const [tableNameError, setTableNameError] = useState(""); const [validationResult, setValidationResult] = useState(null); const [useLogTable, setUseLogTable] = useState(false); /** * 모달 리셋 */ const resetModal = () => { setTableName(""); setDescription(""); setColumns([ { name: "", label: "", inputType: "text", nullable: true, order: 1, }, ]); setTableNameError(""); setValidationResult(null); setUseLogTable(false); }; /** * 모달 열림/닫힘 시 리셋 */ useEffect(() => { if (isOpen) { resetModal(); } }, [isOpen]); /** * 테이블명 검증 */ const validateTableName = (name: string): string => { if (!name) { return "테이블명은 필수입니다."; } if (!VALIDATION_RULES.tableName.pattern.test(name)) { return VALIDATION_RULES.tableName.errorMessage; } if (name.length < VALIDATION_RULES.tableName.minLength || name.length > VALIDATION_RULES.tableName.maxLength) { return `테이블명은 ${VALIDATION_RULES.tableName.minLength}-${VALIDATION_RULES.tableName.maxLength}자여야 합니다.`; } if (SYSTEM_TABLES.includes(name.toLowerCase() as any)) { return "시스템 테이블명으로 사용할 수 없습니다."; } if (RESERVED_WORDS.includes(name.toLowerCase() as any)) { return "SQL 예약어는 테이블명으로 사용할 수 없습니다."; } if (name.startsWith("_") || name.endsWith("_")) { return "테이블명은 언더스코어로 시작하거나 끝날 수 없습니다."; } if (name.includes("__")) { return "테이블명에 연속된 언더스코어는 사용할 수 없습니다."; } return ""; }; /** * 테이블명 변경 처리 */ const handleTableNameChange = (value: string) => { setTableName(value); const error = validateTableName(value); setTableNameError(error); // 검증 결과 초기화 if (validationResult) { setValidationResult(null); } }; /** * 컬럼 추가 */ const addColumn = () => { setColumns([ ...columns, { name: "", label: "", inputType: "text", nullable: true, order: columns.length + 1, }, ]); }; /** * 테이블 생성 사전 검증 */ const validateTable = async () => { if (tableNameError || !tableName) { toast.error("테이블명을 올바르게 입력해주세요."); return; } const validColumns = columns.filter((col) => col.name && col.inputType); if (validColumns.length === 0) { toast.error("최소 1개의 유효한 컬럼이 필요합니다."); return; } setValidating(true); try { const result = await ddlApi.validateTableCreation({ tableName, columns: validColumns, description, }); setValidationResult(result); if (result.isValid) { toast.success("검증 완료! 테이블을 생성할 수 있습니다."); } else { toast.error("검증 실패. 오류를 확인해주세요."); } } catch (error: any) { // console.error("테이블 검증 실패:", error); toast.error("검증 중 오류가 발생했습니다."); } finally { setValidating(false); } }; /** * 테이블 생성 실행 */ const handleCreateTable = async () => { if (tableNameError || !tableName) { toast.error("테이블명을 올바르게 입력해주세요."); return; } const validColumns = columns.filter((col) => col.name && col.inputType); if (validColumns.length === 0) { toast.error("최소 1개의 유효한 컬럼이 필요합니다."); return; } setLoading(true); try { const result = await ddlApi.createTable({ tableName, columns: validColumns, description, }); if (result.success) { toast.success(result.message); // 로그 테이블 생성 옵션이 선택되었다면 로그 테이블 생성 if (useLogTable) { try { const pkColumn = { columnName: "id", dataType: "integer" }; const logResult = await tableManagementApi.createLogTable(tableName, pkColumn); if (logResult.success) { toast.success(`${tableName}_log 테이블이 생성되었습니다.`); } else { toast.warning(`테이블은 생성되었으나 로그 테이블 생성 실패: ${logResult.message}`); } } catch (logError) { toast.warning("테이블은 생성되었으나 로그 테이블 생성 중 오류가 발생했습니다."); } } onSuccess(result); onClose(); } else { toast.error(result.error?.details || result.message); } } catch (error: any) { // console.error("테이블 생성 실패:", error); toast.error(error.response?.data?.error?.details || "테이블 생성에 실패했습니다."); } finally { setLoading(false); } }; /** * 폼 유효성 확인 */ const isFormValid = !tableNameError && tableName && columns.some((col) => col.name && col.inputType); return ( 새 테이블 생성 최고 관리자만 새로운 테이블을 생성할 수 있습니다. 테이블명과 컬럼 정의를 입력하고 검증 후 생성하세요.
{/* 테이블 기본 정보 */}
handleTableNameChange(e.target.value)} placeholder="예: customer_info" className={tableNameError ? "border-red-300" : ""} /> {tableNameError &&

{tableNameError}

}

영문자로 시작, 영문자/숫자/언더스코어만 사용 가능

setDescription(e.target.value)} placeholder="테이블에 대한 설명" />
{/* 컬럼 정의 */}
{/* 로그 테이블 생성 옵션 */}
setUseLogTable(checked as boolean)} disabled={loading} />

선택 시 {tableName || "table"}_log 테이블이 자동으로 생성되어 INSERT/UPDATE/DELETE 변경 이력을 기록합니다.

{/* 자동 추가 컬럼 안내 */} 자동 추가 컬럼 다음 컬럼들이 자동으로 추가됩니다: id(기본키), created_date, updated_date, company_code {/* 검증 결과 */} {validationResult && ( {validationResult.isValid ? : } {validationResult.isValid ? "검증 성공" : "검증 실패"}
{validationResult.summary}
{validationResult.errors && validationResult.errors.length > 0 && (
오류:
    {validationResult.errors.map((error: string, index: number) => (
  • {error}
  • ))}
)} {validationResult.warnings && validationResult.warnings.length > 0 && (
경고:
    {validationResult.warnings.map((warning: string, index: number) => (
  • {warning}
  • ))}
)}
)}
); }