diff --git a/.gitignore b/.gitignore index 2566257f..972957ba 100644 --- a/.gitignore +++ b/.gitignore @@ -194,4 +194,6 @@ mcp-task-queue/ # 파이프라인 회고록 (자동 생성) docs/retrospectives/ -mes-architecture-guide.md \ No newline at end of file +mes-architecture-guide.md +# MES Reference Documents +docs/mes-reference/ diff --git a/frontend/components/v2/V2Repeater.tsx b/frontend/components/v2/V2Repeater.tsx index f2f46f82..9290f21c 100644 --- a/frontend/components/v2/V2Repeater.tsx +++ b/frontend/components/v2/V2Repeater.tsx @@ -367,6 +367,20 @@ export const V2Repeater: React.FC = ({ }); try { + // 🆕 필수값 검증 + const requiredColumns = repeaterColumnsRef.current.filter(col => col.required); + for (let i = 0; i < currentData.length; i++) { + const row = currentData[i]; + for (const col of requiredColumns) { + const val = row[col.field]; + if (val === undefined || val === null || val === "") { + toast.error(`${i + 1}번째 행의 '${col.label}'은(는) 필수 입력 항목입니다.`); + window.dispatchEvent(new CustomEvent("repeaterSaveComplete")); + return; + } + } + } + let validColumns: Set = new Set(); try { const columnsResponse = await apiClient.get(`/table-management/tables/${tableName}/columns`); @@ -706,6 +720,7 @@ export const V2Repeater: React.FC = ({ displayName: col.displayName || col.display_name || col.label || name, detailSettings: col.detailSettings || col.detail_settings, categoryRef: typeInfo?.categoryRef || null, + isRequired: col.isRequired || col.is_required || col.notNull || col.not_null === true || col.not_null === 'Y' || col.not_null === 'y', }; }); setCurrentTableColumnInfo(columnMap); @@ -808,10 +823,12 @@ export const V2Repeater: React.FC = ({ loadSourceColumnLabels(); }, [resolvedSourceTable, isModalMode]); + const repeaterColumnsRef = useRef([]); + // V2ColumnConfig → RepeaterColumnConfig 변환 // 🆕 모든 컬럼을 columns 배열의 순서대로 처리 (isSourceDisplay 플래그로 구분) const repeaterColumns: RepeaterColumnConfig[] = useMemo(() => { - return config.columns + const cols = config.columns .filter((col: V2ColumnConfig) => col.visible !== false) .map((col: V2ColumnConfig): RepeaterColumnConfig => { const colInfo = currentTableColumnInfo[col.key]; @@ -858,12 +875,15 @@ export const V2Repeater: React.FC = ({ type, editable: col.editable !== false, width: col.width === "auto" ? undefined : col.width, - required: false, + required: colInfo?.isRequired || false, categoryRef, // 🆕 카테고리 참조 ID 전달 hidden: col.hidden, // 🆕 히든 처리 autoFill: col.autoFill, // 🆕 자동 입력 설정 }; }); + + repeaterColumnsRef.current = cols; + return cols; }, [config.columns, sourceColumnLabels, currentTableColumnInfo, resolvedSourceTable, config.dataSource?.tableName]); // 리피터 컬럼 설정에서 카테고리 타입 컬럼 자동 감지