[agent-pipeline] pipe-20260311130333-zqic round-2

This commit is contained in:
DDD1542 2026-03-11 22:20:59 +09:00
parent ae852ed4ad
commit d2c8f5f8f5
1 changed files with 254 additions and 264 deletions

View File

@ -3,13 +3,12 @@
/** /**
* BOM * BOM
* *
* V2RepeaterConfigPanel : * UX:
* - : 저장 + + + * - : 저장 ()
* - : 소스 + + * - : 소스 + +
*/ */
import React, { useState, useEffect, useMemo, useCallback } from "react"; import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Label } from "@/components/ui/label";
import { import {
Select, Select,
SelectContent, SelectContent,
@ -17,7 +16,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Separator } from "@/components/ui/separator"; import { Switch } from "@/components/ui/switch";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
@ -102,27 +101,18 @@ interface BomColumnConfig {
} }
interface BomItemEditorConfig { interface BomItemEditorConfig {
// 저장 테이블 설정 (리피터 패턴)
useCustomTable?: boolean; useCustomTable?: boolean;
mainTableName?: string; mainTableName?: string;
foreignKeyColumn?: string; foreignKeyColumn?: string;
foreignKeySourceColumn?: string; foreignKeySourceColumn?: string;
// 트리 구조 설정
parentKeyColumn?: string; parentKeyColumn?: string;
// 엔티티 (품목 참조) 설정
dataSource?: { dataSource?: {
sourceTable?: string; sourceTable?: string;
foreignKey?: string; foreignKey?: string;
referenceKey?: string; referenceKey?: string;
displayColumn?: string; displayColumn?: string;
}; };
// 컬럼 설정
columns: BomColumnConfig[]; columns: BomColumnConfig[];
// 기능 옵션
features?: { features?: {
showAddButton?: boolean; showAddButton?: boolean;
showDeleteButton?: boolean; showDeleteButton?: boolean;
@ -472,7 +462,6 @@ export function V2BomItemEditorConfigPanel({
}); });
}; };
// FK 컬럼 제외한 입력 가능 컬럼
const inputableColumns = useMemo(() => { const inputableColumns = useMemo(() => {
const fkColumn = config.dataSource?.foreignKey; const fkColumn = config.dataSource?.foreignKey;
return currentTableColumns.filter( return currentTableColumns.filter(
@ -495,9 +484,12 @@ export function V2BomItemEditorConfigPanel({
{/* ─── 기본 설정 탭 ─── */} {/* ─── 기본 설정 탭 ─── */}
<TabsContent value="basic" className="mt-4 space-y-4"> <TabsContent value="basic" className="mt-4 space-y-4">
{/* 저장 대상 테이블 (리피터 동일) */} {/* 저장 대상 테이블 */}
<div className="space-y-2"> <div className="rounded-lg border bg-muted/30 p-4 space-y-3">
<Label className="text-xs font-medium"> </Label> <div className="flex items-center gap-2">
<Database className="h-4 w-4 text-primary" />
<span className="text-sm font-medium">BOM ?</span>
</div>
<div <div
className={cn( className={cn(
@ -539,7 +531,7 @@ export function V2BomItemEditorConfigPanel({
</div> </div>
</div> </div>
{/* 테이블 Combobox (리피터 동일) */} {/* 테이블 Combobox */}
<Popover open={tableComboboxOpen} onOpenChange={setTableComboboxOpen}> <Popover open={tableComboboxOpen} onOpenChange={setTableComboboxOpen}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button <Button
@ -651,19 +643,18 @@ export function V2BomItemEditorConfigPanel({
</PopoverContent> </PopoverContent>
</Popover> </Popover>
{/* FK 직접 입력 (연관 없는 테이블 선택 시) */} {/* FK 직접 입력 */}
{config.useCustomTable && {config.useCustomTable &&
config.mainTableName && config.mainTableName &&
currentTableName && currentTableName &&
!relatedTables.some((r) => r.tableName === config.mainTableName) && ( !relatedTables.some((r) => r.tableName === config.mainTableName) && (
<div className="space-y-2 rounded border border-amber-200 bg-amber-50 p-2"> <div className="space-y-2 rounded border border-amber-200 bg-amber-50 p-2">
<p className="text-[10px] text-amber-700"> <p className="text-[10px] text-amber-700">
({currentTableName}) . FK ({currentTableName}) . FK .
.
</p> </p>
<div className="grid grid-cols-2 gap-2"> <div className="grid grid-cols-2 gap-2">
<div className="space-y-1"> <div className="space-y-1">
<Label className="text-[10px]">FK ( )</Label> <p className="text-xs text-muted-foreground">FK ( )</p>
<Input <Input
value={config.foreignKeyColumn || ""} value={config.foreignKeyColumn || ""}
onChange={(e) => updateConfig({ foreignKeyColumn: e.target.value })} onChange={(e) => updateConfig({ foreignKeyColumn: e.target.value })}
@ -672,7 +663,7 @@ export function V2BomItemEditorConfigPanel({
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<Label className="text-[10px]">PK ( )</Label> <p className="text-xs text-muted-foreground">PK ( )</p>
<Input <Input
value={config.foreignKeySourceColumn || "id"} value={config.foreignKeySourceColumn || "id"}
onChange={(e) => updateConfig({ foreignKeySourceColumn: e.target.value })} onChange={(e) => updateConfig({ foreignKeySourceColumn: e.target.value })}
@ -683,72 +674,85 @@ export function V2BomItemEditorConfigPanel({
</div> </div>
</div> </div>
)} )}
{/* 화면 메인 테이블 참고 정보 */}
{currentTableName && (
<div className="rounded-md border bg-background p-3">
<p className="text-xs text-muted-foreground"> </p>
<p className="mt-0.5 text-sm font-medium">{currentTableName}</p>
<p className="text-[10px] text-muted-foreground mt-0.5">
{currentTableColumns.length} / {entityColumns.length}
</p>
</div>
)}
</div> </div>
<Separator />
{/* 트리 구조 설정 (BOM 전용) */} {/* 트리 구조 설정 (BOM 전용) */}
<div className="space-y-2"> <div className="rounded-lg border bg-muted/30 p-4 space-y-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<GitBranch className="h-4 w-4" /> <GitBranch className="h-4 w-4 text-primary" />
<Label className="text-xs font-medium"> </Label> <span className="text-sm font-medium"> ?</span>
</div> </div>
<p className="text-muted-foreground text-[10px]"> <p className="text-[11px] text-muted-foreground">
FK FK -
</p> </p>
{currentTableColumns.length > 0 ? ( {currentTableColumns.length > 0 ? (
<Select <div>
value={config.parentKeyColumn || ""} <p className="mb-1.5 text-xs text-muted-foreground"> </p>
onValueChange={(value) => updateConfig({ parentKeyColumn: value })} <Select
> value={config.parentKeyColumn || ""}
<SelectTrigger className="h-8 text-xs"> onValueChange={(value) => updateConfig({ parentKeyColumn: value })}
<SelectValue placeholder="부모 키 컬럼 선택" /> >
</SelectTrigger> <SelectTrigger className="h-8 text-sm">
<SelectContent> <SelectValue placeholder="컬럼 선택" />
{currentTableColumns.map((col) => ( </SelectTrigger>
<SelectItem key={col.columnName} value={col.columnName}> <SelectContent>
<div className="flex items-center gap-2"> {currentTableColumns.map((col) => (
<span>{col.displayName}</span> <SelectItem key={col.columnName} value={col.columnName}>
{col.displayName !== col.columnName && ( <div className="flex items-center gap-2">
<span className="text-muted-foreground text-[10px]"> <span>{col.displayName}</span>
({col.columnName}) {col.displayName !== col.columnName && (
</span> <span className="text-muted-foreground text-[10px]">
)} ({col.columnName})
</div> </span>
</SelectItem> )}
))} </div>
</SelectContent> </SelectItem>
</Select> ))}
</SelectContent>
</Select>
</div>
) : ( ) : (
<div className="rounded border border-border bg-muted p-2"> <div className="rounded-md border-2 border-dashed p-4 text-center">
<p className="text-[10px] text-muted-foreground"> <GitBranch className="mx-auto mb-2 h-8 w-8 opacity-30 text-muted-foreground" />
{loadingColumns ? "로딩 중..." : "저장 테이블을 먼저 선택하세요"} <p className="text-sm text-muted-foreground">
{loadingColumns ? "컬럼 정보를 불러오고 있어요..." : "저장 테이블을 먼저 선택해주세요"}
</p> </p>
</div> </div>
)} )}
{/* 최대 깊이 */} <div className="flex items-center justify-between py-1">
<div className="space-y-1"> <span className="text-xs text-muted-foreground"> </span>
<Label className="text-[10px]"> </Label>
<Input <Input
type="number" type="number"
min={1} min={1}
max={10} max={10}
value={config.features?.maxDepth ?? 3} value={config.features?.maxDepth ?? 3}
onChange={(e) => updateFeatures("maxDepth", parseInt(e.target.value) || 3)} onChange={(e) => updateFeatures("maxDepth", parseInt(e.target.value) || 3)}
className="h-7 w-20 text-xs" className="h-7 w-[80px] text-xs"
/> />
</div> </div>
</div> </div>
<Separator /> {/* 엔티티 선택 (품목 참조) */}
<div className="rounded-lg border bg-muted/30 p-4 space-y-3">
{/* 엔티티 선택 (리피터 모달 모드와 동일) */} <div className="flex items-center gap-2">
<div className="space-y-2"> <Link2 className="h-4 w-4 text-primary" />
<Label className="text-xs font-medium"> ( )</Label> <span className="text-sm font-medium"> ?</span>
<p className="text-muted-foreground text-[10px]"> </div>
(FK만 ) <p className="text-[11px] text-muted-foreground">
FK만
</p> </p>
{entityColumns.length > 0 ? ( {entityColumns.length > 0 ? (
@ -757,7 +761,7 @@ export function V2BomItemEditorConfigPanel({
onValueChange={handleEntityColumnSelect} onValueChange={handleEntityColumnSelect}
disabled={!targetTableForColumns} disabled={!targetTableForColumns}
> >
<SelectTrigger className="h-8 text-xs"> <SelectTrigger className="h-8 text-sm">
<SelectValue placeholder="엔티티 컬럼 선택" /> <SelectValue placeholder="엔티티 컬럼 선택" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@ -774,100 +778,86 @@ export function V2BomItemEditorConfigPanel({
</SelectContent> </SelectContent>
</Select> </Select>
) : ( ) : (
<div className="rounded border border-border bg-muted p-2"> <div className="rounded-md border-2 border-dashed p-4 text-center">
<p className="text-[10px] text-muted-foreground"> <p className="text-sm text-muted-foreground">
{loadingColumns {loadingColumns
? "로딩 중..." ? "컬럼 정보를 불러오고 있어요..."
: !targetTableForColumns : !targetTableForColumns
? "저장 테이블을 먼저 선택세요" ? "저장 테이블을 먼저 선택해주세요"
: "엔티티 타입 컬럼이 없습니다"} : "엔티티 타입 컬럼이 없어요"}
</p> </p>
</div> </div>
)} )}
{config.dataSource?.sourceTable && ( {config.dataSource?.sourceTable && (
<div className="space-y-1 rounded border border-emerald-200 bg-emerald-50 p-2"> <div className="rounded-md border bg-background p-3 space-y-1">
<p className="text-xs font-medium text-emerald-700"> </p> <p className="text-xs text-muted-foreground"> </p>
<div className="text-[10px] text-emerald-600"> <p className="text-sm font-medium">{config.dataSource.sourceTable}</p>
<p> : {config.dataSource.sourceTable}</p> <p className="text-[11px] text-muted-foreground">
<p> : {config.dataSource.foreignKey} (FK)</p> {config.dataSource.foreignKey} FK로
</div> </p>
</div> </div>
)} )}
</div> </div>
<Separator /> {/* 기능 옵션 - Switch + 설명 텍스트 */}
<div className="rounded-lg border bg-muted/30 p-4 space-y-1">
{/* 기능 옵션 */} <span className="text-sm font-medium"> </span>
<div className="space-y-3"> <div className="space-y-2">
<Label className="text-xs font-medium"> </Label> <div className="flex items-center justify-between py-1">
<div className="grid grid-cols-2 gap-2"> <div>
<div className="flex items-center space-x-2"> <p className="text-sm"> </p>
<Checkbox <p className="text-[11px] text-muted-foreground"> </p>
id="bom-showAddButton" </div>
<Switch
checked={config.features?.showAddButton ?? true} checked={config.features?.showAddButton ?? true}
onCheckedChange={(checked) => updateFeatures("showAddButton", !!checked)} onCheckedChange={(checked) => updateFeatures("showAddButton", checked)}
/> />
<label htmlFor="bom-showAddButton" className="text-xs">
</label>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center justify-between py-1">
<Checkbox <div>
id="bom-showDeleteButton" <p className="text-sm"> </p>
<p className="text-[11px] text-muted-foreground"> </p>
</div>
<Switch
checked={config.features?.showDeleteButton ?? true} checked={config.features?.showDeleteButton ?? true}
onCheckedChange={(checked) => updateFeatures("showDeleteButton", !!checked)} onCheckedChange={(checked) => updateFeatures("showDeleteButton", checked)}
/> />
<label htmlFor="bom-showDeleteButton" className="text-xs">
</label>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center justify-between py-1">
<Checkbox <div>
id="bom-inlineEdit" <p className="text-sm"> </p>
<p className="text-[11px] text-muted-foreground"> </p>
</div>
<Switch
checked={config.features?.inlineEdit ?? false} checked={config.features?.inlineEdit ?? false}
onCheckedChange={(checked) => updateFeatures("inlineEdit", !!checked)} onCheckedChange={(checked) => updateFeatures("inlineEdit", checked)}
/> />
<label htmlFor="bom-inlineEdit" className="text-xs">
</label>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center justify-between py-1">
<Checkbox <div>
id="bom-showRowNumber" <p className="text-sm"> </p>
<p className="text-[11px] text-muted-foreground"> </p>
</div>
<Switch
checked={config.features?.showRowNumber ?? false} checked={config.features?.showRowNumber ?? false}
onCheckedChange={(checked) => updateFeatures("showRowNumber", !!checked)} onCheckedChange={(checked) => updateFeatures("showRowNumber", checked)}
/> />
<label htmlFor="bom-showRowNumber" className="text-xs">
</label>
</div> </div>
</div> </div>
</div> </div>
{/* 메인 화면 테이블 참고 */}
{currentTableName && (
<>
<Separator />
<div className="space-y-2">
<Label className="text-xs font-medium"> ()</Label>
<div className="rounded border border-border bg-muted p-2">
<p className="text-xs font-medium text-foreground">{currentTableName}</p>
<p className="text-[10px] text-muted-foreground">
{currentTableColumns.length} / {entityColumns.length}
</p>
</div>
</div>
</>
)}
</TabsContent> </TabsContent>
{/* ─── 컬럼 설정 탭 (리피터 동일 패턴) ─── */} {/* ─── 컬럼 설정 탭 ─── */}
<TabsContent value="columns" className="mt-4 space-y-4"> <TabsContent value="columns" className="mt-4 space-y-4">
<div className="space-y-2"> {/* 통합 컬럼 선택 */}
<Label className="text-xs font-medium"> </Label> <div className="rounded-lg border bg-muted/30 p-4 space-y-3">
<p className="text-muted-foreground text-[10px]"> <div className="flex items-center gap-2">
<Database className="h-4 w-4 text-primary" />
<span className="text-sm font-medium"> ?</span>
</div>
<p className="text-[11px] text-muted-foreground">
,
</p> </p>
{/* 소스 테이블 컬럼 (표시용) */} {/* 소스 테이블 컬럼 (표시용) */}
@ -880,7 +870,7 @@ export function V2BomItemEditorConfigPanel({
{loadingSourceColumns ? ( {loadingSourceColumns ? (
<p className="text-muted-foreground py-2 text-xs"> ...</p> <p className="text-muted-foreground py-2 text-xs"> ...</p>
) : sourceTableColumns.length === 0 ? ( ) : sourceTableColumns.length === 0 ? (
<p className="text-muted-foreground py-2 text-xs"> </p> <p className="text-muted-foreground py-2 text-xs"> </p>
) : ( ) : (
<div className="max-h-28 space-y-0.5 overflow-y-auto rounded-md border border-primary/20 bg-primary/10/30 p-2"> <div className="max-h-28 space-y-0.5 overflow-y-auto rounded-md border border-primary/20 bg-primary/10/30 p-2">
{sourceTableColumns.map((column) => ( {sourceTableColumns.map((column) => (
@ -915,7 +905,7 @@ export function V2BomItemEditorConfigPanel({
{loadingColumns ? ( {loadingColumns ? (
<p className="text-muted-foreground py-2 text-xs"> ...</p> <p className="text-muted-foreground py-2 text-xs"> ...</p>
) : inputableColumns.length === 0 ? ( ) : inputableColumns.length === 0 ? (
<p className="text-muted-foreground py-2 text-xs"> </p> <p className="text-muted-foreground py-2 text-xs"> </p>
) : ( ) : (
<div className="max-h-36 space-y-0.5 overflow-y-auto rounded-md border p-2"> <div className="max-h-36 space-y-0.5 overflow-y-auto rounded-md border p-2">
{inputableColumns.map((column) => ( {inputableColumns.map((column) => (
@ -941,141 +931,141 @@ export function V2BomItemEditorConfigPanel({
)} )}
</div> </div>
{/* 선택된 컬럼 상세 (리피터 동일 패턴) */} {/* 선택된 컬럼 상세 */}
{config.columns.length > 0 && ( {config.columns.length > 0 && (
<> <div className="rounded-lg border bg-muted/30 p-4 space-y-3">
<Separator /> <div className="flex items-center justify-between">
<div className="space-y-2"> <span className="text-sm font-medium"> ({config.columns.length})</span>
<Label className="text-xs font-medium"> <span className="text-[11px] text-muted-foreground"> </span>
({config.columns.length}) </div>
<span className="text-muted-foreground ml-2 font-normal"> </span> <div className="max-h-48 space-y-1 overflow-y-auto">
</Label> {config.columns.map((col, index) => (
<div className="max-h-48 space-y-1 overflow-y-auto"> <div key={col.key} className="space-y-1">
{config.columns.map((col, index) => ( <div
<div key={col.key} className="space-y-1"> className={cn(
<div "flex items-center gap-2 rounded-md border p-2",
className={cn( col.isSourceDisplay
"flex items-center gap-2 rounded-md border p-2", ? "border-primary/20 bg-primary/10/50"
col.isSourceDisplay : "border-border bg-muted/30",
? "border-primary/20 bg-primary/10/50" col.hidden && "opacity-50",
: "border-border bg-muted/30", )}
col.hidden && "opacity-50", draggable
)} onDragStart={(e) => e.dataTransfer.setData("columnIndex", String(index))}
draggable onDragOver={(e) => e.preventDefault()}
onDragStart={(e) => e.dataTransfer.setData("columnIndex", String(index))} onDrop={(e) => {
onDragOver={(e) => e.preventDefault()} e.preventDefault();
onDrop={(e) => { const fromIndex = parseInt(e.dataTransfer.getData("columnIndex"), 10);
e.preventDefault(); if (fromIndex !== index) {
const fromIndex = parseInt(e.dataTransfer.getData("columnIndex"), 10); const newColumns = [...config.columns];
if (fromIndex !== index) { const [movedCol] = newColumns.splice(fromIndex, 1);
const newColumns = [...config.columns]; newColumns.splice(index, 0, movedCol);
const [movedCol] = newColumns.splice(fromIndex, 1); updateConfig({ columns: newColumns });
newColumns.splice(index, 0, movedCol); }
updateConfig({ columns: newColumns }); }}
>
<GripVertical className="text-muted-foreground h-3 w-3 cursor-grab flex-shrink-0" />
{!col.isSourceDisplay && (
<button
type="button"
onClick={() =>
setExpandedColumn(expandedColumn === col.key ? null : col.key)
}
className="rounded p-0.5 hover:bg-muted/80"
>
{expandedColumn === col.key ? (
<ChevronDown className="h-3 w-3 text-muted-foreground" />
) : (
<ChevronRight className="h-3 w-3 text-muted-foreground" />
)}
</button>
)}
{col.isSourceDisplay ? (
<Link2 className="h-3 w-3 flex-shrink-0 text-primary" />
) : (
<Database className="text-muted-foreground h-3 w-3 flex-shrink-0" />
)}
<Input
value={col.title}
onChange={(e) => updateColumnProp(col.key, "title", e.target.value)}
placeholder="제목"
className="h-6 flex-1 text-xs"
/>
{!col.isSourceDisplay && (
<button
type="button"
onClick={() => updateColumnProp(col.key, "hidden", !col.hidden)}
className={cn(
"rounded p-1 hover:bg-muted/80",
col.hidden ? "text-muted-foreground/70" : "text-muted-foreground",
)}
title={col.hidden ? "히든 (저장만 됨)" : "표시됨"}
>
{col.hidden ? (
<EyeOff className="h-3 w-3" />
) : (
<Eye className="h-3 w-3" />
)}
</button>
)}
{!col.isSourceDisplay && (
<button
type="button"
onClick={() => updateColumnProp(col.key, "editable", !(col.editable ?? true))}
className={cn(
"shrink-0 rounded px-1.5 py-0.5 text-[9px] font-medium transition-colors",
(col.editable ?? true)
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400"
: "bg-muted text-muted-foreground dark:bg-foreground/90 dark:text-muted-foreground/70"
)}
title={(col.editable ?? true) ? "편집 가능" : "읽기 전용"}
>
{(col.editable ?? true) ? "편집" : "읽기"}
</button>
)}
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => {
if (col.isSourceDisplay) {
toggleSourceDisplayColumn({
columnName: col.key,
displayName: col.title,
});
} else {
toggleInputColumn({ columnName: col.key, displayName: col.title });
} }
}} }}
className="text-destructive h-6 w-6 p-0"
> >
<GripVertical className="text-muted-foreground h-3 w-3 cursor-grab flex-shrink-0" /> <Trash2 className="h-3 w-3" />
</Button>
{!col.isSourceDisplay && (
<button
type="button"
onClick={() =>
setExpandedColumn(expandedColumn === col.key ? null : col.key)
}
className="rounded p-0.5 hover:bg-muted/80"
>
{expandedColumn === col.key ? (
<ChevronDown className="h-3 w-3 text-muted-foreground" />
) : (
<ChevronRight className="h-3 w-3 text-muted-foreground" />
)}
</button>
)}
{col.isSourceDisplay ? (
<Link2
className="h-3 w-3 flex-shrink-0 text-primary"
title="소스 표시 (읽기 전용)"
/>
) : (
<Database className="text-muted-foreground h-3 w-3 flex-shrink-0" />
)}
<Input
value={col.title}
onChange={(e) => updateColumnProp(col.key, "title", e.target.value)}
placeholder="제목"
className="h-6 flex-1 text-xs"
/>
{!col.isSourceDisplay && (
<button
type="button"
onClick={() => updateColumnProp(col.key, "hidden", !col.hidden)}
className={cn(
"rounded p-1 hover:bg-muted/80",
col.hidden ? "text-muted-foreground/70" : "text-muted-foreground",
)}
title={col.hidden ? "히든 (저장만 됨)" : "표시됨"}
>
{col.hidden ? (
<EyeOff className="h-3 w-3" />
) : (
<Eye className="h-3 w-3" />
)}
</button>
)}
{!col.isSourceDisplay && (
<Checkbox
checked={col.editable ?? true}
onCheckedChange={(checked) =>
updateColumnProp(col.key, "editable", !!checked)
}
title="편집 가능"
/>
)}
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => {
if (col.isSourceDisplay) {
toggleSourceDisplayColumn({
columnName: col.key,
displayName: col.title,
});
} else {
toggleInputColumn({ columnName: col.key, displayName: col.title });
}
}}
className="text-destructive h-6 w-6 p-0"
>
<Trash2 className="h-3 w-3" />
</Button>
</div>
{/* 확장 상세 */}
{!col.isSourceDisplay && expandedColumn === col.key && (
<div className="ml-6 space-y-2 rounded-md border border-dashed border-input bg-muted p-2">
<div className="space-y-1">
<Label className="text-[10px] text-muted-foreground"> </Label>
<Input
value={col.width || "auto"}
onChange={(e) => updateColumnProp(col.key, "width", e.target.value)}
placeholder="auto, 100px, 20%"
className="h-6 text-xs"
/>
</div>
</div>
)}
</div> </div>
))}
</div> {/* 확장 상세 */}
{!col.isSourceDisplay && expandedColumn === col.key && (
<div className="ml-6 space-y-2 rounded-md border border-dashed border-input bg-muted p-2">
<div className="space-y-1">
<p className="text-[10px] text-muted-foreground"> </p>
<Input
value={col.width || "auto"}
onChange={(e) => updateColumnProp(col.key, "width", e.target.value)}
placeholder="auto, 100px, 20%"
className="h-6 text-xs"
/>
</div>
</div>
)}
</div>
))}
</div> </div>
</> </div>
)} )}
</TabsContent> </TabsContent>
</Tabs> </Tabs>