From 6f311148a55d9eadac8832bcd4af234fe9fcff9c Mon Sep 17 00:00:00 2001 From: DDD1542 Date: Wed, 11 Mar 2026 22:26:52 +0900 Subject: [PATCH] [agent-pipeline] pipe-20260311130333-zqic round-3 --- .../v2/config-panels/V2BomTreeConfigPanel.tsx | 694 +++++++++--------- 1 file changed, 353 insertions(+), 341 deletions(-) diff --git a/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx b/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx index e492a13b..11979eb9 100644 --- a/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx +++ b/frontend/components/v2/config-panels/V2BomTreeConfigPanel.tsx @@ -3,13 +3,12 @@ /** * BOM 트리 뷰 설정 패널 * - * V2BomItemEditorConfigPanel 구조 기반: - * - 기본 탭: 디테일 테이블 + 엔티티 선택 + 트리 설정 + * 토스식 단계별 UX: + * - 기본 탭: 디테일 테이블 → 트리 구조 → 엔티티 → 표시 옵션 → 고급(이력/버전) * - 컬럼 탭: 소스 표시 컬럼 + 디테일 컬럼 + 선택된 컬럼 상세 */ import React, { useState, useEffect, useMemo, useCallback } from "react"; -import { Label } from "@/components/ui/label"; import { Select, SelectContent, @@ -17,11 +16,12 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Separator } from "@/components/ui/separator"; +import { Switch } from "@/components/ui/switch"; import { Checkbox } from "@/components/ui/checkbox"; 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 { Database, Link2, @@ -35,6 +35,7 @@ import { Check, ChevronsUpDown, GitBranch, + Settings, } from "lucide-react"; import { Command, @@ -399,7 +400,6 @@ export function V2BomTreeConfigPanel({ }); }; - // FK/시스템 컬럼 제외한 표시 가능 컬럼 const displayableColumns = useMemo(() => { const fkColumn = config.dataSource?.foreignKey; const systemCols = ["id", "created_at", "updated_at", "created_by", "updated_by", "company_code", "created_date"]; @@ -408,7 +408,6 @@ export function V2BomTreeConfigPanel({ ); }, [detailTableColumns, config.dataSource?.foreignKey]); - // FK 후보 컬럼 const fkCandidateColumns = useMemo(() => { const systemCols = ["created_at", "updated_at", "created_by", "updated_by", "company_code", "created_date"]; return detailTableColumns.filter((c) => !systemCols.includes(c.columnName)); @@ -429,8 +428,11 @@ export function V2BomTreeConfigPanel({ {/* ─── 기본 설정 탭 ─── */} {/* 디테일 테이블 */} -
- +
+
+ + BOM 디테일을 어디에서 가져오나요? +
- 테이블을 찾을 수 없습니다. + 테이블을 찾을 수 없어요. {relatedTables.length > 0 && ( @@ -538,29 +540,38 @@ export function V2BomTreeConfigPanel({ + + {/* 화면 메인 테이블 참고 */} + {currentTableName && ( +
+

화면 메인 테이블

+

{currentTableName}

+

+ 컬럼 {detailTableColumns.length}개 / 엔티티 {entityColumns.length}개 +

+
+ )}
- - {/* 트리 구조 설정 */} -
+
- - + + 트리 구조는 어떻게 만드나요?
-

- 메인 FK와 부모-자식 계층 FK를 선택하세요 +

+ 메인 FK와 부모-자식 계층 FK를 선택하면 트리 구조가 만들어져요

{fkCandidateColumns.length > 0 ? ( -
-
- +
+
+

FK 컬럼 (메인 테이블 참조)

-
- +
+

부모 키 컬럼 (자기 참조 FK)

) : ( -
-

+

+

{loadingColumns - ? "로딩 중..." + ? "컬럼 정보를 불러오고 있어요..." : !config.detailTable - ? "디테일 테이블을 먼저 선택하세요" - : "엔티티 타입 컬럼이 없습니다"} + ? "디테일 테이블을 먼저 선택해주세요" + : "엔티티 타입 컬럼이 없어요"}

)} {config.dataSource?.sourceTable && ( -
-

선택된 엔티티

-
-

참조 테이블: {config.dataSource.sourceTable}

-

FK 컬럼: {config.dataSource.foreignKey}

-
+
+

선택된 엔티티

+

{config.dataSource.sourceTable}

+

+ {config.dataSource.foreignKey} 컬럼에서 참조해요 +

)}
- - - {/* 이력/버전 테이블 설정 */} -
- -

- BOM 변경 이력과 버전 관리에 사용할 테이블을 선택하세요 -

- + {/* 표시 옵션 - Switch + 설명 텍스트 */} +
+ 표시 옵션
-
-
- updateFeatures("showHistory", !!checked)} - /> - +
+
+

전체 펼치기/접기

+

트리를 한번에 펼치거나 접을 수 있어요

- {(config.features?.showHistory ?? true) && ( - - - - - - - - - - 테이블을 찾을 수 없습니다. - - - {allTables.map((table) => ( - updateConfig({ historyTable: table.tableName })} - className="text-xs" - > - - - {table.displayName} - - ))} - - - - - - )} -
- -
-
- updateFeatures("showVersion", !!checked)} - /> - -
- {(config.features?.showVersion ?? true) && ( - - - - - - - - - - 테이블을 찾을 수 없습니다. - - - {allTables.map((table) => ( - updateConfig({ versionTable: table.tableName })} - className="text-xs" - > - - - {table.displayName} - - ))} - - - - - - )} -
-
-
- - - - {/* 표시 옵션 */} -
- -
-
- updateFeatures("showExpandAll", !!checked)} + onCheckedChange={(checked) => updateFeatures("showExpandAll", checked)} /> -
-
- +
+

헤더 정보

+

트리 상단에 요약 정보를 표시해요

+
+ updateFeatures("showHeader", !!checked)} + onCheckedChange={(checked) => updateFeatures("showHeader", checked)} /> -
-
- +
+

수량 표시

+

각 노드에 수량 정보를 보여줘요

+
+ updateFeatures("showQuantity", !!checked)} + onCheckedChange={(checked) => updateFeatures("showQuantity", checked)} /> -
-
- +
+

로스율 표시

+

생산 손실율을 함께 보여줘요

+
+ updateFeatures("showLossRate", !!checked)} + onCheckedChange={(checked) => updateFeatures("showLossRate", checked)} /> -
- {/* 메인 화면 테이블 참고 */} - {currentTableName && ( - <> - -
- -
-

{currentTableName}

-

- 컬럼 {detailTableColumns.length}개 / 엔티티 {entityColumns.length}개 -

+ {/* 고급 설정 (이력/버전 관리) - Collapsible */} + + + + + +
+ {/* 이력 관리 */} +
+
+
+

이력 관리

+

BOM 변경 이력을 추적해요

+
+ updateFeatures("showHistory", checked)} + /> +
+ {(config.features?.showHistory ?? true) && ( +
+

이력 테이블

+ + + + + + + + + + 테이블을 찾을 수 없어요. + + + {allTables.map((table) => ( + updateConfig({ historyTable: table.tableName })} + className="text-xs" + > + + + {table.displayName} + + ))} + + + + + +
+ )} +
+ + {/* 버전 관리 */} +
+
+
+

버전 관리

+

BOM 버전별로 관리해요

+
+ updateFeatures("showVersion", checked)} + /> +
+ {(config.features?.showVersion ?? true) && ( +
+

버전 테이블

+ + + + + + + + + + 테이블을 찾을 수 없어요. + + + {allTables.map((table) => ( + updateConfig({ versionTable: table.tableName })} + className="text-xs" + > + + + {table.displayName} + + ))} + + + + + +
+ )}
- - )} +
+
{/* ─── 컬럼 설정 탭 ─── */} -
- -

- 트리 노드에 표시할 소스/디테일 컬럼을 선택하세요 + {/* 통합 컬럼 선택 */} +

+
+ + 트리에 어떤 컬럼을 표시할까요? +
+

+ 소스 테이블 컬럼은 표시용, 디테일 테이블 컬럼은 직접 컬럼이에요

{/* 소스 테이블 컬럼 (표시용) */} @@ -882,7 +897,7 @@ export function V2BomTreeConfigPanel({ {loadingSourceColumns ? (

로딩 중...

) : sourceTableColumns.length === 0 ? ( -

컬럼 정보가 없습니다

+

컬럼 정보가 없어요

) : (
{sourceTableColumns.map((column) => ( @@ -917,7 +932,7 @@ export function V2BomTreeConfigPanel({ {loadingColumns ? (

로딩 중...

) : displayableColumns.length === 0 ? ( -

컬럼 정보가 없습니다

+

컬럼 정보가 없어요

) : (
{displayableColumns.map((column) => ( @@ -945,123 +960,120 @@ export function V2BomTreeConfigPanel({ {/* 선택된 컬럼 상세 */} {config.columns.length > 0 && ( - <> - -
- -
- {config.columns.map((col, index) => ( -
-
e.dataTransfer.setData("columnIndex", String(index))} - onDragOver={(e) => e.preventDefault()} - onDrop={(e) => { - e.preventDefault(); - const fromIndex = parseInt(e.dataTransfer.getData("columnIndex"), 10); - if (fromIndex !== index) { - const newColumns = [...config.columns]; - const [movedCol] = newColumns.splice(fromIndex, 1); - newColumns.splice(index, 0, movedCol); - updateConfig({ columns: newColumns }); +
+
+ 선택된 컬럼 ({config.columns.length}) + 드래그로 순서 변경 +
+
+ {config.columns.map((col, index) => ( +
+
e.dataTransfer.setData("columnIndex", String(index))} + onDragOver={(e) => e.preventDefault()} + onDrop={(e) => { + e.preventDefault(); + const fromIndex = parseInt(e.dataTransfer.getData("columnIndex"), 10); + if (fromIndex !== index) { + const newColumns = [...config.columns]; + const [movedCol] = newColumns.splice(fromIndex, 1); + newColumns.splice(index, 0, movedCol); + updateConfig({ columns: newColumns }); + } + }} + > + + + {!col.isSourceDisplay && ( + + )} + + {col.isSourceDisplay ? ( + + ) : ( + + )} + + updateColumnProp(col.key, "title", e.target.value)} + placeholder="제목" + className="h-6 flex-1 text-xs" + /> + + {!col.isSourceDisplay && ( + + )} + + - )} - - {col.isSourceDisplay ? ( - - ) : ( - - )} - - updateColumnProp(col.key, "title", e.target.value)} - placeholder="제목" - className="h-6 flex-1 text-xs" - /> - - {!col.isSourceDisplay && ( - - )} - - -
- - {/* 확장 상세 */} - {!col.isSourceDisplay && expandedColumn === col.key && ( -
-
- - updateColumnProp(col.key, "width", e.target.value)} - placeholder="auto, 100px, 20%" - className="h-6 text-xs" - /> -
-
- )} + +
- ))} -
+ + {/* 확장 상세 */} + {!col.isSourceDisplay && expandedColumn === col.key && ( +
+
+

컬럼 너비

+ updateColumnProp(col.key, "width", e.target.value)} + placeholder="auto, 100px, 20%" + className="h-6 text-xs" + /> +
+
+ )} +
+ ))}
- +
)}