feat(split-panel-layout2): 테이블 모드, 수정/삭제, 복수 버튼 기능 추가
- 표시 모드 추가 (card/table) - 카드 모드 라벨 표시 옵션 (이름 행/정보 행 가로 배치) - 체크박스 선택 기능 (전체/개별 선택) - 개별 수정/삭제 핸들러 구현 (openEditModal, DELETE API) - 복수 액션 버튼 배열 지원 (add, edit, bulk-delete, custom) - 설정 패널에 표시 라벨 입력 필드 추가 - 기본키 컬럼 설정 옵션 추가
This commit is contained in:
@@ -530,6 +530,15 @@ export const SplitPanelLayout2ConfigPanel: React.FC<SplitPanelLayout2ConfigPanel
|
||||
onValueChange={(value) => updateDisplayColumn("left", index, "name", value)}
|
||||
placeholder="컬럼 선택"
|
||||
/>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">표시 라벨</Label>
|
||||
<Input
|
||||
value={col.label || ""}
|
||||
onChange={(e) => updateDisplayColumn("left", index, "label", e.target.value)}
|
||||
placeholder="라벨명 (미입력 시 컬럼명 사용)"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">표시 위치</Label>
|
||||
<Select
|
||||
@@ -707,6 +716,15 @@ export const SplitPanelLayout2ConfigPanel: React.FC<SplitPanelLayout2ConfigPanel
|
||||
onValueChange={(value) => updateDisplayColumn("right", index, "name", value)}
|
||||
placeholder="컬럼 선택"
|
||||
/>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">표시 라벨</Label>
|
||||
<Input
|
||||
value={col.label || ""}
|
||||
onChange={(e) => updateDisplayColumn("right", index, "label", e.target.value)}
|
||||
placeholder="라벨명 (미입력 시 컬럼명 사용)"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">표시 위치</Label>
|
||||
<Select
|
||||
@@ -826,6 +844,254 @@ export const SplitPanelLayout2ConfigPanel: React.FC<SplitPanelLayout2ConfigPanel
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 표시 모드 설정 */}
|
||||
<div className="pt-3 border-t">
|
||||
<Label className="text-xs font-medium">표시 모드</Label>
|
||||
<Select
|
||||
value={config.rightPanel?.displayMode || "card"}
|
||||
onValueChange={(value) => updateConfig("rightPanel.displayMode", value)}
|
||||
>
|
||||
<SelectTrigger className="h-9 text-sm mt-1">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="card">카드형</SelectItem>
|
||||
<SelectItem value="table">테이블형</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-[10px] text-muted-foreground mt-1">
|
||||
카드형: 카드 형태로 정보 표시, 테이블형: 표 형태로 정보 표시
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 카드 모드 전용 옵션 */}
|
||||
{(config.rightPanel?.displayMode || "card") === "card" && (
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<Label className="text-xs">라벨 표시</Label>
|
||||
<p className="text-[10px] text-muted-foreground">라벨: 값 형식으로 표시</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={config.rightPanel?.showLabels || false}
|
||||
onCheckedChange={(checked) => updateConfig("rightPanel.showLabels", checked)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 체크박스 표시 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<Label className="text-xs">체크박스 표시</Label>
|
||||
<p className="text-[10px] text-muted-foreground">항목 선택 기능 활성화</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={config.rightPanel?.showCheckbox || false}
|
||||
onCheckedChange={(checked) => updateConfig("rightPanel.showCheckbox", checked)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 수정/삭제 버튼 */}
|
||||
<div className="pt-3 border-t">
|
||||
<Label className="text-xs font-medium">개별 수정/삭제</Label>
|
||||
<div className="mt-2 space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-xs">수정 버튼 표시</Label>
|
||||
<Switch
|
||||
checked={config.rightPanel?.showEditButton || false}
|
||||
onCheckedChange={(checked) => updateConfig("rightPanel.showEditButton", checked)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-xs">삭제 버튼 표시</Label>
|
||||
<Switch
|
||||
checked={config.rightPanel?.showDeleteButton || false}
|
||||
onCheckedChange={(checked) => updateConfig("rightPanel.showDeleteButton", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 수정 모달 화면 (수정 버튼 활성화 시) */}
|
||||
{config.rightPanel?.showEditButton && (
|
||||
<div>
|
||||
<Label className="text-xs">수정 모달 화면</Label>
|
||||
<ScreenSelect
|
||||
value={config.rightPanel?.editModalScreenId}
|
||||
onValueChange={(value) => updateConfig("rightPanel.editModalScreenId", value)}
|
||||
placeholder="수정 모달 화면 선택 (미선택 시 추가 모달 사용)"
|
||||
open={false}
|
||||
onOpenChange={() => {}}
|
||||
/>
|
||||
<p className="text-[10px] text-muted-foreground mt-1">
|
||||
미선택 시 추가 모달 화면을 수정용으로 사용
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 기본키 컬럼 */}
|
||||
<div>
|
||||
<Label className="text-xs">기본키 컬럼</Label>
|
||||
<ColumnSelect
|
||||
columns={rightColumns}
|
||||
value={config.rightPanel?.primaryKeyColumn || ""}
|
||||
onValueChange={(value) => updateConfig("rightPanel.primaryKeyColumn", value)}
|
||||
placeholder="기본키 컬럼 선택 (기본: id)"
|
||||
/>
|
||||
<p className="text-[10px] text-muted-foreground mt-1">
|
||||
수정/삭제 시 사용할 기본키 컬럼 (미선택 시 id 사용)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 복수 액션 버튼 설정 */}
|
||||
<div className="pt-3 border-t">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<Label className="text-xs font-medium">액션 버튼 (복수)</Label>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-6 text-xs"
|
||||
onClick={() => {
|
||||
const current = config.rightPanel?.actionButtons || [];
|
||||
updateConfig("rightPanel.actionButtons", [
|
||||
...current,
|
||||
{
|
||||
id: `btn-${Date.now()}`,
|
||||
label: "새 버튼",
|
||||
variant: "default",
|
||||
action: "add",
|
||||
},
|
||||
]);
|
||||
}}
|
||||
>
|
||||
<Plus className="mr-1 h-3 w-3" />
|
||||
추가
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-[10px] text-muted-foreground mb-2">
|
||||
복수의 버튼을 추가하면 기존 단일 추가 버튼 대신 사용됩니다
|
||||
</p>
|
||||
<div className="space-y-3">
|
||||
{(config.rightPanel?.actionButtons || []).map((btn, index) => (
|
||||
<div key={btn.id} className="rounded-md border p-3 space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-medium text-muted-foreground">버튼 {index + 1}</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-6 w-6 p-0"
|
||||
onClick={() => {
|
||||
const current = config.rightPanel?.actionButtons || [];
|
||||
updateConfig(
|
||||
"rightPanel.actionButtons",
|
||||
current.filter((_, i) => i !== index)
|
||||
);
|
||||
}}
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">버튼 라벨</Label>
|
||||
<Input
|
||||
value={btn.label}
|
||||
onChange={(e) => {
|
||||
const current = [...(config.rightPanel?.actionButtons || [])];
|
||||
current[index] = { ...current[index], label: e.target.value };
|
||||
updateConfig("rightPanel.actionButtons", current);
|
||||
}}
|
||||
placeholder="버튼 라벨"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">동작</Label>
|
||||
<Select
|
||||
value={btn.action || "add"}
|
||||
onValueChange={(value) => {
|
||||
const current = [...(config.rightPanel?.actionButtons || [])];
|
||||
current[index] = { ...current[index], action: value as any };
|
||||
updateConfig("rightPanel.actionButtons", current);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="add">추가 (모달 열기)</SelectItem>
|
||||
<SelectItem value="edit">수정 (선택 항목)</SelectItem>
|
||||
<SelectItem value="bulk-delete">일괄 삭제 (선택 항목)</SelectItem>
|
||||
<SelectItem value="custom">커스텀</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">스타일</Label>
|
||||
<Select
|
||||
value={btn.variant || "default"}
|
||||
onValueChange={(value) => {
|
||||
const current = [...(config.rightPanel?.actionButtons || [])];
|
||||
current[index] = { ...current[index], variant: value as any };
|
||||
updateConfig("rightPanel.actionButtons", current);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="default">기본 (Primary)</SelectItem>
|
||||
<SelectItem value="outline">외곽선</SelectItem>
|
||||
<SelectItem value="destructive">삭제 (빨간색)</SelectItem>
|
||||
<SelectItem value="ghost">투명</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">아이콘</Label>
|
||||
<Select
|
||||
value={btn.icon || "none"}
|
||||
onValueChange={(value) => {
|
||||
const current = [...(config.rightPanel?.actionButtons || [])];
|
||||
current[index] = { ...current[index], icon: value === "none" ? undefined : value };
|
||||
updateConfig("rightPanel.actionButtons", current);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">없음</SelectItem>
|
||||
<SelectItem value="Plus">+ (추가)</SelectItem>
|
||||
<SelectItem value="Edit">수정</SelectItem>
|
||||
<SelectItem value="Trash2">삭제</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{btn.action === "add" && (
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">모달 화면</Label>
|
||||
<ScreenSelect
|
||||
value={btn.modalScreenId}
|
||||
onValueChange={(value) => {
|
||||
const current = [...(config.rightPanel?.actionButtons || [])];
|
||||
current[index] = { ...current[index], modalScreenId: value };
|
||||
updateConfig("rightPanel.actionButtons", current);
|
||||
}}
|
||||
placeholder="모달 화면 선택"
|
||||
open={false}
|
||||
onOpenChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{(config.rightPanel?.actionButtons || []).length === 0 && (
|
||||
<div className="text-center py-4 text-xs text-muted-foreground border rounded-md">
|
||||
액션 버튼을 추가하세요 (선택사항)
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user