From 2cddb4225520e99f999eb0ca7950f00d2b667408 Mon Sep 17 00:00:00 2001 From: kjs Date: Thu, 4 Dec 2025 14:30:52 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table-list/TableListComponent.tsx | 63 ++-- .../table-list/TableListConfigPanel.tsx | 326 +++++++++--------- 2 files changed, 198 insertions(+), 191 deletions(-) diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index 7f6fded5..6a1f01fe 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -1183,13 +1183,20 @@ export const TableListComponent: React.FC = ({ referenceTable: col.additionalJoinInfo!.referenceTable, })); - // console.log("๐Ÿ” [TableList] API ํ˜ธ์ถœ ์‹œ์ž‘", { - // tableName: tableConfig.selectedTable, - // page, - // pageSize, - // sortBy, - // sortOrder, - // }); + // ๐ŸŽฏ ํ™”๋ฉด๋ณ„ ์—”ํ‹ฐํ‹ฐ ํ‘œ์‹œ ์„ค์ • ์ˆ˜์ง‘ + const screenEntityConfigs: Record = {}; + (tableConfig.columns || []) + .filter((col) => col.entityDisplayConfig && col.entityDisplayConfig.displayColumns?.length > 0) + .forEach((col) => { + screenEntityConfigs[col.columnName] = { + displayColumns: col.entityDisplayConfig!.displayColumns, + separator: col.entityDisplayConfig!.separator || " - ", + sourceTable: col.entityDisplayConfig!.sourceTable || tableConfig.selectedTable, + joinTable: col.entityDisplayConfig!.joinTable, + }; + }); + + console.log("๐ŸŽฏ [TableList] ํ™”๋ฉด๋ณ„ ์—”ํ‹ฐํ‹ฐ ์„ค์ •:", screenEntityConfigs); // ๐ŸŽฏ ํ•ญ์ƒ entityJoinApi ์‚ฌ์šฉ (writer ์ปฌ๋Ÿผ ์ž๋™ ์กฐ์ธ ์ง€์›) response = await entityJoinApi.getTableDataWithJoins(tableConfig.selectedTable, { @@ -1200,6 +1207,7 @@ export const TableListComponent: React.FC = ({ search: hasFilters ? filters : undefined, enableEntityJoin: true, additionalJoinColumns: entityJoinColumns.length > 0 ? entityJoinColumns : undefined, + screenEntityConfigs: Object.keys(screenEntityConfigs).length > 0 ? screenEntityConfigs : undefined, // ๐ŸŽฏ ํ™”๋ฉด๋ณ„ ์—”ํ‹ฐํ‹ฐ ์„ค์ • ์ „๋‹ฌ dataFilter: tableConfig.dataFilter, // ๐Ÿ†• ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ ์ „๋‹ฌ }); @@ -1756,33 +1764,46 @@ export const TableListComponent: React.FC = ({ const formatCellValue = useCallback( (value: any, column: ColumnConfig, rowData?: Record) => { - if (value === null || value === undefined) return "-"; - - // ๐ŸŽฏ writer ์ปฌ๋Ÿผ ์ž๋™ ๋ณ€ํ™˜: user_id -> user_name - if (column.columnName === "writer" && rowData && rowData.writer_name) { - return rowData.writer_name; - } - - // ๐ŸŽฏ ์—”ํ‹ฐํ‹ฐ ์ปฌ๋Ÿผ ํ‘œ์‹œ ์„ค์ •์ด ์žˆ๋Š” ๊ฒฝ์šฐ + // ๐ŸŽฏ ์—”ํ‹ฐํ‹ฐ ์ปฌ๋Ÿผ ํ‘œ์‹œ ์„ค์ •์ด ์žˆ๋Š” ๊ฒฝ์šฐ - value๊ฐ€ null์ด์–ด๋„ rowData์—์„œ ์กฐํ•ฉ ๊ฐ€๋Šฅ + // ์ด ์ฒดํฌ๋ฅผ ๊ฐ€์žฅ ๋จผ์ € ์ˆ˜ํ–‰ (null ์ฒดํฌ๋ณด๋‹ค ์•ž์—) if (column.entityDisplayConfig && rowData) { - // displayColumns ๋˜๋Š” selectedColumns ๋‘˜ ๋‹ค ์ฒดํฌ - const displayColumns = column.entityDisplayConfig.displayColumns || column.entityDisplayConfig.selectedColumns; + const displayColumns = column.entityDisplayConfig.displayColumns || (column.entityDisplayConfig as any).selectedColumns; const separator = column.entityDisplayConfig.separator; if (displayColumns && displayColumns.length > 0) { // ์„ ํƒ๋œ ์ปฌ๋Ÿผ๋“ค์˜ ๊ฐ’์„ ๊ตฌ๋ถ„์ž๋กœ ์กฐํ•ฉ const values = displayColumns - .map((colName) => { - const cellValue = rowData[colName]; + .map((colName: string) => { + // 1. ๋จผ์ € ์ง์ ‘ ์ปฌ๋Ÿผ๋ช…์œผ๋กœ ์‹œ๋„ (๊ธฐ๋ณธ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ์ธ ๊ฒฝ์šฐ) + let cellValue = rowData[colName]; + + // 2. ์—†์œผ๋ฉด ${sourceColumn}_${colName} ํ˜•์‹์œผ๋กœ ์‹œ๋„ (์กฐ์ธ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ์ธ ๊ฒฝ์šฐ) + if (cellValue === null || cellValue === undefined) { + const joinedKey = `${column.columnName}_${colName}`; + cellValue = rowData[joinedKey]; + } + if (cellValue === null || cellValue === undefined) return ""; return String(cellValue); }) - .filter((v) => v !== ""); // ๋นˆ ๊ฐ’ ์ œ์™ธ + .filter((v: string) => v !== ""); // ๋นˆ ๊ฐ’ ์ œ์™ธ - return values.join(separator || " - "); + const result = values.join(separator || " - "); + if (result) { + return result; // ๊ฒฐ๊ณผ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฐ˜ํ™˜ + } + // ๊ฒฐ๊ณผ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด ์•„๋ž˜๋กœ ๊ณ„์† ์ง„ํ–‰ (์›๋ž˜ ๊ฐ’ ์‚ฌ์šฉ) } } + // value๊ฐ€ null/undefined๋ฉด "-" ๋ฐ˜ํ™˜ + if (value === null || value === undefined) return "-"; + + // ๐ŸŽฏ writer ์ปฌ๋Ÿผ ์ž๋™ ๋ณ€ํ™˜: user_id -> user_name + if (column.columnName === "writer" && rowData && rowData.writer_name) { + return rowData.writer_name; + } + const meta = columnMeta[column.columnName]; // inputType ๊ธฐ๋ฐ˜ ํฌ๋งทํŒ… (columnMeta์—์„œ ๊ฐ€์ ธ์˜จ inputType ์šฐ์„ ) diff --git a/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx b/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx index 6e6c414f..823424cc 100644 --- a/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx +++ b/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx @@ -467,42 +467,22 @@ export const TableListConfigPanel: React.FC = ({ // ๐ŸŽฏ ์—”ํ‹ฐํ‹ฐ ์ปฌ๋Ÿผ์˜ ํ‘œ์‹œ ์ปฌ๋Ÿผ ์ •๋ณด ๋กœ๋“œ const loadEntityDisplayConfig = async (column: ColumnConfig) => { - if (!column.isEntityJoin || !column.entityJoinInfo) { - return; - } + const configKey = `${column.columnName}`; + + // ์ด๋ฏธ ๋กœ๋“œ๋œ ๊ฒฝ์šฐ ์Šคํ‚ต + if (entityDisplayConfigs[configKey]) return; - // entityDisplayConfig๊ฐ€ ์—†์œผ๋ฉด ์ดˆ๊ธฐํ™” - if (!column.entityDisplayConfig) { - // sourceTable์„ ๊ฒฐ์ •: entityJoinInfo -> config.selectedTable -> screenTableName ์ˆœ์„œ - const initialSourceTable = column.entityJoinInfo?.sourceTable || config.selectedTable || screenTableName; - - if (!initialSourceTable) { - return; - } - - const updatedColumns = config.columns?.map((col) => { - if (col.columnName === column.columnName) { - return { - ...col, - entityDisplayConfig: { - displayColumns: [], - separator: " - ", - sourceTable: initialSourceTable, - joinTable: "", - }, - }; - } - return col; - }); - - if (updatedColumns) { - handleChange("columns", updatedColumns); - // ์—…๋ฐ์ดํŠธ๋œ ์ปฌ๋Ÿผ์œผ๋กœ ๋‹ค์‹œ ์‹œ๋„ - const updatedColumn = updatedColumns.find((col) => col.columnName === column.columnName); - if (updatedColumn) { - return loadEntityDisplayConfig(updatedColumn); - } - } + if (!column.isEntityJoin) { + // ์—”ํ‹ฐํ‹ฐ ์ปฌ๋Ÿผ์ด ์•„๋‹ˆ๋ฉด ๋นˆ ์ƒํƒœ๋กœ ์„ค์ •ํ•˜์—ฌ ๋กœ๋”ฉ ์ƒํƒœ ํ•ด์ œ + setEntityDisplayConfigs((prev) => ({ + ...prev, + [configKey]: { + sourceColumns: [], + joinColumns: [], + selectedColumns: [], + separator: " - ", + }, + })); return; } @@ -512,32 +492,56 @@ export const TableListConfigPanel: React.FC = ({ // 3. config.selectedTable // 4. screenTableName const sourceTable = - column.entityDisplayConfig.sourceTable || + column.entityDisplayConfig?.sourceTable || column.entityJoinInfo?.sourceTable || config.selectedTable || screenTableName; - let joinTable = column.entityDisplayConfig.joinTable; - - // sourceTable์ด ์—ฌ์ „ํžˆ ๋น„์–ด์žˆ์œผ๋ฉด ์—๋Ÿฌ + // sourceTable์ด ๋น„์–ด์žˆ์œผ๋ฉด ๋นˆ ์ƒํƒœ๋กœ ์„ค์ • if (!sourceTable) { + console.warn("โš ๏ธ sourceTable์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ:", column.columnName); + setEntityDisplayConfigs((prev) => ({ + ...prev, + [configKey]: { + sourceColumns: [], + joinColumns: [], + selectedColumns: column.entityDisplayConfig?.displayColumns || [], + separator: column.entityDisplayConfig?.separator || " - ", + }, + })); return; } - if (!joinTable && sourceTable) { - // joinTable์ด ์—†์œผ๋ฉด tableTypeApi๋กœ ์กฐํšŒํ•ด์„œ ์„ค์ • + let joinTable = column.entityDisplayConfig?.joinTable; + + // joinTable์ด ์—†์œผ๋ฉด tableTypeApi๋กœ ์กฐํšŒํ•ด์„œ ์„ค์ • + if (!joinTable) { try { + console.log("๐Ÿ” tableTypeApi๋กœ ์ปฌ๋Ÿผ ์ •๋ณด ์กฐํšŒ:", { + tableName: sourceTable, + columnName: column.columnName, + }); + const columnList = await tableTypeApi.getColumns(sourceTable); const columnInfo = columnList.find((col: any) => (col.column_name || col.columnName) === column.columnName); + console.log("๐Ÿ” ์ปฌ๋Ÿผ ์ •๋ณด ์กฐํšŒ ๊ฒฐ๊ณผ:", { + columnInfo: columnInfo, + referenceTable: columnInfo?.reference_table || columnInfo?.referenceTable, + referenceColumn: columnInfo?.reference_column || columnInfo?.referenceColumn, + }); + if (columnInfo?.reference_table || columnInfo?.referenceTable) { joinTable = columnInfo.reference_table || columnInfo.referenceTable; + console.log("โœ… tableTypeApi์—์„œ ์กฐ์ธ ํ…Œ์ด๋ธ” ์ •๋ณด ์ฐพ์Œ:", joinTable); // entityDisplayConfig ์—…๋ฐ์ดํŠธ const updatedConfig = { ...column.entityDisplayConfig, sourceTable: sourceTable, joinTable: joinTable, + displayColumns: column.entityDisplayConfig?.displayColumns || [], + separator: column.entityDisplayConfig?.separator || " - ", }; // ์ปฌ๋Ÿผ ์„ค์ • ์—…๋ฐ์ดํŠธ @@ -553,74 +557,27 @@ export const TableListConfigPanel: React.FC = ({ } } catch (error) { console.error("tableTypeApi ์ปฌ๋Ÿผ ์ •๋ณด ์กฐํšŒ ์‹คํŒจ:", error); - console.log("โŒ ์กฐํšŒ ์‹คํŒจ ์ƒ์„ธ:", { sourceTable, columnName: column.columnName }); } - } else if (!joinTable) { - console.warn("โš ๏ธ sourceTable์ด ์—†์–ด์„œ joinTable ์กฐํšŒ ๋ถˆ๊ฐ€:", column.columnName); } console.log("๐Ÿ” ์ตœ์ข… ์ถ”์ถœํ•œ ๊ฐ’:", { sourceTable, joinTable }); - const configKey = `${column.columnName}`; - - // ์ด๋ฏธ ๋กœ๋“œ๋œ ๊ฒฝ์šฐ ์Šคํ‚ต - if (entityDisplayConfigs[configKey]) return; - - // joinTable์ด ๋น„์–ด์žˆ์œผ๋ฉด tableTypeApi๋กœ ์ปฌ๋Ÿผ ์ •๋ณด๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์™€์„œ referenceTable ์ •๋ณด๋ฅผ ์ฐพ๊ธฐ - let actualJoinTable = joinTable; - if (!actualJoinTable && sourceTable) { - try { - console.log("๐Ÿ” tableTypeApi๋กœ ์ปฌ๋Ÿผ ์ •๋ณด ๋‹ค์‹œ ์กฐํšŒ:", { - tableName: sourceTable, - columnName: column.columnName, - }); - - const columnList = await tableTypeApi.getColumns(sourceTable); - const columnInfo = columnList.find((col: any) => (col.column_name || col.columnName) === column.columnName); - - console.log("๐Ÿ” ์ปฌ๋Ÿผ ์ •๋ณด ์กฐํšŒ ๊ฒฐ๊ณผ:", { - columnInfo: columnInfo, - referenceTable: columnInfo?.reference_table || columnInfo?.referenceTable, - referenceColumn: columnInfo?.reference_column || columnInfo?.referenceColumn, - }); - - if (columnInfo?.reference_table || columnInfo?.referenceTable) { - actualJoinTable = columnInfo.reference_table || columnInfo.referenceTable; - console.log("โœ… tableTypeApi์—์„œ ์กฐ์ธ ํ…Œ์ด๋ธ” ์ •๋ณด ์ฐพ์Œ:", actualJoinTable); - - // entityDisplayConfig ์—…๋ฐ์ดํŠธ - const updatedConfig = { - ...column.entityDisplayConfig, - joinTable: actualJoinTable, - }; - - // ์ปฌ๋Ÿผ ์„ค์ • ์—…๋ฐ์ดํŠธ - const updatedColumns = config.columns?.map((col) => - col.columnName === column.columnName ? { ...col, entityDisplayConfig: updatedConfig } : col, - ); - - if (updatedColumns) { - handleChange("columns", updatedColumns); - } - } - } catch (error) { - console.error("tableTypeApi ์ปฌ๋Ÿผ ์ •๋ณด ์กฐํšŒ ์‹คํŒจ:", error); - } - } - - // sourceTable๊ณผ joinTable์ด ๋ชจ๋‘ ์žˆ์–ด์•ผ ๋กœ๋“œ - if (!sourceTable || !actualJoinTable) { - return; - } try { - // ๊ธฐ๋ณธ ํ…Œ์ด๋ธ”๊ณผ ์กฐ์ธ ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ ์ •๋ณด๋ฅผ ๋ณ‘๋ ฌ๋กœ ๋กœ๋“œ - const [sourceResult, joinResult] = await Promise.all([ - entityJoinApi.getReferenceTableColumns(sourceTable), - entityJoinApi.getReferenceTableColumns(actualJoinTable), - ]); - + // ๊ธฐ๋ณธ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ์ •๋ณด๋Š” ํ•ญ์ƒ ๋กœ๋“œ + const sourceResult = await entityJoinApi.getReferenceTableColumns(sourceTable); const sourceColumns = sourceResult.columns || []; - const joinColumns = joinResult.columns || []; + + // joinTable์ด ์žˆ์œผ๋ฉด ์กฐ์ธ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ๋„ ๋กœ๋“œ + let joinColumns: Array<{ columnName: string; displayName: string; dataType: string }> = []; + if (joinTable) { + try { + const joinResult = await entityJoinApi.getReferenceTableColumns(joinTable); + joinColumns = joinResult.columns || []; + } catch (joinError) { + console.warn("โš ๏ธ ์กฐ์ธ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ๋กœ๋“œ ์‹คํŒจ:", joinTable, joinError); + // ์กฐ์ธ ํ…Œ์ด๋ธ” ๋กœ๋“œ ์‹คํŒจํ•ด๋„ ์†Œ์Šค ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ์€ ํ‘œ์‹œ + } + } setEntityDisplayConfigs((prev) => ({ ...prev, @@ -633,6 +590,16 @@ export const TableListConfigPanel: React.FC = ({ })); } catch (error) { console.error("์—”ํ‹ฐํ‹ฐ ํ‘œ์‹œ ์ปฌ๋Ÿผ ์ •๋ณด ๋กœ๋“œ ์‹คํŒจ:", error); + // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ์—๋„ ๋นˆ ์ƒํƒœ๋กœ ์„ค์ •ํ•˜์—ฌ ๋กœ๋”ฉ ์ƒํƒœ ํ•ด์ œ + setEntityDisplayConfigs((prev) => ({ + ...prev, + [configKey]: { + sourceColumns: [], + joinColumns: [], + selectedColumns: column.entityDisplayConfig?.displayColumns || [], + separator: column.entityDisplayConfig?.separator || " - ", + }, + })); } }; @@ -873,76 +840,95 @@ export const TableListConfigPanel: React.FC = ({ {/* ํ‘œ์‹œ ์ปฌ๋Ÿผ ์„ ํƒ (๋‹ค์ค‘ ์„ ํƒ) */}
- - - - - - - - - ์ปฌ๋Ÿผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. - {entityDisplayConfigs[column.columnName].sourceColumns.length > 0 && ( - - {entityDisplayConfigs[column.columnName].sourceColumns.map((col) => ( - toggleEntityDisplayColumn(column.columnName, col.columnName)} - className="text-xs" - > - - {col.displayName} - - ))} - - )} - {entityDisplayConfigs[column.columnName].joinColumns.length > 0 && ( - - {entityDisplayConfigs[column.columnName].joinColumns.map((col) => ( - toggleEntityDisplayColumn(column.columnName, col.columnName)} - className="text-xs" - > - - {col.displayName} - - ))} - - )} - - - - + {entityDisplayConfigs[column.columnName].sourceColumns.length === 0 && + entityDisplayConfigs[column.columnName].joinColumns.length === 0 ? ( +
+ ํ‘œ์‹œ ๊ฐ€๋Šฅํ•œ ์ปฌ๋Ÿผ์ด ์—†์Šต๋‹ˆ๋‹ค. + {!column.entityDisplayConfig?.joinTable && ( +

+ ํ…Œ์ด๋ธ” ํƒ€์ž… ๊ด€๋ฆฌ์—์„œ ์ฐธ์กฐ ํ…Œ์ด๋ธ”์„ ์„ค์ •ํ•˜๋ฉด ๋” ๋งŽ์€ ์ปฌ๋Ÿผ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +

+ )} +
+ ) : ( + + + + + + + + + ์ปฌ๋Ÿผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. + {entityDisplayConfigs[column.columnName].sourceColumns.length > 0 && ( + + {entityDisplayConfigs[column.columnName].sourceColumns.map((col) => ( + toggleEntityDisplayColumn(column.columnName, col.columnName)} + className="text-xs" + > + + {col.displayName} + + ))} + + )} + {entityDisplayConfigs[column.columnName].joinColumns.length > 0 && ( + + {entityDisplayConfigs[column.columnName].joinColumns.map((col) => ( + toggleEntityDisplayColumn(column.columnName, col.columnName)} + className="text-xs" + > + + {col.displayName} + + ))} + + )} + + + + + )}
+ {/* ์ฐธ์กฐ ํ…Œ์ด๋ธ” ๋ฏธ์„ค์ • ์•ˆ๋‚ด */} + {!column.entityDisplayConfig?.joinTable && entityDisplayConfigs[column.columnName].sourceColumns.length > 0 && ( +
+ ํ˜„์žฌ ๊ธฐ๋ณธ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ” ํƒ€์ž… ๊ด€๋ฆฌ์—์„œ ์ฐธ์กฐ ํ…Œ์ด๋ธ”์„ ์„ค์ •ํ•˜๋ฉด ์กฐ์ธ๋œ ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ๋„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +
+ )} + {/* ์„ ํƒ๋œ ์ปฌ๋Ÿผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ */} {entityDisplayConfigs[column.columnName].selectedColumns.length > 0 && (