From 238a7d1db4402f22a571eed5941b42d6522ceb77 Mon Sep 17 00:00:00 2001 From: kmh Date: Wed, 11 Mar 2026 23:38:42 +0900 Subject: [PATCH] feat: Enhance V2RepeaterConfigPanel with entity join column management - Updated the toggleEntityJoinColumn function to include an optional columnType parameter for better flexibility in handling join columns. - Improved the logic for managing entity joins and columns, ensuring that columns are correctly added or removed based on user interactions. - Introduced a new section in the UI to display entity join columns in a read-only format, providing users with clear visibility of the join configurations. - Added loading states and messages to enhance user experience during data retrieval for entity joins. These changes aim to improve the functionality and usability of the V2RepeaterConfigPanel in managing entity relationships. --- .../config-panels/V2RepeaterConfigPanel.tsx | 278 +++++++++--------- 1 file changed, 134 insertions(+), 144 deletions(-) diff --git a/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx b/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx index e3f5f6cc..92efdcd8 100644 --- a/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx +++ b/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx @@ -375,12 +375,15 @@ export const V2RepeaterConfigPanel: React.FC = ({ // Entity 조인 컬럼 토글 (추가/제거) const toggleEntityJoinColumn = useCallback( - (joinTableName: string, sourceColumn: string, refColumnName: string, refColumnLabel: string, displayField: string) => { + (joinTableName: string, sourceColumn: string, refColumnName: string, refColumnLabel: string, displayField: string, columnType?: string) => { const currentJoins = config.entityJoins || []; const existingJoinIdx = currentJoins.findIndex( (j) => j.sourceColumn === sourceColumn && j.referenceTable === joinTableName, ); + let newEntityJoins = [...currentJoins]; + let newColumns = [...config.columns]; + if (existingJoinIdx >= 0) { const existingJoin = currentJoins[existingJoinIdx]; const existingColIdx = existingJoin.columns.findIndex((c) => c.referenceField === refColumnName); @@ -388,34 +391,49 @@ export const V2RepeaterConfigPanel: React.FC = ({ if (existingColIdx >= 0) { const updatedColumns = existingJoin.columns.filter((_, i) => i !== existingColIdx); if (updatedColumns.length === 0) { - updateConfig({ entityJoins: currentJoins.filter((_, i) => i !== existingJoinIdx) }); + newEntityJoins = newEntityJoins.filter((_, i) => i !== existingJoinIdx); } else { - const updated = [...currentJoins]; - updated[existingJoinIdx] = { ...existingJoin, columns: updatedColumns }; - updateConfig({ entityJoins: updated }); + newEntityJoins[existingJoinIdx] = { ...existingJoin, columns: updatedColumns }; } + // config.columns에서도 제거 + newColumns = newColumns.filter(c => !(c.key === displayField && c.isJoinColumn)); } else { - const updated = [...currentJoins]; - updated[existingJoinIdx] = { + newEntityJoins[existingJoinIdx] = { ...existingJoin, columns: [...existingJoin.columns, { referenceField: refColumnName, displayField }], }; - updateConfig({ entityJoins: updated }); + // config.columns에 추가 + newColumns.push({ + key: displayField, + title: refColumnLabel, + width: "auto", + visible: true, + editable: false, + isJoinColumn: true, + inputType: columnType || "text", + }); } } else { - updateConfig({ - entityJoins: [ - ...currentJoins, - { - sourceColumn, - referenceTable: joinTableName, - columns: [{ referenceField: refColumnName, displayField }], - }, - ], + newEntityJoins.push({ + sourceColumn, + referenceTable: joinTableName, + columns: [{ referenceField: refColumnName, displayField }], + }); + // config.columns에 추가 + newColumns.push({ + key: displayField, + title: refColumnLabel, + width: "auto", + visible: true, + editable: false, + isJoinColumn: true, + inputType: columnType || "text", }); } + + updateConfig({ entityJoins: newEntityJoins, columns: newColumns }); }, - [config.entityJoins, updateConfig], + [config.entityJoins, config.columns, updateConfig], ); // Entity 조인에 특정 컬럼이 설정되어 있는지 확인 @@ -604,9 +622,9 @@ export const V2RepeaterConfigPanel: React.FC = ({ // 컬럼 토글 (현재 테이블 컬럼 - 입력용) const toggleInputColumn = (column: ColumnOption) => { - const existingIndex = config.columns.findIndex((c) => c.key === column.columnName); + const existingIndex = config.columns.findIndex((c) => c.key === column.columnName && !c.isJoinColumn && !c.isSourceDisplay); if (existingIndex >= 0) { - const newColumns = config.columns.filter((c) => c.key !== column.columnName); + const newColumns = config.columns.filter((_, i) => i !== existingIndex); updateConfig({ columns: newColumns }); } else { // 컬럼의 inputType과 detailSettings 정보 포함 @@ -651,7 +669,7 @@ export const V2RepeaterConfigPanel: React.FC = ({ }; const isColumnAdded = (columnName: string) => { - return config.columns.some((c) => c.key === columnName && !c.isSourceDisplay); + return config.columns.some((c) => c.key === columnName && !c.isSourceDisplay && !c.isJoinColumn); }; const isSourceColumnSelected = (columnName: string) => { @@ -761,10 +779,9 @@ export const V2RepeaterConfigPanel: React.FC = ({ return (
- + 기본 컬럼 - Entity 조인 {/* 기본 설정 탭 */} @@ -1365,6 +1382,84 @@ export const V2RepeaterConfigPanel: React.FC = ({ )}
+ {/* ===== 🆕 Entity 조인 컬럼 (표시용) ===== */} +
+
+ + +
+

+ FK 컬럼을 기반으로 참조 테이블의 데이터를 자동으로 조회하여 표시합니다. +

+ + {loadingEntityJoins ? ( +

로딩 중...

+ ) : entityJoinData.joinTables.length === 0 ? ( +

+ {entityJoinTargetTable + ? `${entityJoinTargetTable} 테이블에 Entity 조인 가능한 컬럼이 없습니다` + : "저장 테이블을 먼저 설정해주세요"} +

+ ) : ( +
+ {entityJoinData.joinTables.map((joinTable, tableIndex) => { + const sourceColumn = (joinTable as any).joinConfig?.sourceColumn || ""; + + return ( +
+
+ + {joinTable.tableName} + ({sourceColumn}) +
+
+ {joinTable.availableColumns.map((column, colIndex) => { + const isActive = isEntityJoinColumnActive( + joinTable.tableName, + sourceColumn, + column.columnName, + ); + const matchingCol = config.columns.find((c) => c.key === column.columnName && c.isJoinColumn); + const displayField = matchingCol?.key || column.columnName; + + return ( +
+ toggleEntityJoinColumn( + joinTable.tableName, + sourceColumn, + column.columnName, + column.columnLabel, + displayField, + column.inputType || column.dataType + ) + } + > + + + {column.columnLabel} + + {column.inputType || column.dataType} + +
+ ); + })} +
+
+ ); + })} +
+ )} +
+ {/* 선택된 컬럼 상세 설정 - 🆕 모든 컬럼 통합, 순서 변경 가능 */} {config.columns.length > 0 && ( <> @@ -1381,7 +1476,7 @@ export const V2RepeaterConfigPanel: React.FC = ({
= ({ {/* 확장/축소 버튼 (입력 컬럼만) */} - {!col.isSourceDisplay && ( + {(!col.isSourceDisplay && !col.isJoinColumn) && (
{/* 확장된 상세 설정 (입력 컬럼만) */} - {!col.isSourceDisplay && expandedColumn === col.key && ( + {(!col.isSourceDisplay && !col.isJoinColumn) && expandedColumn === col.key && (
{/* 자동 입력 설정 */}
@@ -1812,120 +1916,6 @@ export const V2RepeaterConfigPanel: React.FC = ({ )} - {/* Entity 조인 설정 탭 */} - -
-
-

Entity 조인 연결

-

- FK 컬럼을 기반으로 참조 테이블의 데이터를 자동으로 조회하여 표시합니다 -

-
-
- - {loadingEntityJoins ? ( -

로딩 중...

- ) : entityJoinData.joinTables.length === 0 ? ( -
-

- {entityJoinTargetTable - ? `${entityJoinTargetTable} 테이블에 Entity 조인 가능한 컬럼이 없습니다` - : "저장 테이블을 먼저 설정해주세요"} -

-
- ) : ( -
- {entityJoinData.joinTables.map((joinTable, tableIndex) => { - const sourceColumn = (joinTable as any).joinConfig?.sourceColumn || ""; - - return ( -
-
- - {joinTable.tableName} - ({sourceColumn}) -
-
- {joinTable.availableColumns.map((column, colIndex) => { - const isActive = isEntityJoinColumnActive( - joinTable.tableName, - sourceColumn, - column.columnName, - ); - const matchingCol = config.columns.find((c) => c.key === column.columnName); - const displayField = matchingCol?.key || column.columnName; - - return ( -
- toggleEntityJoinColumn( - joinTable.tableName, - sourceColumn, - column.columnName, - column.columnLabel, - displayField, - ) - } - > - - - {column.columnLabel} - - {column.inputType || column.dataType} - -
- ); - })} -
-
- ); - })} -
- )} - - {/* 현재 설정된 Entity 조인 목록 */} - {config.entityJoins && config.entityJoins.length > 0 && ( -
-

설정된 조인

-
- {config.entityJoins.map((join, idx) => ( -
- - {join.sourceColumn} - - {join.referenceTable} - - ({join.columns.map((c) => c.referenceField).join(", ")}) - - -
- ))} -
-
- )} -
-
-
);