diff --git a/backend-node/src/services/tableManagementService.ts b/backend-node/src/services/tableManagementService.ts index 8bcec704..ac8b62fd 100644 --- a/backend-node/src/services/tableManagementService.ts +++ b/backend-node/src/services/tableManagementService.ts @@ -1069,12 +1069,28 @@ export class TableManagementService { paramCount: number; } | null> { try { + // ๐Ÿ”ง {value, operator} ํ˜•ํƒœ์˜ ํ•„ํ„ฐ ๊ฐ์ฒด ์ฒ˜๋ฆฌ + let actualValue = value; + let operator = "contains"; // ๊ธฐ๋ณธ๊ฐ’ + + if (typeof value === "object" && value !== null && "value" in value) { + actualValue = value.value; + operator = value.operator || "contains"; + + logger.info("๐Ÿ” ํ•„ํ„ฐ ๊ฐ์ฒด ์ฒ˜๋ฆฌ:", { + columnName, + originalValue: value, + actualValue, + operator, + }); + } + // "__ALL__" ๊ฐ’์ด๊ฑฐ๋‚˜ ๋นˆ ๊ฐ’์ด๋ฉด ํ•„ํ„ฐ ์กฐ๊ฑด์„ ์ ์šฉํ•˜์ง€ ์•Š์Œ if ( - value === "__ALL__" || - value === "" || - value === null || - value === undefined + actualValue === "__ALL__" || + actualValue === "" || + actualValue === null || + actualValue === undefined ) { return null; } @@ -1083,12 +1099,22 @@ export class TableManagementService { const columnInfo = await this.getColumnWebTypeInfo(tableName, columnName); if (!columnInfo) { - // ์ปฌ๋Ÿผ ์ •๋ณด๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ๋ณธ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰ - return { - whereClause: `${columnName}::text ILIKE $${paramIndex}`, - values: [`%${value}%`], - paramCount: 1, - }; + // ์ปฌ๋Ÿผ ์ •๋ณด๊ฐ€ ์—†์œผ๋ฉด operator์— ๋”ฐ๋ฅธ ๊ธฐ๋ณธ ๊ฒ€์ƒ‰ + switch (operator) { + case "equals": + return { + whereClause: `${columnName}::text = $${paramIndex}`, + values: [actualValue], + paramCount: 1, + }; + case "contains": + default: + return { + whereClause: `${columnName}::text ILIKE $${paramIndex}`, + values: [`%${actualValue}%`], + paramCount: 1, + }; + } } const webType = columnInfo.webType; @@ -1097,17 +1123,17 @@ export class TableManagementService { switch (webType) { case "date": case "datetime": - return this.buildDateRangeCondition(columnName, value, paramIndex); + return this.buildDateRangeCondition(columnName, actualValue, paramIndex); case "number": case "decimal": - return this.buildNumberRangeCondition(columnName, value, paramIndex); + return this.buildNumberRangeCondition(columnName, actualValue, paramIndex); case "code": return await this.buildCodeSearchCondition( tableName, columnName, - value, + actualValue, paramIndex ); @@ -1115,15 +1141,15 @@ export class TableManagementService { return await this.buildEntitySearchCondition( tableName, columnName, - value, + actualValue, paramIndex ); default: - // ๊ธฐ๋ณธ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰ + // ๊ธฐ๋ณธ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰ (actualValue ์‚ฌ์šฉ) return { whereClause: `${columnName}::text ILIKE $${paramIndex}`, - values: [`%${value}%`], + values: [`%${actualValue}%`], paramCount: 1, }; } @@ -1133,9 +1159,14 @@ export class TableManagementService { error ); // ์˜ค๋ฅ˜ ์‹œ ๊ธฐ๋ณธ ๊ฒ€์ƒ‰์œผ๋กœ ํด๋ฐฑ + let fallbackValue = value; + if (typeof value === "object" && value !== null && "value" in value) { + fallbackValue = value.value; + } + return { whereClause: `${columnName}::text ILIKE $${paramIndex}`, - values: [`%${value}%`], + values: [`%${fallbackValue}%`], paramCount: 1, }; } diff --git a/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx b/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx index 68a686b8..91947094 100644 --- a/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx +++ b/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx @@ -185,11 +185,6 @@ export const SplitPanelLayoutComponent: React.FC // ๐Ÿ”„ ์ปฌ๋Ÿผ ๊ฐ€์‹œ์„ฑ ๋ฐ ์ˆœ์„œ ์ฒ˜๋ฆฌ const visibleLeftColumns = useMemo(() => { const displayColumns = componentConfig.leftPanel?.columns || []; - console.log("๐Ÿ” [๋ถ„ํ• ํŒจ๋„] visibleLeftColumns ๊ณ„์‚ฐ:", { - displayColumns: displayColumns.length, - leftColumnVisibility: leftColumnVisibility.length, - leftColumnOrder: leftColumnOrder.length, - }); if (displayColumns.length === 0) return []; @@ -202,7 +197,6 @@ export const SplitPanelLayoutComponent: React.FC const colName = typeof col === 'string' ? col : (col.name || col.columnName); return visibilityMap.get(colName) !== false; }); - console.log("โœ… [๋ถ„ํ• ํŒจ๋„] ๊ฐ€์‹œ์„ฑ ์ ์šฉ ํ›„:", columns.length); } // ๐Ÿ”ง ์ปฌ๋Ÿผ ์ˆœ์„œ ์ ์šฉ @@ -215,7 +209,6 @@ export const SplitPanelLayoutComponent: React.FC const bIndex = orderMap.get(bName) ?? 999; return aIndex - bIndex; }); - console.log("โœ… [๋ถ„ํ• ํŒจ๋„] ์ˆœ์„œ ์ ์šฉ ํ›„:", columns.map((c: any) => typeof c === 'string' ? c : (c.name || c.columnName))); } return columns; @@ -258,11 +251,6 @@ export const SplitPanelLayoutComponent: React.FC // ๐ŸŽฏ ํ•„ํ„ฐ ์กฐ๊ฑด์„ API์— ์ „๋‹ฌ (entityJoinApi ์‚ฌ์šฉ) const filters = Object.keys(searchValues).length > 0 ? searchValues : undefined; - console.log("๐Ÿ“ก [๋ถ„ํ• ํŒจ๋„] API ํ˜ธ์ถœ ์‹œ์ž‘:", { - tableName: leftTableName, - filters, - searchValues, - }); const result = await entityJoinApi.getTableDataWithJoins(leftTableName, { page: 1, @@ -271,11 +259,6 @@ export const SplitPanelLayoutComponent: React.FC enableEntityJoin: true, // ์—”ํ‹ฐํ‹ฐ ์กฐ์ธ ํ™œ์„ฑํ™” }); - console.log("๐Ÿ“ก [๋ถ„ํ• ํŒจ๋„] API ์‘๋‹ต:", { - success: result.success, - dataLength: result.data?.length || 0, - totalItems: result.totalItems, - }); // ๊ฐ€๋‚˜๋‹ค์ˆœ ์ •๋ ฌ (์ขŒ์ธก ํŒจ๋„์˜ ํ‘œ์‹œ ์ปฌ๋Ÿผ ๊ธฐ์ค€) const leftColumn = componentConfig.rightPanel?.relation?.leftColumn; @@ -946,12 +929,6 @@ export const SplitPanelLayoutComponent: React.FC // ๐Ÿ”ง ์ปฌ๋Ÿผ ๊ฐ€์‹œ์„ฑ ๋ณ€๊ฒฝ ์‹œ localStorage์— ์ €์žฅ ๋ฐ ์ˆœ์„œ ์—…๋ฐ์ดํŠธ useEffect(() => { const leftTableName = componentConfig.leftPanel?.tableName; - console.log("๐Ÿ” [๋ถ„ํ• ํŒจ๋„] ์ปฌ๋Ÿผ ๊ฐ€์‹œ์„ฑ ๋ณ€๊ฒฝ ๊ฐ์ง€:", { - leftColumnVisibility: leftColumnVisibility.length, - leftTableName, - currentUserId, - visibility: leftColumnVisibility, - }); if (leftColumnVisibility.length > 0 && leftTableName && currentUserId) { // ์ˆœ์„œ ์—…๋ฐ์ดํŠธ @@ -959,13 +936,11 @@ export const SplitPanelLayoutComponent: React.FC .map((cv) => cv.columnName) .filter((name) => name !== "__checkbox__"); // ์ฒดํฌ๋ฐ•์Šค ์ œ์™ธ - console.log("โœ… [๋ถ„ํ• ํŒจ๋„] ์ปฌ๋Ÿผ ์ˆœ์„œ ์—…๋ฐ์ดํŠธ:", newOrder); setLeftColumnOrder(newOrder); // localStorage์— ์ €์žฅ const storageKey = `table_column_visibility_${leftTableName}_${currentUserId}`; localStorage.setItem(storageKey, JSON.stringify(leftColumnVisibility)); - console.log("๐Ÿ’พ [๋ถ„ํ• ํŒจ๋„] localStorage ์ €์žฅ:", storageKey); } }, [leftColumnVisibility, componentConfig.leftPanel?.tableName, currentUserId]); @@ -979,16 +954,7 @@ export const SplitPanelLayoutComponent: React.FC // ๐Ÿ”„ ํ•„ํ„ฐ ๋ณ€๊ฒฝ ์‹œ ๋ฐ์ดํ„ฐ ๋‹ค์‹œ ๋กœ๋“œ useEffect(() => { - console.log("๐Ÿ” [๋ถ„ํ• ํŒจ๋„] ํ•„ํ„ฐ ๋ณ€๊ฒฝ ๊ฐ์ง€:", { - leftFilters: leftFilters.length, - filters: leftFilters, - isDesignMode, - autoLoad: componentConfig.autoLoad, - searchValues, - }); - if (!isDesignMode && componentConfig.autoLoad !== false) { - console.log("โœ… [๋ถ„ํ• ํŒจ๋„] loadLeftData ํ˜ธ์ถœ (ํ•„ํ„ฐ ๋ณ€๊ฒฝ)"); loadLeftData(); } // eslint-disable-next-line react-hooks/exhaustive-deps