From 506475e5cccaa18eb0a2c50c53ef2e04a09fe445 Mon Sep 17 00:00:00 2001 From: DDD1542 Date: Wed, 11 Mar 2026 16:31:52 +0900 Subject: [PATCH] [agent-pipeline] pipe-20260311071246-rhvz round-4 --- .../v2/config-panels/V2SelectConfigPanel.tsx | 426 +++++++++--------- 1 file changed, 201 insertions(+), 225 deletions(-) diff --git a/frontend/components/v2/config-panels/V2SelectConfigPanel.tsx b/frontend/components/v2/config-panels/V2SelectConfigPanel.tsx index 66ebb369..47964819 100644 --- a/frontend/components/v2/config-panels/V2SelectConfigPanel.tsx +++ b/frontend/components/v2/config-panels/V2SelectConfigPanel.tsx @@ -9,7 +9,6 @@ import React, { useState, useEffect, useCallback, useMemo } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Separator } from "@/components/ui/separator"; import { Checkbox } from "@/components/ui/checkbox"; import { Button } from "@/components/ui/button"; import { Plus, Trash2, Loader2, Filter } from "lucide-react"; @@ -75,7 +74,6 @@ const FilterConditionsSection: React.FC<{ const updated = [...filters]; updated[index] = { ...updated[index], ...patch }; - // valueType 변경 시 관련 필드 초기화 if (patch.valueType) { if (patch.valueType === "static") { updated[index].fieldRef = undefined; @@ -89,7 +87,6 @@ const FilterConditionsSection: React.FC<{ } } - // isNull/isNotNull 연산자는 값 불필요 if (patch.operator === "isNull" || patch.operator === "isNotNull") { updated[index].value = undefined; updated[index].fieldRef = undefined; @@ -107,11 +104,11 @@ const FilterConditionsSection: React.FC<{ const needsValue = (op: string) => op !== "isNull" && op !== "isNotNull"; return ( -
+
- + DATA FILTER
- {/* 행 2: 값 유형 + 값 입력 (isNull/isNotNull 제외) */} {needsValue(filter.operator) && (
- {/* 값 유형 */} - {/* 값 입력 영역 */} {(filter.valueType || "static") === "static" && ( ; onChange: (config: Record) => void; - /** 컬럼의 inputType (entity/category 타입 확인용) */ inputType?: string; - /** 현재 테이블명 (카테고리 값 조회용) */ tableName?: string; - /** 현재 컬럼명 (카테고리 값 조회용) */ columnName?: string; } @@ -282,11 +269,9 @@ export const V2SelectConfigPanel: React.FC = ({ const [entityColumns, setEntityColumns] = useState([]); const [loadingColumns, setLoadingColumns] = useState(false); - // 카테고리 값 목록 const [categoryValues, setCategoryValues] = useState([]); const [loadingCategoryValues, setLoadingCategoryValues] = useState(false); - // 필터용 컬럼 목록 (옵션 데이터 소스 테이블의 컬럼) const [filterColumns, setFilterColumns] = useState([]); const [loadingFilterColumns, setLoadingFilterColumns] = useState(false); @@ -294,7 +279,6 @@ export const V2SelectConfigPanel: React.FC = ({ onChange({ ...config, [field]: value }); }; - // 필터 대상 테이블 결정 const filterTargetTable = useMemo(() => { const src = config.source || "static"; if (src === "entity") return config.entityTable; @@ -303,7 +287,6 @@ export const V2SelectConfigPanel: React.FC = ({ return null; }, [config.source, config.entityTable, config.table, tableName]); - // 필터 대상 테이블의 컬럼 로드 useEffect(() => { if (!filterTargetTable) { setFilterColumns([]); @@ -332,14 +315,12 @@ export const V2SelectConfigPanel: React.FC = ({ loadFilterColumns(); }, [filterTargetTable]); - // 카테고리 타입이면 source를 자동으로 category로 설정 useEffect(() => { if (isCategoryType && config.source !== "category") { onChange({ ...config, source: "category" }); } }, [isCategoryType]); - // 카테고리 값 로드 const loadCategoryValues = useCallback(async (catTable: string, catColumn: string) => { if (!catTable || !catColumn) { setCategoryValues([]); @@ -374,7 +355,6 @@ export const V2SelectConfigPanel: React.FC = ({ } }, []); - // 카테고리 소스일 때 값 로드 useEffect(() => { if (config.source === "category") { const catTable = config.categoryTable || tableName; @@ -385,7 +365,6 @@ export const V2SelectConfigPanel: React.FC = ({ } }, [config.source, config.categoryTable, config.categoryColumn, tableName, columnName, loadCategoryValues]); - // 엔티티 테이블 변경 시 컬럼 목록 조회 const loadEntityColumns = useCallback(async (tblName: string) => { if (!tblName) { setEntityColumns([]); @@ -423,7 +402,6 @@ export const V2SelectConfigPanel: React.FC = ({ } }, [config.source, config.entityTable, loadEntityColumns]); - // 정적 옵션 관리 const options = config.options || []; const addOption = () => { @@ -442,135 +420,139 @@ export const V2SelectConfigPanel: React.FC = ({ updateConfig("options", newOptions); }; - // 현재 source 결정 (카테고리 타입이면 강제 category) const effectiveSource = isCategoryType ? "category" : config.source || "static"; return ( -
- {/* 선택 모드 */} -
- - -
- - - - {/* 데이터 소스 */} -
- - {isCategoryType ? ( -
- 카테고리 (자동 설정) +
+ {/* SELECT MODE 섹션 */} +
+

SELECT MODE

+
+ 선택 모드 +
+
- ) : ( - - )} +
- {/* 카테고리 설정 */} + {/* DATA SOURCE 섹션 */} +
+

DATA SOURCE

+
+ 데이터 소스 +
+ {isCategoryType ? ( +
+ 카테고리 (자동) +
+ ) : ( + + )} +
+
+
+ + {/* CATEGORY 섹션 */} {effectiveSource === "category" && ( -
-
- -
-
-
-

테이블

-

{config.categoryTable || tableName || "-"}

-
-
-

컬럼

-

{config.categoryColumn || columnName || "-"}

-
+
+

CATEGORY

+ +
+
+
+

테이블

+

{config.categoryTable || tableName || "-"}

+
+
+

컬럼

+

{config.categoryColumn || columnName || "-"}

- {/* 카테고리 값 로딩 중 */} {loadingCategoryValues && ( -
+
카테고리 값 로딩 중...
)} - {/* 카테고리 값 목록 표시 */} {categoryValues.length > 0 && ( -
- -
- {categoryValues.map((cv) => ( -
- {cv.valueCode} - {cv.valueLabel} -
- ))} -
-
- )} - - {/* 기본값 설정 */} - {categoryValues.length > 0 && ( -
- - -

화면 로드 시 자동 선택될 카테고리 값

-
+
+
+ +
+ 기본값 +
+ +
+
+

화면 로드 시 자동 선택될 카테고리 값

+ )} - {/* 카테고리 값 없음 안내 */} {!loadingCategoryValues && categoryValues.length === 0 && ( -

+

카테고리 값이 없습니다. 테이블 카테고리 관리에서 값을 추가해주세요.

)}
)} - {/* 정적 옵션 관리 */} + {/* STATIC OPTIONS 섹션 */} {effectiveSource === "static" && ( -
-
- +
+
+

STATIC OPTIONS

- {/* 기본값 설정 */} {options.length > 0 && ( -
- - -

화면 로드 시 자동 선택될 값

-
+ <> +
+ 기본값 +
+ +
+
+

화면 로드 시 자동 선택될 값

+ )}
)} - {/* 공통 코드 설정 */} + {/* CODE GROUP 섹션 */} {effectiveSource === "code" && ( -
- - {config.codeGroup ? ( -

{config.codeGroup}

- ) : ( -

테이블 타입 관리에서 코드 그룹을 설정해주세요

- )} +
+

CODE GROUP

+
+ 코드 그룹 +
+ {config.codeGroup ? ( + {config.codeGroup} + ) : ( + 미설정 + )} +
+
)} - {/* 엔티티(참조 테이블) 설정 */} + {/* ENTITY 섹션 */} {effectiveSource === "entity" && ( -
-
- - -

- 조인할 테이블명 (테이블 타입 관리에서 설정된 경우 자동 입력됨) -

+
+

ENTITY

+ +
+ 참조 테이블 +
+ +
{loadingColumns && ( -
+
컬럼 목록 로딩 중...
)} -
-
- +
+
+ {entityColumns.length > 0 ? ( updateConfig("entityLabelColumn", value)} > - + @@ -715,89 +705,75 @@ export const V2SelectConfigPanel: React.FC = ({ value={config.entityLabelColumn || ""} onChange={(e) => updateConfig("entityLabelColumn", e.target.value)} placeholder="name" - className="h-8 text-xs" + className="h-7 text-xs" /> )} -

화면에 표시될 값

{config.entityTable && !loadingColumns && entityColumns.length === 0 && ( -

+

테이블 컬럼을 조회할 수 없습니다. 테이블 타입 관리에서 참조 테이블을 설정해주세요.

)} {config.entityTable && entityColumns.length > 0 && ( -
-

- 같은 폼에 참조 테이블({config.entityTable})의 컬럼이 배치되어 있으면, 엔티티 선택 시 해당 필드가 자동으로 - 채워집니다. -

-
+

+ 같은 폼에 참조 테이블({config.entityTable})의 컬럼이 배치되어 있으면, 엔티티 선택 시 해당 필드가 자동으로 + 채워집니다. +

)}
)} - + {/* OPTIONS 섹션 */} +
+

OPTIONS

- {/* 추가 옵션 */} -
- - -
+
+ 다중 선택 허용 updateConfig("multiple", checked)} /> -
-
+
+ 검색 기능 updateConfig("searchable", checked)} /> -
-
+
+ 값 초기화 허용 updateConfig("allowClear", checked)} /> -
+ + {config.multiple && ( +
+ 최대 선택 개수 +
+ updateConfig("maxSelect", e.target.value ? Number(e.target.value) : undefined)} + placeholder="제한 없음" + min="1" + className="h-7 text-xs" + /> +
+
+ )}
- {/* 다중 선택 시 최대 개수 */} - {config.multiple && ( -
- - updateConfig("maxSelect", e.target.value ? Number(e.target.value) : undefined)} - placeholder="제한 없음" - min="1" - className="h-8 text-xs" - /> -
- )} - - {/* 데이터 필터 조건 - static 소스 외 모든 소스에서 사용 */} + {/* DATA FILTER 섹션 */} {effectiveSource !== "static" && filterTargetTable && ( - <> - +
= ({ targetTable={filterTargetTable} onFiltersChange={(filters) => updateConfig("filters", filters)} /> - +
)}
);