분할패널 테이블 리스트 구현
This commit is contained in:
@@ -353,6 +353,32 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>표시 모드</Label>
|
||||
<Select
|
||||
value={config.leftPanel?.displayMode || "list"}
|
||||
onValueChange={(value: "list" | "table") => updateLeftPanel({ displayMode: value })}
|
||||
>
|
||||
<SelectTrigger className="bg-white">
|
||||
<SelectValue placeholder="표시 모드 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="list">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">목록 (LIST)</span>
|
||||
<span className="text-xs text-gray-500">클릭 가능한 항목 목록 (기본)</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="table">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">테이블 (TABLE)</span>
|
||||
<span className="text-xs text-gray-500">컬럼 헤더가 있는 테이블 형식</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>검색 기능</Label>
|
||||
<Switch
|
||||
@@ -670,6 +696,185 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 좌측 패널 표시 컬럼 설정 */}
|
||||
<div className="space-y-3 rounded-lg border border-green-200 bg-green-50 p-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm font-semibold">표시할 컬럼 선택</Label>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
const currentColumns = config.leftPanel?.columns || [];
|
||||
const newColumns = [
|
||||
...currentColumns,
|
||||
{ name: "", label: "", width: 100 },
|
||||
];
|
||||
updateLeftPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-7 text-xs"
|
||||
disabled={!config.leftPanel?.tableName && !screenTableName}
|
||||
>
|
||||
<Plus className="mr-1 h-3 w-3" />
|
||||
컬럼 추가
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-600">
|
||||
좌측 패널에 표시할 컬럼을 선택하세요. 선택하지 않으면 모든 컬럼이 표시됩니다.
|
||||
</p>
|
||||
|
||||
{/* 선택된 컬럼 목록 */}
|
||||
<div className="space-y-2">
|
||||
{(config.leftPanel?.columns || []).length === 0 ? (
|
||||
<div className="rounded-md border border-dashed border-gray-300 bg-white p-3 text-center">
|
||||
<p className="text-xs text-gray-500">설정된 컬럼이 없습니다</p>
|
||||
<p className="mt-1 text-[10px] text-gray-400">
|
||||
컬럼을 추가하지 않으면 모든 컬럼이 표시됩니다
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
(config.leftPanel?.columns || []).map((col, index) => {
|
||||
const isTableMode = config.leftPanel?.displayMode === "table";
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="space-y-2 rounded-md border bg-white p-2"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
className="h-8 w-full justify-between text-xs"
|
||||
>
|
||||
{col.name || "컬럼 선택"}
|
||||
<ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="컬럼 검색..." className="text-xs" />
|
||||
<CommandEmpty className="text-xs">컬럼을 찾을 수 없습니다.</CommandEmpty>
|
||||
<CommandGroup className="max-h-[200px] overflow-auto">
|
||||
{leftTableColumns.map((column) => (
|
||||
<CommandItem
|
||||
key={column.columnName}
|
||||
value={column.columnName}
|
||||
onSelect={(value) => {
|
||||
const newColumns = [...(config.leftPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
name: value,
|
||||
label: column.columnLabel || value,
|
||||
};
|
||||
updateLeftPanel({ columns: newColumns });
|
||||
}}
|
||||
className="text-xs"
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-3 w-3",
|
||||
col.name === column.columnName ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{column.columnLabel || column.columnName}
|
||||
<span className="ml-2 text-[10px] text-gray-500">
|
||||
({column.columnName})
|
||||
</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
const newColumns = (config.leftPanel?.columns || []).filter(
|
||||
(_, i) => i !== index
|
||||
);
|
||||
updateLeftPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 테이블 모드 전용 옵션 */}
|
||||
{isTableMode && (
|
||||
<div className="grid grid-cols-3 gap-2 pt-1">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-[10px] text-gray-600">너비 (px)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min="50"
|
||||
value={col.width || 100}
|
||||
onChange={(e) => {
|
||||
const newColumns = [...(config.leftPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
width: parseInt(e.target.value) || 100,
|
||||
};
|
||||
updateLeftPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-7 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-[10px] text-gray-600">정렬</Label>
|
||||
<Select
|
||||
value={col.align || "left"}
|
||||
onValueChange={(value: "left" | "center" | "right") => {
|
||||
const newColumns = [...(config.leftPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
align: value,
|
||||
};
|
||||
updateLeftPanel({ columns: newColumns });
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-7 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="left">왼쪽</SelectItem>
|
||||
<SelectItem value="center">가운데</SelectItem>
|
||||
<SelectItem value="right">오른쪽</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
<label className="flex h-7 items-center gap-1 text-[10px] cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={col.sortable ?? false}
|
||||
onChange={(e) => {
|
||||
const newColumns = [...(config.leftPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
sortable: e.target.checked,
|
||||
};
|
||||
updateLeftPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-3 w-3"
|
||||
/>
|
||||
정렬가능
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 좌측 패널 추가 모달 컬럼 설정 */}
|
||||
{config.leftPanel?.showAdd && (
|
||||
<div className="space-y-3 rounded-lg border border-purple-200 bg-purple-50 p-3">
|
||||
@@ -895,6 +1100,32 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>표시 모드</Label>
|
||||
<Select
|
||||
value={config.rightPanel?.displayMode || "list"}
|
||||
onValueChange={(value: "list" | "table") => updateRightPanel({ displayMode: value })}
|
||||
>
|
||||
<SelectTrigger className="bg-white">
|
||||
<SelectValue placeholder="표시 모드 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="list">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">목록 (LIST)</span>
|
||||
<span className="text-xs text-gray-500">클릭 가능한 항목 목록 (기본)</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="table">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">테이블 (TABLE)</span>
|
||||
<span className="text-xs text-gray-500">컬럼 헤더가 있는 테이블 형식</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* 컬럼 매핑 - 조인 모드에서만 표시 */}
|
||||
{relationshipType !== "detail" && (
|
||||
<div className="space-y-3 rounded-lg border border-gray-200 bg-gray-50 p-3">
|
||||
@@ -1057,75 +1288,145 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
(config.rightPanel?.columns || []).map((col, index) => (
|
||||
(config.rightPanel?.columns || []).map((col, index) => {
|
||||
const isTableMode = config.rightPanel?.displayMode === "table";
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-2 rounded-md border bg-white p-2"
|
||||
className="space-y-2 rounded-md border bg-white p-2"
|
||||
>
|
||||
<div className="flex-1">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
className="h-8 w-full justify-between text-xs"
|
||||
>
|
||||
{col.name || "컬럼 선택"}
|
||||
<ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="컬럼 검색..." className="text-xs" />
|
||||
<CommandEmpty className="text-xs">컬럼을 찾을 수 없습니다.</CommandEmpty>
|
||||
<CommandGroup className="max-h-[200px] overflow-auto">
|
||||
{rightTableColumns.map((column) => (
|
||||
<CommandItem
|
||||
key={column.columnName}
|
||||
value={column.columnName}
|
||||
onSelect={(value) => {
|
||||
const newColumns = [...(config.rightPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
name: value,
|
||||
label: column.columnLabel || value,
|
||||
};
|
||||
updateRightPanel({ columns: newColumns });
|
||||
}}
|
||||
className="text-xs"
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-3 w-3",
|
||||
col.name === column.columnName ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{column.columnLabel || column.columnName}
|
||||
<span className="ml-2 text-[10px] text-gray-500">
|
||||
({column.columnName})
|
||||
</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
className="h-8 w-full justify-between text-xs"
|
||||
>
|
||||
{col.name || "컬럼 선택"}
|
||||
<ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="컬럼 검색..." className="text-xs" />
|
||||
<CommandEmpty className="text-xs">컬럼을 찾을 수 없습니다.</CommandEmpty>
|
||||
<CommandGroup className="max-h-[200px] overflow-auto">
|
||||
{rightTableColumns.map((column) => (
|
||||
<CommandItem
|
||||
key={column.columnName}
|
||||
value={column.columnName}
|
||||
onSelect={(value) => {
|
||||
const newColumns = [...(config.rightPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
name: value,
|
||||
label: column.columnLabel || value,
|
||||
};
|
||||
updateRightPanel({ columns: newColumns });
|
||||
}}
|
||||
className="text-xs"
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-3 w-3",
|
||||
col.name === column.columnName ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{column.columnLabel || column.columnName}
|
||||
<span className="ml-2 text-[10px] text-gray-500">
|
||||
({column.columnName})
|
||||
</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
const newColumns = (config.rightPanel?.columns || []).filter(
|
||||
(_, i) => i !== index
|
||||
);
|
||||
updateRightPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
const newColumns = (config.rightPanel?.columns || []).filter(
|
||||
(_, i) => i !== index
|
||||
);
|
||||
updateRightPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
|
||||
{/* 테이블 모드 전용 옵션 */}
|
||||
{isTableMode && (
|
||||
<div className="grid grid-cols-3 gap-2 pt-1">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-[10px] text-gray-600">너비 (px)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min="50"
|
||||
value={col.width || 100}
|
||||
onChange={(e) => {
|
||||
const newColumns = [...(config.rightPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
width: parseInt(e.target.value) || 100,
|
||||
};
|
||||
updateRightPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-7 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-[10px] text-gray-600">정렬</Label>
|
||||
<Select
|
||||
value={col.align || "left"}
|
||||
onValueChange={(value: "left" | "center" | "right") => {
|
||||
const newColumns = [...(config.rightPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
align: value,
|
||||
};
|
||||
updateRightPanel({ columns: newColumns });
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-7 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="left">왼쪽</SelectItem>
|
||||
<SelectItem value="center">가운데</SelectItem>
|
||||
<SelectItem value="right">오른쪽</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
<label className="flex h-7 items-center gap-1 text-[10px] cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={col.sortable ?? false}
|
||||
onChange={(e) => {
|
||||
const newColumns = [...(config.rightPanel?.columns || [])];
|
||||
newColumns[index] = {
|
||||
...newColumns[index],
|
||||
sortable: e.target.checked,
|
||||
};
|
||||
updateRightPanel({ columns: newColumns });
|
||||
}}
|
||||
className="h-3 w-3"
|
||||
/>
|
||||
정렬가능
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user