feature/screen-management #162

Merged
kjs merged 9 commits from feature/screen-management into main 2025-10-29 11:26:27 +09:00
14 changed files with 233 additions and 362 deletions
Showing only changes of commit 711e051b1c - Show all commits

View File

@ -29,59 +29,6 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
return (
<div className={`space-y-6 p-6 ${className}`}>
{/* 여백 섹션 */}
<div className="space-y-3">
<div className="flex items-center gap-2">
<Box className="text-primary h-4 w-4" />
<h3 className="text-sm font-semibold"></h3>
</div>
<Separator className="my-2" />
<div className="space-y-3">
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1.5">
<Label htmlFor="margin" className="text-xs font-medium">
</Label>
<Input
id="margin"
type="text"
placeholder="10px"
value={localStyle.margin || ""}
onChange={(e) => handleStyleChange("margin", e.target.value)}
className="h-8"
/>
</div>
<div className="space-y-1.5">
<Label htmlFor="padding" className="text-xs font-medium">
</Label>
<Input
id="padding"
type="text"
placeholder="10px"
value={localStyle.padding || ""}
onChange={(e) => handleStyleChange("padding", e.target.value)}
className="h-8"
/>
</div>
</div>
<div className="space-y-1.5">
<Label htmlFor="gap" className="text-xs font-medium">
</Label>
<Input
id="gap"
type="text"
placeholder="10px"
value={localStyle.gap || ""}
onChange={(e) => handleStyleChange("gap", e.target.value)}
className="h-8"
/>
</div>
</div>
</div>
{/* 테두리 섹션 */}
<div className="space-y-3">
<div className="flex items-center gap-2">
@ -101,7 +48,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
placeholder="1px"
value={localStyle.borderWidth || ""}
onChange={(e) => handleStyleChange("borderWidth", e.target.value)}
className="h-8"
className="h-8 text-xs"
/>
</div>
<div className="space-y-1.5">
@ -112,7 +59,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
value={localStyle.borderStyle || "solid"}
onValueChange={(value) => handleStyleChange("borderStyle", value)}
>
<SelectTrigger className="h-8">
<SelectTrigger className="h-8 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
@ -136,14 +83,14 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
type="color"
value={localStyle.borderColor || "#000000"}
onChange={(e) => handleStyleChange("borderColor", e.target.value)}
className="h-8 w-14 p-1"
className="h-8 w-14 p-1 text-xs"
/>
<Input
type="text"
value={localStyle.borderColor || "#000000"}
onChange={(e) => handleStyleChange("borderColor", e.target.value)}
placeholder="#000000"
className="h-8 flex-1"
className="h-8 flex-1 text-xs"
/>
</div>
</div>
@ -157,7 +104,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
placeholder="5px"
value={localStyle.borderRadius || ""}
onChange={(e) => handleStyleChange("borderRadius", e.target.value)}
className="h-8"
className="h-8 text-xs"
/>
</div>
</div>
@ -182,14 +129,14 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
type="color"
value={localStyle.backgroundColor || "#ffffff"}
onChange={(e) => handleStyleChange("backgroundColor", e.target.value)}
className="h-8 w-14 p-1"
className="h-8 w-14 p-1 text-xs"
/>
<Input
type="text"
value={localStyle.backgroundColor || "#ffffff"}
onChange={(e) => handleStyleChange("backgroundColor", e.target.value)}
placeholder="#ffffff"
className="h-8 flex-1"
className="h-8 flex-1 text-xs"
/>
</div>
</div>
@ -204,7 +151,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
placeholder="url('image.jpg')"
value={localStyle.backgroundImage || ""}
onChange={(e) => handleStyleChange("backgroundImage", e.target.value)}
className="h-8"
className="h-8 text-xs"
/>
</div>
</div>
@ -229,14 +176,14 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
type="color"
value={localStyle.color || "#000000"}
onChange={(e) => handleStyleChange("color", e.target.value)}
className="h-8 w-14 p-1"
className="h-8 w-14 p-1 text-xs"
/>
<Input
type="text"
value={localStyle.color || "#000000"}
onChange={(e) => handleStyleChange("color", e.target.value)}
placeholder="#000000"
className="h-8 flex-1"
className="h-8 flex-1 text-xs"
/>
</div>
</div>
@ -250,7 +197,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
placeholder="14px"
value={localStyle.fontSize || ""}
onChange={(e) => handleStyleChange("fontSize", e.target.value)}
className="h-8"
className="h-8 text-xs"
/>
</div>
</div>
@ -264,17 +211,31 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
value={localStyle.fontWeight || "normal"}
onValueChange={(value) => handleStyleChange("fontWeight", value)}
>
<SelectTrigger className="h-6 w-full text-[10px] px-2">
<SelectTrigger className="h-6 w-full px-2 text-[10px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="normal" className="text-[10px]"></SelectItem>
<SelectItem value="bold" className="text-[10px]"></SelectItem>
<SelectItem value="100" className="text-[10px]">100</SelectItem>
<SelectItem value="400" className="text-[10px]">400</SelectItem>
<SelectItem value="500" className="text-[10px]">500</SelectItem>
<SelectItem value="600" className="text-[10px]">600</SelectItem>
<SelectItem value="700" className="text-[10px]">700</SelectItem>
<SelectItem value="normal" className="text-[10px]">
</SelectItem>
<SelectItem value="bold" className="text-[10px]">
</SelectItem>
<SelectItem value="100" className="text-[10px]">
100
</SelectItem>
<SelectItem value="400" className="text-[10px]">
400
</SelectItem>
<SelectItem value="500" className="text-[10px]">
500
</SelectItem>
<SelectItem value="600" className="text-[10px]">
600
</SelectItem>
<SelectItem value="700" className="text-[10px]">
700
</SelectItem>
</SelectContent>
</Select>
</div>
@ -286,14 +247,22 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
value={localStyle.textAlign || "left"}
onValueChange={(value) => handleStyleChange("textAlign", value)}
>
<SelectTrigger className="h-6 w-full text-[10px] px-2">
<SelectTrigger className="h-6 w-full px-2 text-[10px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="left" className="text-[10px]"></SelectItem>
<SelectItem value="center" className="text-[10px]"></SelectItem>
<SelectItem value="right" className="text-[10px]"></SelectItem>
<SelectItem value="justify" className="text-[10px]"></SelectItem>
<SelectItem value="left" className="text-[10px]">
</SelectItem>
<SelectItem value="center" className="text-[10px]">
</SelectItem>
<SelectItem value="right" className="text-[10px]">
</SelectItem>
<SelectItem value="justify" className="text-[10px]">
</SelectItem>
</SelectContent>
</Select>
</div>

View File

@ -515,94 +515,60 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
{/* 테이블 이력 보기 액션 설정 */}
{(component.componentConfig?.action?.type || "save") === "view_table_history" && (
<div className="mt-4 space-y-4">
<h4 className="text-sm font-medium">📜 </h4>
<div>
<Label>
() <span className="text-red-600">*</span>
</Label>
{!config.action?.historyTableName && !currentTableName ? (
<div className="mt-2 rounded-md border border-yellow-300 bg-yellow-50 p-3">
<p className="text-xs text-yellow-800">
<strong></strong> , .
</p>
</div>
) : (
<>
{!config.action?.historyTableName && currentTableName && (
<div className="mt-2 rounded-md border border-green-300 bg-green-50 p-2">
<p className="text-xs text-green-800">
<strong>{currentTableName}</strong>() .
</p>
</div>
)}
<Popover open={displayColumnOpen} onOpenChange={setDisplayColumnOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={displayColumnOpen}
className="mt-2 h-10 w-full justify-between text-sm"
disabled={columnsLoading || tableColumns.length === 0}
>
{columnsLoading
? "로딩 중..."
: config.action?.historyDisplayColumn
? config.action.historyDisplayColumn
: tableColumns.length === 0
? "사용 가능한 컬럼이 없습니다"
: "컬럼을 선택하세요"}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
<Command>
<CommandInput placeholder="컬럼 검색..." className="text-sm" />
<CommandList>
<CommandEmpty className="text-sm"> .</CommandEmpty>
<CommandGroup>
{tableColumns.map((column) => (
<CommandItem
key={column}
value={column}
onSelect={(currentValue) => {
onUpdateProperty("componentConfig.action.historyDisplayColumn", currentValue);
setDisplayColumnOpen(false);
}}
className="text-sm"
>
<Check
className={cn(
"mr-2 h-4 w-4",
config.action?.historyDisplayColumn === column ? "opacity-100" : "opacity-0",
)}
/>
{column}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<p className="mt-2 text-xs text-gray-700">
<strong> </strong> .
<br />
: <code className="rounded bg-white px-1">device_code</code> &quot;DTG-001&quot;
.
<br /> .
</p>
{tableColumns.length === 0 && !columnsLoading && (
<p className="mt-2 text-xs text-red-600">
ID .
</p>
)}
</>
)}
<Popover open={displayColumnOpen} onOpenChange={setDisplayColumnOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={displayColumnOpen}
className="mt-2 h-8 w-full justify-between text-xs"
disabled={columnsLoading || tableColumns.length === 0}
>
{columnsLoading
? "로딩 중..."
: config.action?.historyDisplayColumn
? config.action.historyDisplayColumn
: tableColumns.length === 0
? "사용 가능한 컬럼이 없습니다"
: "컬럼을 선택하세요"}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
<Command>
<CommandInput placeholder="컬럼 검색..." className="text-sm" />
<CommandList>
<CommandEmpty className="text-sm"> .</CommandEmpty>
<CommandGroup>
{tableColumns.map((column) => (
<CommandItem
key={column}
value={column}
onSelect={(currentValue) => {
onUpdateProperty("componentConfig.action.historyDisplayColumn", currentValue);
setDisplayColumnOpen(false);
}}
className="text-sm"
>
<Check
className={cn(
"mr-2 h-4 w-4",
config.action?.historyDisplayColumn === column ? "opacity-100" : "opacity-0",
)}
/>
{column}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
</div>
</div>
)}
@ -693,6 +659,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
setLocalInputs((prev) => ({ ...prev, targetUrl: newValue }));
onUpdateProperty("componentConfig.action.targetUrl", newValue);
}}
className="h-8 text-xs"
/>
<p className="mt-1 text-xs text-gray-500">URL을 </p>
</div>

View File

@ -21,14 +21,14 @@ interface ComponentsPanelProps {
placedColumns?: Set<string>; // 이미 배치된 컬럼명 집합
}
export function ComponentsPanel({
className,
tables = [],
searchTerm = "",
onSearchChange,
export function ComponentsPanel({
className,
tables = [],
searchTerm = "",
onSearchChange,
onTableDragStart,
selectedTableName,
placedColumns
placedColumns,
}: ComponentsPanelProps) {
const [searchQuery, setSearchQuery] = useState("");
@ -176,8 +176,8 @@ export function ComponentsPanel({
</div>
{/* 카테고리 탭 */}
<Tabs defaultValue="input" className="flex flex-1 flex-col">
<TabsList className="mb-3 grid h-8 w-full grid-cols-5">
<Tabs defaultValue="input" className="flex min-h-0 flex-1 flex-col">
<TabsList className="mb-3 grid h-8 w-full flex-shrink-0 grid-cols-5">
<TabsTrigger value="tables" className="flex items-center gap-1 px-1 text-xs">
<Database className="h-3 w-3" />
<span className="hidden sm:inline"></span>

View File

@ -1150,7 +1150,7 @@ export const DetailSettingsPanel: React.FC<DetailSettingsPanelProps> = ({
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700"> </label>
<Select value={localDetailType} onValueChange={handleDetailTypeChange}>
<SelectTrigger className="w-full bg-white">
<SelectTrigger className="h-8 w-full bg-white text-xs">
<SelectValue placeholder="세부 타입을 선택하세요" />
</SelectTrigger>
<SelectContent>

View File

@ -551,11 +551,6 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
{/* 액션 버튼들 */}
<div className="flex flex-wrap gap-1.5">
<Button size="sm" variant="outline" onClick={onCopyComponent} className="h-8 px-2.5 text-xs">
<Copy className="mr-1 h-3 w-3" />
</Button>
{canGroup && (
<Button size="sm" variant="outline" onClick={onGroupComponents} className="h-8 px-2.5 text-xs">
<Group className="mr-1 h-3 w-3" />
@ -569,11 +564,6 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
</Button>
)}
<Button size="sm" variant="destructive" onClick={onDeleteComponent} className="h-8 px-2.5 text-xs">
<Trash2 className="mr-1 h-3 w-3" />
</Button>
</div>
</div>

View File

@ -82,9 +82,9 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
<div className="space-y-4">
{/* 프리셋 선택 */}
<div className="space-y-2">
<Label className="text-sm font-medium"> </Label>
<Label className="text-xs font-medium"> </Label>
<Select value={selectedPreset} onValueChange={handlePresetChange}>
<SelectTrigger>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="해상도를 선택하세요" />
</SelectTrigger>
<SelectContent>
@ -93,7 +93,7 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
{SCREEN_RESOLUTIONS.filter((r) => r.category === "desktop").map((resolution) => (
<SelectItem key={resolution.name} value={resolution.name}>
<div className="flex items-center space-x-2">
<Monitor className="h-4 w-4 text-primary" />
<Monitor className="text-primary h-4 w-4" />
<span>{resolution.name}</span>
</div>
</SelectItem>
@ -125,7 +125,7 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
<div className="px-2 py-1 text-xs font-medium text-gray-500"> </div>
<SelectItem value="custom">
<div className="flex items-center space-x-2">
<Settings className="h-4 w-4 text-muted-foreground" />
<Settings className="text-muted-foreground h-4 w-4" />
<span> </span>
</div>
</SelectItem>
@ -139,43 +139,33 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
<Label className="text-sm font-medium"> </Label>
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1">
<Label className="text-xs text-muted-foreground"> (px)</Label>
<Label className="text-muted-foreground text-xs"> (px)</Label>
<Input
type="number"
value={customWidth}
onChange={(e) => setCustomWidth(e.target.value)}
placeholder="1920"
min="1"
className="h-8 text-xs"
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-muted-foreground"> (px)</Label>
<Label className="text-muted-foreground text-xs"> (px)</Label>
<Input
type="number"
value={customHeight}
onChange={(e) => setCustomHeight(e.target.value)}
placeholder="1080"
min="1"
className="h-8 text-xs"
/>
</div>
</div>
<Button onClick={handleCustomResolution} size="sm" className="w-full">
<Button onClick={handleCustomResolution} size="sm" className="h-8 w-full text-xs">
</Button>
</div>
)}
{/* 해상도 정보 */}
<div className="space-y-2 text-xs text-gray-500">
<div className="flex items-center justify-between">
<span> :</span>
<span>{(currentResolution.width / currentResolution.height).toFixed(2)}:1</span>
</div>
<div className="flex items-center justify-between">
<span> :</span>
<span>{(currentResolution.width * currentResolution.height).toLocaleString()}</span>
</div>
</div>
</div>
);
};

View File

@ -202,15 +202,6 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
return (
<div className="space-y-1.5">
{/* 컴포넌트 정보 - 간소화 */}
<div className="bg-muted flex items-center justify-between rounded px-2 py-1">
<div className="flex items-center gap-1">
<Info className="text-muted-foreground h-2.5 w-2.5" />
<span className="text-foreground text-[10px] font-medium">{selectedComponent.type}</span>
</div>
<span className="text-muted-foreground text-[9px]">{selectedComponent.id.slice(0, 8)}</span>
</div>
{/* 라벨 + 최소 높이 (같은 행) */}
<div className="grid grid-cols-2 gap-1.5">
<div className="space-y-0.5">
@ -300,24 +291,15 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
</div>
)}
{/* 위치 */}
<div className="grid grid-cols-3 gap-2">
<div>
<Label>X {dragState?.isDragging && <Badge variant="secondary"></Badge>}</Label>
<Input type="number" value={Math.round(currentPosition.x || 0)} disabled />
</div>
<div>
<Label>Y</Label>
<Input type="number" value={Math.round(currentPosition.y || 0)} disabled />
</div>
<div>
<Label>Z</Label>
<Input
type="number"
value={currentPosition.z || 1}
onChange={(e) => handleUpdate("position.z", parseInt(e.target.value) || 1)}
/>
</div>
{/* Z-Index */}
<div className="space-y-0.5">
<Label className="text-[10px]">Z-Index ()</Label>
<Input
type="number"
value={currentPosition.z || 1}
onChange={(e) => handleUpdate("position.z", parseInt(e.target.value) || 1)}
className="h-6 text-[10px]"
/>
</div>
{/* 라벨 스타일 */}
@ -389,33 +371,6 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
</div>
)}
</div>
{/* 액션 버튼 */}
<Separator />
<div className="flex gap-2">
{onCopyComponent && (
<Button
variant="outline"
size="sm"
onClick={() => onCopyComponent(selectedComponent.id)}
className="flex-1"
>
<Copy className="mr-2 h-4 w-4" />
</Button>
)}
{onDeleteComponent && (
<Button
variant="outline"
size="sm"
onClick={() => onDeleteComponent(selectedComponent.id)}
className="flex-1 text-red-600 hover:bg-red-50 hover:text-red-700"
>
<Trash2 className="mr-2 h-4 w-4" />
</Button>
)}
</div>
</div>
);
};
@ -513,7 +468,7 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
<div>
<Label> </Label>
<Select value={localComponentDetailType || webType} onValueChange={handleDetailTypeChange}>
<SelectTrigger>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="세부 타입 선택" />
</SelectTrigger>
<SelectContent>
@ -561,7 +516,7 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
<div>
<Label> </Label>
<Select value={widget.webType} onValueChange={(value) => handleUpdate("webType", value)}>
<SelectTrigger>
<SelectTrigger className="h-8 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>

View File

@ -90,11 +90,11 @@ export const CheckboxTypeConfigPanel: React.FC<CheckboxTypeConfigPanelProps> = (
const newConfig = JSON.parse(JSON.stringify(currentValues));
// console.log("☑️ CheckboxTypeConfig 업데이트:", {
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// });
setTimeout(() => {
@ -122,7 +122,7 @@ export const CheckboxTypeConfigPanel: React.FC<CheckboxTypeConfigPanelProps> = (
</Label>
<Select value={localValues.labelPosition} onValueChange={(value) => updateConfig("labelPosition", value)}>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="라벨 위치 선택" />
</SelectTrigger>
<SelectContent>
@ -218,7 +218,7 @@ export const CheckboxTypeConfigPanel: React.FC<CheckboxTypeConfigPanelProps> = (
{/* 안내 메시지 */}
{localValues.indeterminate && (
<div className="rounded-md bg-accent p-3">
<div className="bg-accent rounded-md p-3">
<div className="text-sm font-medium text-blue-900"> </div>
<div className="mt-1 text-xs text-blue-800">
.

View File

@ -105,10 +105,10 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
// 실제 config 업데이트
const newConfig = { ...safeConfig, [key]: value };
// console.log("💻 CodeTypeConfig 업데이트:", {
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// });
onConfigChange(newConfig);
};
@ -121,7 +121,7 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
</Label>
<Select value={localValues.language} onValueChange={(value) => updateConfig("language", value)}>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="언어 선택" />
</SelectTrigger>
<SelectContent className="max-h-60">
@ -140,7 +140,7 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
</Label>
<Select value={localValues.theme} onValueChange={(value) => updateConfig("theme", value)}>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="테마 선택" />
</SelectTrigger>
<SelectContent>
@ -271,7 +271,7 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
</div>
{/* 안내 메시지 */}
<div className="rounded-md bg-accent p-3">
<div className="bg-accent rounded-md p-3">
<div className="text-sm font-medium text-blue-900"> </div>
<div className="mt-1 text-xs text-blue-800">

View File

@ -27,8 +27,8 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
// 로컬 상태로 실시간 입력 관리
const [localValues, setLocalValues] = useState(() => {
// console.log("📅 DateTypeConfigPanel 초기 상태 설정:", {
// config,
// safeConfig,
// config,
// safeConfig,
// });
return {
@ -47,17 +47,17 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
const hasValidConfig = config && Object.keys(config).length > 0;
// console.log("📅 DateTypeConfigPanel config 변경 감지:", {
// config,
// configExists: !!config,
// configKeys: config ? Object.keys(config) : [],
// hasValidConfig,
// safeConfig,
// safeConfigKeys: Object.keys(safeConfig),
// currentLocalValues: localValues,
// configStringified: JSON.stringify(config),
// safeConfigStringified: JSON.stringify(safeConfig),
// willUpdateLocalValues: hasValidConfig,
// timestamp: new Date().toISOString(),
// config,
// configExists: !!config,
// configKeys: config ? Object.keys(config) : [],
// hasValidConfig,
// safeConfig,
// safeConfigKeys: Object.keys(safeConfig),
// currentLocalValues: localValues,
// configStringified: JSON.stringify(config),
// safeConfigStringified: JSON.stringify(safeConfig),
// willUpdateLocalValues: hasValidConfig,
// timestamp: new Date().toISOString(),
// });
// config가 없거나 비어있으면 로컬 상태를 유지
@ -85,17 +85,17 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
localValues.maxDate !== newLocalValues.maxDate;
// console.log("🔄 로컬 상태 업데이트 검사:", {
// oldLocalValues: localValues,
// newLocalValues,
// hasChanges,
// changes: {
// format: localValues.format !== newLocalValues.format,
// showTime: localValues.showTime !== newLocalValues.showTime,
// defaultValue: localValues.defaultValue !== newLocalValues.defaultValue,
// placeholder: localValues.placeholder !== newLocalValues.placeholder,
// minDate: localValues.minDate !== newLocalValues.minDate,
// maxDate: localValues.maxDate !== newLocalValues.maxDate,
// },
// oldLocalValues: localValues,
// newLocalValues,
// hasChanges,
// changes: {
// format: localValues.format !== newLocalValues.format,
// showTime: localValues.showTime !== newLocalValues.showTime,
// defaultValue: localValues.defaultValue !== newLocalValues.defaultValue,
// placeholder: localValues.placeholder !== newLocalValues.placeholder,
// minDate: localValues.minDate !== newLocalValues.minDate,
// maxDate: localValues.maxDate !== newLocalValues.maxDate,
// },
// });
if (hasChanges) {
@ -113,34 +113,34 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
// 실제 config 업데이트 - 현재 로컬 상태를 기반으로 새 객체 생성 (safeConfig 기본값 덮어쓰기 방지)
const newConfig = JSON.parse(JSON.stringify({ ...localValues, [key]: value }));
// console.log("📅 DateTypeConfig 업데이트:", {
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// timestamp: new Date().toISOString(),
// changes: {
// format: newConfig.format !== safeConfig.format,
// showTime: newConfig.showTime !== safeConfig.showTime,
// placeholder: newConfig.placeholder !== safeConfig.placeholder,
// minDate: newConfig.minDate !== safeConfig.minDate,
// maxDate: newConfig.maxDate !== safeConfig.maxDate,
// defaultValue: newConfig.defaultValue !== safeConfig.defaultValue,
// },
// willCallOnConfigChange: true,
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// timestamp: new Date().toISOString(),
// changes: {
// format: newConfig.format !== safeConfig.format,
// showTime: newConfig.showTime !== safeConfig.showTime,
// placeholder: newConfig.placeholder !== safeConfig.placeholder,
// minDate: newConfig.minDate !== safeConfig.minDate,
// maxDate: newConfig.maxDate !== safeConfig.maxDate,
// defaultValue: newConfig.defaultValue !== safeConfig.defaultValue,
// },
// willCallOnConfigChange: true,
// });
// console.log("🔄 onConfigChange 호출 직전:", {
// newConfig,
// configStringified: JSON.stringify(newConfig),
// newConfig,
// configStringified: JSON.stringify(newConfig),
// });
// 약간의 지연을 두고 업데이트 (배치 업데이트 방지)
setTimeout(() => {
// console.log("✅ onConfigChange 호출 완료:", {
// key,
// newConfig,
// timestamp: new Date().toISOString(),
// key,
// newConfig,
// timestamp: new Date().toISOString(),
// });
onConfigChange(newConfig);
}, 0);
@ -157,9 +157,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
value={localValues.format}
onValueChange={(value) => {
// console.log("📅 날짜 형식 변경:", {
// oldFormat: localValues.format,
// newFormat: value,
// oldShowTime: localValues.showTime,
// oldFormat: localValues.format,
// newFormat: value,
// oldShowTime: localValues.showTime,
// });
// format 변경 시 showTime도 자동 동기화
@ -175,9 +175,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
);
// console.log("🔄 format+showTime 동시 업데이트:", {
// newFormat: value,
// newShowTime: hasTime,
// newConfig,
// newFormat: value,
// newShowTime: hasTime,
// newConfig,
// });
// 로컬 상태도 동시 업데이트
@ -193,7 +193,7 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
}, 0);
}}
>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="날짜 형식 선택" />
</SelectTrigger>
<SelectContent>
@ -215,9 +215,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
onCheckedChange={(checked) => {
const newShowTime = !!checked;
// console.log("⏰ 시간 표시 체크박스 변경:", {
// oldShowTime: localValues.showTime,
// newShowTime,
// currentFormat: localValues.format,
// oldShowTime: localValues.showTime,
// newShowTime,
// currentFormat: localValues.format,
// });
// showTime 변경 시 format도 적절히 조정
@ -231,9 +231,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
}
// console.log("🔄 showTime+format 동시 업데이트:", {
// newShowTime,
// oldFormat: localValues.format,
// newFormat,
// newShowTime,
// oldFormat: localValues.format,
// newFormat,
// });
// 한 번에 두 값을 모두 업데이트 - 현재 로컬 상태 기반으로 생성

View File

@ -92,10 +92,10 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
// 실제 config 업데이트
const newConfig = { ...safeConfig, [key]: value };
// console.log("🏢 EntityTypeConfig 업데이트:", {
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// });
onConfigChange(newConfig);
};
@ -233,7 +233,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
</Label>
<Select value={localValues.displayFormat} onValueChange={(value) => updateConfig("displayFormat", value)}>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="형식 선택" />
</SelectTrigger>
<SelectContent>
@ -317,7 +317,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
<div className="mt-2">
<div className="flex items-center space-x-2 rounded border bg-white p-2">
<Search className="h-4 w-4 text-gray-400" />
<div className="flex-1 text-sm text-muted-foreground">
<div className="text-muted-foreground flex-1 text-sm">
{localValues.placeholder || `${localValues.referenceTable || "엔터티"}를 선택하세요`}
</div>
<Database className="h-4 w-4 text-gray-400" />
@ -334,7 +334,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
</div>
{/* 안내 메시지 */}
<div className="rounded-md bg-accent p-3">
<div className="bg-accent rounded-md p-3">
<div className="text-sm font-medium text-blue-900"> </div>
<div className="mt-1 text-xs text-blue-800">
<strong> </strong>:

View File

@ -89,12 +89,12 @@ export const NumberTypeConfigPanel: React.FC<NumberTypeConfigPanelProps> = ({ co
const newConfig = JSON.parse(JSON.stringify(currentValues));
// console.log("🔢 NumberTypeConfig 업데이트:", {
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// timestamp: new Date().toISOString(),
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// timestamp: new Date().toISOString(),
// });
// 약간의 지연을 두고 업데이트 (배치 업데이트 방지)
@ -111,7 +111,7 @@ export const NumberTypeConfigPanel: React.FC<NumberTypeConfigPanelProps> = ({ co
</Label>
<Select value={localValues.format} onValueChange={(value) => updateConfig("format", value)}>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="숫자 형식 선택" />
</SelectTrigger>
<SelectContent>

View File

@ -82,11 +82,11 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
// 실제 config 업데이트 - 깊은 복사로 새 객체 보장
const newConfig = JSON.parse(JSON.stringify({ ...safeConfig, [key]: value }));
// console.log("📋 SelectTypeConfig 업데이트:", {
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// timestamp: new Date().toISOString(),
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// timestamp: new Date().toISOString(),
// });
// 약간의 지연을 두고 업데이트 (배치 업데이트 방지)
@ -101,10 +101,10 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
const updatedOptions = [...(safeConfig.options || []), newOptionData];
// console.log(" SelectType 옵션 추가:", {
// newOption: newOptionData,
// updatedOptions,
// currentLocalOptions: localOptions,
// timestamp: new Date().toISOString(),
// newOption: newOptionData,
// updatedOptions,
// currentLocalOptions: localOptions,
// timestamp: new Date().toISOString(),
// });
// 로컬 상태 즉시 업데이트
@ -128,9 +128,9 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
const removeOption = (index: number) => {
// console.log(" SelectType 옵션 삭제:", {
// removeIndex: index,
// currentOptions: safeConfig.options,
// currentLocalOptions: localOptions,
// removeIndex: index,
// currentOptions: safeConfig.options,
// currentLocalOptions: localOptions,
// });
// 로컬 상태 즉시 업데이트
@ -170,7 +170,7 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
value={localValues.placeholder}
onChange={(e) => updateConfig("placeholder", e.target.value)}
placeholder="옵션을 선택하세요"
className="mt-1"
className="mt-1 h-8 text-xs"
/>
</div>

View File

@ -94,11 +94,11 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
const newConfig = JSON.parse(JSON.stringify(currentValues));
// console.log("📝 TextTypeConfig 업데이트:", {
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// key,
// value,
// oldConfig: safeConfig,
// newConfig,
// localValues,
// });
setTimeout(() => {
@ -114,7 +114,7 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
</Label>
<Select value={localValues.format} onValueChange={(value) => updateConfig("format", value)}>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="입력 형식 선택" />
</SelectTrigger>
<SelectContent>
@ -220,13 +220,13 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
</div>
{localValues.autoInput && (
<div className="space-y-3 border-l-2 border-primary/20 pl-4">
<div className="border-primary/20 space-y-3 border-l-2 pl-4">
<div>
<Label htmlFor="autoValueType" className="text-sm font-medium">
</Label>
<Select value={localValues.autoValueType} onValueChange={(value) => updateConfig("autoValueType", value)}>
<SelectTrigger className="mt-1">
<SelectTrigger className="mt-1 h-8 text-xs">
<SelectValue placeholder="자동값 타입 선택" />
</SelectTrigger>
<SelectContent>
@ -256,7 +256,7 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
</div>
)}
<div className="rounded-md bg-accent p-3">
<div className="bg-accent rounded-md p-3">
<div className="text-sm font-medium text-blue-900"> </div>
<div className="mt-1 text-xs text-blue-800">
, .
@ -280,7 +280,7 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
{/* 형식별 안내 메시지 */}
{localValues.format !== "none" && (
<div className="rounded-md bg-accent p-3">
<div className="bg-accent rounded-md p-3">
<div className="text-sm font-medium text-blue-900"> </div>
<div className="mt-1 text-xs text-blue-800">
{localValues.format === "email" && "유효한 이메일 주소를 입력해야 합니다 (예: user@example.com)"}