From db3ad9d639dca4a5c57f1a18c5f1e821705cc885 Mon Sep 17 00:00:00 2001
From: DDD1542
Date: Thu, 12 Mar 2026 07:54:21 +0900
Subject: [PATCH] [agent-pipeline] pipe-20260311221723-l7a9 round-2
---
.../V2AggregationWidgetConfigPanel.tsx | 295 ++++++++--------
.../V2BomItemEditorConfigPanel.tsx | 306 ++++++++++------
.../v2/config-panels/V2BomTreeConfigPanel.tsx | 333 +++++++++++-------
3 files changed, 560 insertions(+), 374 deletions(-)
diff --git a/frontend/components/v2/config-panels/V2AggregationWidgetConfigPanel.tsx b/frontend/components/v2/config-panels/V2AggregationWidgetConfigPanel.tsx
index ace13f60..3385572d 100644
--- a/frontend/components/v2/config-panels/V2AggregationWidgetConfigPanel.tsx
+++ b/frontend/components/v2/config-panels/V2AggregationWidgetConfigPanel.tsx
@@ -16,6 +16,7 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/component
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { Separator } from "@/components/ui/separator";
+import { Badge } from "@/components/ui/badge";
import {
Database,
Link2,
@@ -30,6 +31,7 @@ import {
LayoutGrid,
Paintbrush,
ChevronDown,
+ ChevronRight,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { tableManagementApi } from "@/lib/api/tableManagement";
@@ -238,6 +240,8 @@ export const V2AggregationWidgetConfigPanel: React.FC(null);
const dataSourceType = config.dataSourceType || "table";
@@ -650,144 +654,156 @@ export const V2AggregationWidgetConfigPanel: React.FC
-
-
-
- {(config.items || []).length === 0 ? (
-
-
-
아직 집계 항목이 없어요
-
위의 추가 버튼으로 항목을 만들어보세요
-
- ) : (
-
- {(config.items || []).map((item, index) => (
-
-
- 항목 {index + 1}
-
-
-
-
- {/* 컬럼 */}
-
-
컬럼
-
-
-
- {/* 집계 타입 */}
-
- 집계 타입
-
-
-
- {/* 표시 라벨 */}
-
- 표시 라벨
- updateItem(item.id, { columnLabel: e.target.value })}
- placeholder="표시될 라벨"
- className="h-7 text-xs"
- />
-
-
- {/* 표시 형식 */}
-
- 표시 형식
-
-
-
- {/* 접두사 */}
-
- 접두사
- updateItem(item.id, { prefix: e.target.value })}
- placeholder="예: ₩"
- className="h-7 text-xs"
- />
-
-
- {/* 접미사 */}
-
- 접미사
- updateItem(item.id, { suffix: e.target.value })}
- placeholder="예: 원, 개"
- className="h-7 text-xs"
- />
-
-
+
+
+
+
+
+
+ {(config.items || []).length === 0 ? (
+
+
+
아직 집계 항목이 없어요
+
위의 추가 버튼으로 항목을 만들어보세요
- ))}
+ ) : (
+
+ {(config.items || []).map((item, index) => (
+
+
setExpandedItemId(expandedItemId === item.id ? null : item.id)}
+ className="flex w-full items-center gap-1.5 px-2.5 py-1.5 text-left hover:bg-muted/30 transition-colors"
+ >
+
+ #{index + 1}
+ {item.columnLabel || item.columnName || "미설정"}
+ {AGGREGATION_TYPE_OPTIONS.find((o) => o.value === item.type)?.label || item.type}
+ { e.stopPropagation(); removeItem(item.id); }} className="h-5 w-5 p-0 text-muted-foreground hover:text-destructive shrink-0">
+
+
+
+ {expandedItemId === item.id && (
+
+ {/* 컬럼 */}
+
+
컬럼
+
+
+
+ {/* 집계 타입 */}
+
+ 집계 타입
+
+
+
+ {/* 표시 라벨 */}
+
+ 표시 라벨
+ updateItem(item.id, { columnLabel: e.target.value })}
+ placeholder="표시될 라벨"
+ className="h-7 text-xs"
+ />
+
+
+ {/* 표시 형식 */}
+
+ 표시 형식
+
+
+
+ {/* 접두사 */}
+
+ 접두사
+ updateItem(item.id, { prefix: e.target.value })}
+ placeholder="예: ₩"
+ className="h-7 text-xs"
+ />
+
+
+ {/* 접미사 */}
+
+ 접미사
+ updateItem(item.id, { suffix: e.target.value })}
+ placeholder="예: 원, 개"
+ className="h-7 text-xs"
+ />
+
+
+ )}
+
+ ))}
+
+ )}
- )}
-
+
+
{/* ═══════════════════════════════════════ */}
{/* 3단계: 필터 조건 (접힘) */}
@@ -803,9 +819,9 @@ export const V2AggregationWidgetConfigPanel: React.FC
필터 조건
{(config.filters || []).length > 0 && (
-
+
{(config.filters || []).length}
-
+
)}
@@ -845,7 +861,7 @@ export const V2AggregationWidgetConfigPanel: React.FC필터 없음 - 전체 데이터를 집계합니다
) : (
-
+
{(config.filters || []).map((filter, index) => (
레이아웃
+ {config.layout === "vertical" ? "세로" : "가로"}
diff --git a/frontend/components/v2/config-panels/V2BomItemEditorConfigPanel.tsx b/frontend/components/v2/config-panels/V2BomItemEditorConfigPanel.tsx
index ccc37664..04865427 100644
--- a/frontend/components/v2/config-panels/V2BomItemEditorConfigPanel.tsx
+++ b/frontend/components/v2/config-panels/V2BomItemEditorConfigPanel.tsx
@@ -34,6 +34,7 @@ import {
Check,
ChevronsUpDown,
GitBranch,
+ Settings,
} from "lucide-react";
import {
Command,
@@ -48,6 +49,12 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
+import { Badge } from "@/components/ui/badge";
+import {
+ Collapsible,
+ CollapsibleContent,
+ CollapsibleTrigger,
+} from "@/components/ui/collapsible";
import { tableTypeApi } from "@/lib/api/screen";
import { tableManagementApi } from "@/lib/api/tableManagement";
import { cn } from "@/lib/utils";
@@ -171,6 +178,9 @@ export function V2BomItemEditorConfigPanel({
const [loadingRelations, setLoadingRelations] = useState(false);
const [tableComboboxOpen, setTableComboboxOpen] = useState(false);
const [expandedColumn, setExpandedColumn] = useState
(null);
+ const [featureOptionsOpen, setFeatureOptionsOpen] = useState(false);
+ const [columnSelectOpen, setColumnSelectOpen] = useState(false);
+ const [selectedColumnsOpen, setSelectedColumnsOpen] = useState(false);
// ─── 업데이트 헬퍼 (리피터 패턴) ───
const updateConfig = useCallback(
@@ -803,145 +813,215 @@ export function V2BomItemEditorConfigPanel({
)}
- {/* 기능 옵션 - Switch + 설명 텍스트 */}
-
-
기능 옵션
-
-
-
-
추가 버튼
-
하위 품목을 추가할 수 있어요
+ {/* 기능 옵션 - Collapsible + Badge */}
+
+
+
+
+
+ 기능 옵션
+
+ {[
+ config.features?.showAddButton ?? true,
+ config.features?.showDeleteButton ?? true,
+ config.features?.inlineEdit ?? false,
+ config.features?.showRowNumber ?? false,
+ ].filter(Boolean).length}
+ 개
+
- updateFeatures("showAddButton", checked)}
+
-
-
-
-
삭제 버튼
-
선택한 품목을 삭제할 수 있어요
+
+
+
+
+
+
+
추가 버튼
+
하위 품목을 추가할 수 있어요
+
+
updateFeatures("showAddButton", checked)}
+ />
-
updateFeatures("showDeleteButton", checked)}
- />
-
-
-
-
인라인 편집
-
셀을 클릭하면 바로 수정할 수 있어요
+
+
+
삭제 버튼
+
선택한 품목을 삭제할 수 있어요
+
+
updateFeatures("showDeleteButton", checked)}
+ />
-
updateFeatures("inlineEdit", checked)}
- />
-
-
-
-
행 번호
-
각 행에 순번을 표시해요
+
+
+
인라인 편집
+
셀을 클릭하면 바로 수정할 수 있어요
+
+
updateFeatures("inlineEdit", checked)}
+ />
+
+
+
+
updateFeatures("showRowNumber", checked)}
+ />
-
updateFeatures("showRowNumber", checked)}
- />
-
-
+
+
{/* ─── 컬럼 설정 탭 ─── */}
- {/* 통합 컬럼 선택 */}
-
-
-
- 어떤 컬럼을 표시하고 입력받을까요?
-
-
- 소스 테이블 컬럼은 표시용, 저장 테이블 컬럼은 입력용이에요
-
-
- {/* 소스 테이블 컬럼 (표시용) */}
- {config.dataSource?.sourceTable && (
- <>
-
-
- 소스 테이블 ({config.dataSource.sourceTable}) - 표시용
+ {/* 컬럼 선택 - Collapsible + Badge */}
+
+
+
+
+
+ 컬럼 선택
+
+ {config.columns.length}개 선택됨
+
- {loadingSourceColumns ? (
+
+
+
+
+
+
+ 소스 테이블 컬럼은 표시용, 저장 테이블 컬럼은 입력용이에요
+
+
+ {/* 소스 테이블 컬럼 (표시용) */}
+ {config.dataSource?.sourceTable && (
+ <>
+
+
+ 소스 테이블 ({config.dataSource.sourceTable}) - 표시용
+
+ {loadingSourceColumns ? (
+
로딩 중...
+ ) : sourceTableColumns.length === 0 ? (
+
컬럼 정보가 없어요
+ ) : (
+
+ {sourceTableColumns.map((column) => (
+
toggleSourceDisplayColumn(column)}
+ >
+ toggleSourceDisplayColumn(column)}
+ className="pointer-events-none h-3.5 w-3.5"
+ />
+
+ {column.displayName}
+ 표시
+
+ ))}
+
+ )}
+ >
+ )}
+
+ {/* 저장 테이블 컬럼 (입력용) */}
+
+
+ 저장 테이블 ({targetTableForColumns || "미선택"}) - 입력용
+
+ {loadingColumns ? (
로딩 중...
- ) : sourceTableColumns.length === 0 ? (
+ ) : inputableColumns.length === 0 ? (
컬럼 정보가 없어요
) : (
-
- {sourceTableColumns.map((column) => (
+
+ {inputableColumns.map((column) => (
toggleSourceDisplayColumn(column)}
+ onClick={() => toggleInputColumn(column)}
>
toggleSourceDisplayColumn(column)}
+ checked={isColumnAdded(column.columnName)}
+ onCheckedChange={() => toggleInputColumn(column)}
className="pointer-events-none h-3.5 w-3.5"
/>
-
+
{column.displayName}
- 표시
+ {column.inputType}
))}
)}
- >
- )}
-
- {/* 저장 테이블 컬럼 (입력용) */}
-
-
- 저장 테이블 ({targetTableForColumns || "미선택"}) - 입력용
-
- {loadingColumns ? (
-
로딩 중...
- ) : inputableColumns.length === 0 ? (
-
컬럼 정보가 없어요
- ) : (
-
- {inputableColumns.map((column) => (
-
toggleInputColumn(column)}
- >
- toggleInputColumn(column)}
- className="pointer-events-none h-3.5 w-3.5"
- />
-
- {column.displayName}
- {column.inputType}
-
- ))}
- )}
-
+
+
- {/* 선택된 컬럼 상세 */}
+ {/* 선택된 컬럼 상세 - Collapsible + Badge */}
{config.columns.length > 0 && (
-
-
- 선택된 컬럼 ({config.columns.length})
- 드래그로 순서 변경
-
-
+
+
+
+
+ 선택된 컬럼
+
+ {config.columns.length}개
+
+
+
+
+
+
+
+
+ 드래그로 순서 변경
+
+
{config.columns.map((col, index) => (
+
+
+
+
)}
diff --git a/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx b/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx
index 17f298d4..a5ef20c5 100644
--- a/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx
+++ b/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx
@@ -22,6 +22,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
+import { Badge } from "@/components/ui/badge";
import {
Database,
Link2,
@@ -163,6 +164,10 @@ export function V2BomTreeConfigPanel({
const [loadingRelations, setLoadingRelations] = useState(false);
const [tableComboboxOpen, setTableComboboxOpen] = useState(false);
const [expandedColumn, setExpandedColumn] = useState
(null);
+ const [displayOptionsOpen, setDisplayOptionsOpen] = useState(false);
+ const [columnSelectOpen, setColumnSelectOpen] = useState(false);
+ const [selectedColumnsOpen, setSelectedColumnsOpen] = useState(false);
+ const [advancedOpen, setAdvancedOpen] = useState(false);
const updateConfig = useCallback(
(updates: Partial) => {
@@ -680,62 +685,103 @@ export function V2BomTreeConfigPanel({
)}
- {/* 표시 옵션 - Switch + 설명 텍스트 */}
-
-
표시 옵션
-
-
-
-
전체 펼치기/접기
-
트리를 한번에 펼치거나 접을 수 있어요
-
-
updateFeatures("showExpandAll", checked)}
- />
-
-
-
-
헤더 정보
-
트리 상단에 요약 정보를 표시해요
-
-
updateFeatures("showHeader", checked)}
- />
-
-
-
-
수량 표시
-
각 노드에 수량 정보를 보여줘요
-
-
updateFeatures("showQuantity", checked)}
- />
-
-
-
-
로스율 표시
-
생산 손실율을 함께 보여줘요
-
-
updateFeatures("showLossRate", checked)}
- />
-
-
-
-
- {/* 고급 설정 (이력/버전 관리) - Collapsible */}
-
+ {/* 표시 옵션 - Collapsible + Badge */}
+
-
+
+
+
+ 표시 옵션
+
+ {[
+ config.features?.showExpandAll ?? true,
+ config.features?.showHeader ?? true,
+ config.features?.showQuantity ?? true,
+ config.features?.showLossRate ?? true,
+ ].filter(Boolean).length}
+ /4
+
+
+
+
+
+
+
+
+
+
전체 펼치기/접기
+
트리를 한번에 펼치거나 접을 수 있어요
+
+
updateFeatures("showExpandAll", checked)}
+ />
+
+
+
+
헤더 정보
+
트리 상단에 요약 정보를 표시해요
+
+
updateFeatures("showHeader", checked)}
+ />
+
+
+
+
수량 표시
+
각 노드에 수량 정보를 보여줘요
+
+
updateFeatures("showQuantity", checked)}
+ />
+
+
+
+
로스율 표시
+
생산 손실율을 함께 보여줘요
+
+
updateFeatures("showLossRate", checked)}
+ />
+
+
+
+
+
+ {/* 고급 설정 (이력/버전 관리) - Collapsible + Badge */}
+
+
+
고급 설정
+
+ 2개
+
-
+
@@ -880,95 +926,134 @@ export function V2BomTreeConfigPanel({
{/* ─── 컬럼 설정 탭 ─── */}
- {/* 통합 컬럼 선택 */}
-
-
-
- 트리에 어떤 컬럼을 표시할까요?
-
-
- 소스 테이블 컬럼은 표시용, 디테일 테이블 컬럼은 직접 컬럼이에요
-
-
- {/* 소스 테이블 컬럼 (표시용) */}
- {config.dataSource?.sourceTable && (
- <>
-
-
- 소스 테이블 ({config.dataSource.sourceTable}) - 표시용
+ {/* 컬럼 선택 - Collapsible + Badge */}
+
+
+
+
+
+ 컬럼 선택
+
+ {config.columns.length}개 선택됨
+
- {loadingSourceColumns ? (
+
+
+
+
+
+
+ 소스 테이블 컬럼은 표시용, 디테일 테이블 컬럼은 직접 컬럼이에요
+
+
+ {/* 소스 테이블 컬럼 (표시용) */}
+ {config.dataSource?.sourceTable && (
+ <>
+
+
+ 소스 테이블 ({config.dataSource.sourceTable}) - 표시용
+
+ {loadingSourceColumns ? (
+
로딩 중...
+ ) : sourceTableColumns.length === 0 ? (
+
컬럼 정보가 없어요
+ ) : (
+
+ {sourceTableColumns.map((column) => (
+
toggleSourceDisplayColumn(column)}
+ >
+ toggleSourceDisplayColumn(column)}
+ className="pointer-events-none h-3.5 w-3.5"
+ />
+
+ {column.displayName}
+ 표시
+
+ ))}
+
+ )}
+ >
+ )}
+
+ {/* 디테일 테이블 컬럼 */}
+
+
+ 디테일 테이블 ({config.detailTable || "미선택"}) - 직접 컬럼
+
+ {loadingColumns ? (
로딩 중...
- ) : sourceTableColumns.length === 0 ? (
+ ) : displayableColumns.length === 0 ? (
컬럼 정보가 없어요
) : (
-
- {sourceTableColumns.map((column) => (
+
+ {displayableColumns.map((column) => (
toggleSourceDisplayColumn(column)}
+ onClick={() => toggleDetailColumn(column)}
>
toggleSourceDisplayColumn(column)}
+ checked={isColumnAdded(column.columnName)}
+ onCheckedChange={() => toggleDetailColumn(column)}
className="pointer-events-none h-3.5 w-3.5"
/>
-
+
{column.displayName}
- 표시
+ {column.inputType}
))}
)}
- >
- )}
-
- {/* 디테일 테이블 컬럼 */}
-
-
- 디테일 테이블 ({config.detailTable || "미선택"}) - 직접 컬럼
-
- {loadingColumns ? (
-
로딩 중...
- ) : displayableColumns.length === 0 ? (
-
컬럼 정보가 없어요
- ) : (
-
- {displayableColumns.map((column) => (
-
toggleDetailColumn(column)}
- >
- toggleDetailColumn(column)}
- className="pointer-events-none h-3.5 w-3.5"
- />
-
- {column.displayName}
- {column.inputType}
-
- ))}
- )}
-
+
+
- {/* 선택된 컬럼 상세 */}
+ {/* 선택된 컬럼 상세 - Collapsible + Badge */}
{config.columns.length > 0 && (
-
-
- 선택된 컬럼 ({config.columns.length})
- 드래그로 순서 변경
-
-
+
+
+
+
+
+ 선택된 컬럼
+
+ {config.columns.length}개
+
+
+
+
+
+
+
+
드래그로 순서 변경
+
{config.columns.map((col, index) => (
+
+
+
+
)}