테이블 템플릿 제작
This commit is contained in:
@@ -9,10 +9,12 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Settings, Move, Type, Trash2, Copy, Group, Ungroup } from "lucide-react";
|
||||
import { ComponentData, WebType, WidgetComponent, GroupComponent } from "@/types/screen";
|
||||
import { ComponentData, WebType, WidgetComponent, GroupComponent, DataTableComponent, TableInfo } from "@/types/screen";
|
||||
import DataTableConfigPanel from "./DataTableConfigPanel";
|
||||
|
||||
interface PropertiesPanelProps {
|
||||
selectedComponent?: ComponentData;
|
||||
tables?: TableInfo[];
|
||||
onUpdateProperty: (path: string, value: unknown) => void;
|
||||
onDeleteComponent: () => void;
|
||||
onCopyComponent: () => void;
|
||||
@@ -43,6 +45,7 @@ const webTypeOptions: { value: WebType; label: string }[] = [
|
||||
|
||||
export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
selectedComponent,
|
||||
tables = [],
|
||||
onUpdateProperty,
|
||||
onDeleteComponent,
|
||||
onCopyComponent,
|
||||
@@ -71,6 +74,7 @@ export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
labelMarginBottom: selectedComponent?.style?.labelMarginBottom || "4px",
|
||||
required: (selectedComponent?.type === "widget" ? (selectedComponent as WidgetComponent).required : false) || false,
|
||||
readonly: (selectedComponent?.type === "widget" ? (selectedComponent as WidgetComponent).readonly : false) || false,
|
||||
labelDisplay: selectedComponent?.style?.labelDisplay !== false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -83,6 +87,18 @@ export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
if (selectedComponent) {
|
||||
const widget = selectedComponent.type === "widget" ? (selectedComponent as WidgetComponent) : null;
|
||||
const group = selectedComponent.type === "group" ? (selectedComponent as GroupComponent) : null;
|
||||
|
||||
console.log("🔄 PropertiesPanel: 컴포넌트 변경 감지", {
|
||||
componentId: selectedComponent.id,
|
||||
componentType: selectedComponent.type,
|
||||
currentValues: {
|
||||
placeholder: widget?.placeholder,
|
||||
title: group?.title,
|
||||
positionX: selectedComponent.position.x,
|
||||
labelText: selectedComponent.style?.labelText || selectedComponent.label,
|
||||
},
|
||||
});
|
||||
|
||||
setLocalInputs({
|
||||
placeholder: widget?.placeholder || "",
|
||||
title: group?.title || "",
|
||||
@@ -98,9 +114,16 @@ export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
labelMarginBottom: selectedComponent.style?.labelMarginBottom || "4px",
|
||||
required: widget?.required || false,
|
||||
readonly: widget?.readonly || false,
|
||||
labelDisplay: selectedComponent.style?.labelDisplay !== false,
|
||||
});
|
||||
}
|
||||
}, [selectedComponent]);
|
||||
}, [
|
||||
selectedComponent,
|
||||
selectedComponent?.position,
|
||||
selectedComponent?.size,
|
||||
selectedComponent?.style,
|
||||
selectedComponent?.label,
|
||||
]);
|
||||
|
||||
if (!selectedComponent) {
|
||||
return (
|
||||
@@ -112,6 +135,65 @@ export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
// 데이터 테이블 컴포넌트인 경우 전용 패널 사용
|
||||
if (selectedComponent.type === "datatable") {
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
{/* 헤더 */}
|
||||
<div className="border-b border-gray-200 p-4">
|
||||
<div className="mb-3 flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Settings className="h-5 w-5 text-gray-600" />
|
||||
<span className="text-lg font-semibold">데이터 테이블 설정</span>
|
||||
</div>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{selectedComponent.type}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* 액션 버튼들 */}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button variant="outline" size="sm" onClick={onCopyComponent}>
|
||||
<Copy className="mr-1 h-4 w-4" />
|
||||
복사
|
||||
</Button>
|
||||
<Button variant="destructive" size="sm" onClick={onDeleteComponent}>
|
||||
<Trash2 className="mr-1 h-4 w-4" />
|
||||
삭제
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 데이터 테이블 설정 패널 */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<DataTableConfigPanel
|
||||
key={`datatable-${selectedComponent.id}-${selectedComponent.columns.length}-${selectedComponent.filters.length}-${JSON.stringify(selectedComponent.columns.map((c) => c.id))}-${JSON.stringify(selectedComponent.filters.map((f) => f.columnName))}`}
|
||||
component={selectedComponent as DataTableComponent}
|
||||
tables={tables}
|
||||
onUpdateComponent={(updates) => {
|
||||
console.log("🔄 DataTable 컴포넌트 업데이트:", updates);
|
||||
console.log("🔄 업데이트 항목들:", Object.keys(updates));
|
||||
|
||||
// 각 속성을 개별적으로 업데이트
|
||||
Object.entries(updates).forEach(([key, value]) => {
|
||||
console.log(` - ${key}:`, value);
|
||||
if (key === "columns") {
|
||||
console.log(` 컬럼 개수: ${Array.isArray(value) ? value.length : 0}`);
|
||||
}
|
||||
if (key === "filters") {
|
||||
console.log(` 필터 개수: ${Array.isArray(value) ? value.length : 0}`);
|
||||
}
|
||||
onUpdateProperty(key, value);
|
||||
});
|
||||
|
||||
console.log("✅ DataTable 컴포넌트 업데이트 완료");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
{/* 헤더 */}
|
||||
@@ -210,6 +292,7 @@ export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
value={localInputs.placeholder}
|
||||
onChange={(e) => {
|
||||
const newValue = e.target.value;
|
||||
console.log("🔄 placeholder 변경:", newValue);
|
||||
setLocalInputs((prev) => ({ ...prev, placeholder: newValue }));
|
||||
onUpdateProperty("placeholder", newValue);
|
||||
}}
|
||||
@@ -394,8 +477,12 @@ export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
</Label>
|
||||
<Checkbox
|
||||
id="labelDisplay"
|
||||
checked={selectedComponent.style?.labelDisplay !== false}
|
||||
onCheckedChange={(checked) => onUpdateProperty("style.labelDisplay", checked)}
|
||||
checked={localInputs.labelDisplay}
|
||||
onCheckedChange={(checked) => {
|
||||
console.log("🔄 라벨 표시 변경:", checked);
|
||||
setLocalInputs((prev) => ({ ...prev, labelDisplay: checked as boolean }));
|
||||
onUpdateProperty("style.labelDisplay", checked);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -409,6 +496,7 @@ export const PropertiesPanel: React.FC<PropertiesPanelProps> = ({
|
||||
value={localInputs.labelText}
|
||||
onChange={(e) => {
|
||||
const newValue = e.target.value;
|
||||
console.log("🔄 라벨 텍스트 변경:", newValue);
|
||||
setLocalInputs((prev) => ({ ...prev, labelText: newValue }));
|
||||
// 기본 라벨과 스타일 라벨을 모두 업데이트
|
||||
onUpdateProperty("label", newValue);
|
||||
|
||||
Reference in New Issue
Block a user