[agent-pipeline] pipe-20260311052455-y968 round-1

This commit is contained in:
DDD1542 2026-03-11 14:35:02 +09:00
parent afd936ff67
commit b329b52036
2 changed files with 93 additions and 445 deletions

View File

@ -8,7 +8,6 @@ import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { Textarea } from "@/components/ui/textarea";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { ChevronDown, Settings, Info, Database, Trash2, Copy, Palette } from "lucide-react"; import { ChevronDown, Settings, Info, Database, Trash2, Copy, Palette } from "lucide-react";
import { import {
@ -44,20 +43,11 @@ import {
DetailTypeOption, DetailTypeOption,
} from "@/types/input-type-mapping"; } from "@/types/input-type-mapping";
// 새로운 컴포넌트 설정 패널들
import { ButtonConfigPanel } from "../config-panels/ButtonConfigPanel";
import { CardConfigPanel } from "../config-panels/CardConfigPanel";
import { DashboardConfigPanel } from "../config-panels/DashboardConfigPanel";
import { ColorPickerWithTransparent } from "../common/ColorPickerWithTransparent"; import { ColorPickerWithTransparent } from "../common/ColorPickerWithTransparent";
import { StatsCardConfigPanel } from "../config-panels/StatsCardConfigPanel";
// ComponentRegistry import (동적 ConfigPanel 가져오기용) // ComponentRegistry import (동적 ConfigPanel 가져오기용)
import { ComponentRegistry } from "@/lib/registry/ComponentRegistry"; import { ComponentRegistry } from "@/lib/registry/ComponentRegistry";
import { ProgressBarConfigPanel } from "../config-panels/ProgressBarConfigPanel"; import { DynamicComponentConfigPanel, hasComponentConfigPanel } from "@/lib/utils/getComponentConfigPanel";
import { ChartConfigPanel } from "../config-panels/ChartConfigPanel";
import { AlertConfigPanel } from "../config-panels/AlertConfigPanel";
import { BadgeConfigPanel } from "../config-panels/BadgeConfigPanel";
import { DynamicComponentConfigPanel } from "@/lib/utils/getComponentConfigPanel";
import StyleEditor from "../StyleEditor"; import StyleEditor from "../StyleEditor";
import { Slider } from "@/components/ui/slider"; import { Slider } from "@/components/ui/slider";
import { Zap } from "lucide-react"; import { Zap } from "lucide-react";
@ -186,17 +176,6 @@ export const V2PropertiesPanel: React.FC<V2PropertiesPanelProps> = ({
selectedComponent.componentConfig?.id || selectedComponent.componentConfig?.id ||
selectedComponent.type; selectedComponent.type;
const handleUpdateProperty = (path: string, value: any) => {
onUpdateProperty(selectedComponent.id, path, value);
};
const handleConfigChange = (newConfig: any) => {
// 기존 config와 병합하여 다른 속성 유지
const currentConfig = selectedComponent.componentConfig?.config || {};
const mergedConfig = { ...currentConfig, ...newConfig };
onUpdateProperty(selectedComponent.id, "componentConfig.config", mergedConfig);
};
// 🆕 ComponentRegistry에서 ConfigPanel 가져오기 시도 // 🆕 ComponentRegistry에서 ConfigPanel 가져오기 시도
const componentId = const componentId =
selectedComponent.componentType || // ⭐ section-card 등 selectedComponent.componentType || // ⭐ section-card 등
@ -204,58 +183,6 @@ export const V2PropertiesPanel: React.FC<V2PropertiesPanelProps> = ({
selectedComponent.componentConfig?.id || selectedComponent.componentConfig?.id ||
(selectedComponent.type === "component" ? selectedComponent.id : null); // 🆕 독립 컴포넌트 (table-search-widget 등) (selectedComponent.type === "component" ? selectedComponent.id : null); // 🆕 독립 컴포넌트 (table-search-widget 등)
// 🆕 V2 컴포넌트 직접 감지 및 설정 패널 렌더링
if (componentId?.startsWith("v2-")) {
const v2ConfigPanels: Record<string, React.FC<{ config: any; onChange: (config: any) => void }>> = {
"v2-input": require("@/components/v2/config-panels/V2InputConfigPanel").V2InputConfigPanel,
"v2-select": require("@/components/v2/config-panels/V2SelectConfigPanel").V2SelectConfigPanel,
"v2-date": require("@/components/v2/config-panels/V2DateConfigPanel").V2DateConfigPanel,
"v2-list": require("@/components/v2/config-panels/V2ListConfigPanel").V2ListConfigPanel,
"v2-layout": require("@/components/v2/config-panels/V2LayoutConfigPanel").V2LayoutConfigPanel,
"v2-group": require("@/components/v2/config-panels/V2GroupConfigPanel").V2GroupConfigPanel,
"v2-media": require("@/components/v2/config-panels/V2MediaConfigPanel").V2MediaConfigPanel,
"v2-biz": require("@/components/v2/config-panels/V2BizConfigPanel").V2BizConfigPanel,
"v2-hierarchy": require("@/components/v2/config-panels/V2HierarchyConfigPanel").V2HierarchyConfigPanel,
"v2-bom-item-editor": require("@/components/v2/config-panels/V2BomItemEditorConfigPanel").V2BomItemEditorConfigPanel,
"v2-bom-tree": require("@/components/v2/config-panels/V2BomTreeConfigPanel").V2BomTreeConfigPanel,
};
const V2ConfigPanel = v2ConfigPanels[componentId];
if (V2ConfigPanel) {
const currentConfig = selectedComponent.componentConfig || {};
const handleV2ConfigChange = (newConfig: any) => {
onUpdateProperty(selectedComponent.id, "componentConfig", { ...currentConfig, ...newConfig });
};
// 컬럼의 inputType 가져오기 (entity 타입인지 확인용)
const inputType = currentConfig.inputType || currentConfig.webType || (selectedComponent as any).inputType;
// 현재 화면의 테이블명 가져오기
const currentTableName = tables?.[0]?.tableName;
// 컴포넌트별 추가 props
const extraProps: Record<string, any> = {};
if (componentId === "v2-select") {
extraProps.inputType = inputType;
extraProps.tableName = selectedComponent.tableName || currentTable?.tableName || currentTableName;
extraProps.columnName = selectedComponent.columnName || currentConfig.fieldKey || currentConfig.columnName;
}
if (componentId === "v2-list") {
extraProps.currentTableName = currentTableName;
}
if (componentId === "v2-bom-item-editor" || componentId === "v2-bom-tree") {
extraProps.currentTableName = currentTableName;
extraProps.screenTableName = selectedComponent.tableName || currentTable?.tableName || currentTableName;
}
return (
<div key={selectedComponent.id} className="space-y-4">
<V2ConfigPanel config={currentConfig} onChange={handleV2ConfigChange} {...extraProps} />
</div>
);
}
}
if (componentId) { if (componentId) {
const definition = ComponentRegistry.getComponent(componentId); const definition = ComponentRegistry.getComponent(componentId);
@ -322,335 +249,42 @@ export const V2PropertiesPanel: React.FC<V2PropertiesPanelProps> = ({
</div> </div>
); );
} }
// ConfigPanel이 없으면 아래 switch case로 넘어감 // ConfigPanel이 없으면 DynamicComponentConfigPanel fallback으로 처리
} }
// 기존 하드코딩된 설정 패널들 (레거시) // DynamicComponentConfigPanel을 통한 동적 로드 (CONFIG_PANEL_MAP 기반)
switch (componentType) { const fallbackId = componentId || componentType;
case "button": if (fallbackId && hasComponentConfigPanel(fallbackId)) {
case "button-primary": const handleDynamicConfigChange = (newConfig: any) => {
case "button-secondary": const currentConfig = selectedComponent.componentConfig || {};
case "v2-button-primary": const mergedConfig = { ...currentConfig, ...newConfig };
// 🔧 component.id만 key로 사용 (unmount 방지) onUpdateProperty(selectedComponent.id, "componentConfig", mergedConfig);
};
return ( return (
<ButtonConfigPanel <DynamicComponentConfigPanel
key={selectedComponent.id} componentId={fallbackId}
component={selectedComponent} config={selectedComponent.componentConfig || {}}
onUpdateProperty={handleUpdateProperty} onChange={handleDynamicConfigChange}
screenTableName={selectedComponent.tableName || currentTable?.tableName || currentTableName}
tableColumns={currentTable?.columns || []}
tables={tables}
menuObjid={menuObjid}
allComponents={allComponents} allComponents={allComponents}
currentTableName={currentTableName} currentComponent={selectedComponent}
currentScreenCompanyCode={currentScreenCompanyCode}
/> />
); );
}
case "card":
return <CardConfigPanel component={selectedComponent} onUpdateProperty={handleUpdateProperty} />;
case "dashboard":
return <DashboardConfigPanel component={selectedComponent} onUpdateProperty={handleUpdateProperty} />;
case "stats":
case "stats-card":
return <StatsCardConfigPanel component={selectedComponent} onUpdateProperty={handleUpdateProperty} />;
case "progress":
case "progress-bar":
return <ProgressBarConfigPanel component={selectedComponent} onUpdateProperty={handleUpdateProperty} />;
case "chart":
case "chart-basic":
return <ChartConfigPanel component={selectedComponent} onUpdateProperty={handleUpdateProperty} />;
case "alert":
case "alert-info":
return <AlertConfigPanel component={selectedComponent} onUpdateProperty={handleUpdateProperty} />;
case "badge":
case "badge-status":
return <BadgeConfigPanel component={selectedComponent} onUpdateProperty={handleUpdateProperty} />;
case "section-card":
return (
<div className="space-y-4 p-4">
<div className="space-y-2">
<h3 className="text-sm font-semibold">Section Card </h3>
<p className="text-muted-foreground text-xs"> </p>
</div>
{/* 헤더 표시 */}
<div className="flex items-center space-x-2">
<Checkbox
id="showHeader"
checked={selectedComponent.componentConfig?.showHeader !== false}
onCheckedChange={(checked) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.showHeader", checked);
}}
/>
<Label htmlFor="showHeader" className="cursor-pointer text-xs">
</Label>
</div>
{/* 제목 */}
{selectedComponent.componentConfig?.showHeader !== false && (
<div className="space-y-2">
<Label className="text-xs"></Label>
<Input
value={selectedComponent.componentConfig?.title || ""}
onChange={(e) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.title", e.target.value);
}}
placeholder="섹션 제목 입력"
className="h-9 text-xs"
/>
</div>
)}
{/* 설명 */}
{selectedComponent.componentConfig?.showHeader !== false && (
<div className="space-y-2">
<Label className="text-xs"> ()</Label>
<Textarea
value={selectedComponent.componentConfig?.description || ""}
onChange={(e) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.description", e.target.value);
}}
placeholder="섹션 설명 입력"
className="resize-none text-xs"
rows={2}
/>
</div>
)}
{/* 패딩 */}
<div className="space-y-2">
<Label className="text-xs"> </Label>
<Select
value={selectedComponent.componentConfig?.padding || "md"}
onValueChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.padding", value);
}}
>
<SelectTrigger className="h-9 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="none"></SelectItem>
<SelectItem value="sm"> (12px)</SelectItem>
<SelectItem value="md"> (24px)</SelectItem>
<SelectItem value="lg"> (32px)</SelectItem>
</SelectContent>
</Select>
</div>
{/* 배경색 */}
<div className="space-y-2">
<Label className="text-xs"></Label>
<Select
value={selectedComponent.componentConfig?.backgroundColor || "default"}
onValueChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.backgroundColor", value);
}}
>
<SelectTrigger className="h-9 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="default"> ()</SelectItem>
<SelectItem value="muted"></SelectItem>
<SelectItem value="transparent"></SelectItem>
</SelectContent>
</Select>
</div>
{/* 테두리 스타일 */}
<div className="space-y-2">
<Label className="text-xs"> </Label>
<Select
value={selectedComponent.componentConfig?.borderStyle || "solid"}
onValueChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.borderStyle", value);
}}
>
<SelectTrigger className="h-9 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="solid"></SelectItem>
<SelectItem value="dashed"></SelectItem>
<SelectItem value="none"></SelectItem>
</SelectContent>
</Select>
</div>
{/* 접기/펼치기 기능 */}
<div className="space-y-2 border-t pt-2">
<div className="flex items-center space-x-2">
<Checkbox
id="collapsible"
checked={selectedComponent.componentConfig?.collapsible || false}
onCheckedChange={(checked) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.collapsible", checked);
}}
/>
<Label htmlFor="collapsible" className="cursor-pointer text-xs">
/
</Label>
</div>
{selectedComponent.componentConfig?.collapsible && (
<div className="ml-6 flex items-center space-x-2">
<Checkbox
id="defaultOpen"
checked={selectedComponent.componentConfig?.defaultOpen !== false}
onCheckedChange={(checked) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.defaultOpen", checked);
}}
/>
<Label htmlFor="defaultOpen" className="cursor-pointer text-xs">
</Label>
</div>
)}
</div>
</div>
);
case "section-paper":
return (
<div className="space-y-4 p-4">
<div className="space-y-2">
<h3 className="text-sm font-semibold">Section Paper </h3>
<p className="text-muted-foreground text-xs"> </p>
</div>
{/* 배경색 */}
<div className="space-y-2">
<Label className="text-xs"></Label>
<Select
value={selectedComponent.componentConfig?.backgroundColor || "default"}
onValueChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.backgroundColor", value);
}}
>
<SelectTrigger className="h-9 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="default"> ( )</SelectItem>
<SelectItem value="muted"></SelectItem>
<SelectItem value="accent"> ( )</SelectItem>
<SelectItem value="primary"> </SelectItem>
<SelectItem value="custom"></SelectItem>
</SelectContent>
</Select>
</div>
{/* 커스텀 색상 */}
{selectedComponent.componentConfig?.backgroundColor === "custom" && (
<div className="space-y-2">
<Label className="text-xs"> </Label>
<ColorPickerWithTransparent
value={selectedComponent.componentConfig?.customColor}
onChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.customColor", value);
}}
defaultColor="#f0f0f0"
placeholder="#f0f0f0"
/>
</div>
)}
{/* 패딩 */}
<div className="space-y-2">
<Label className="text-xs"> </Label>
<Select
value={selectedComponent.componentConfig?.padding || "md"}
onValueChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.padding", value);
}}
>
<SelectTrigger className="h-9 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="none"></SelectItem>
<SelectItem value="sm"> (12px)</SelectItem>
<SelectItem value="md"> (16px)</SelectItem>
<SelectItem value="lg"> (24px)</SelectItem>
</SelectContent>
</Select>
</div>
{/* 둥근 모서리 */}
<div className="space-y-2">
<Label className="text-xs"> </Label>
<Select
value={selectedComponent.componentConfig?.roundedCorners || "md"}
onValueChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.roundedCorners", value);
}}
>
<SelectTrigger className="h-9 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="none"></SelectItem>
<SelectItem value="sm"> (2px)</SelectItem>
<SelectItem value="md"> (6px)</SelectItem>
<SelectItem value="lg"> (8px)</SelectItem>
</SelectContent>
</Select>
</div>
{/* 그림자 */}
<div className="space-y-2">
<Label className="text-xs"></Label>
<Select
value={selectedComponent.componentConfig?.shadow || "none"}
onValueChange={(value) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.shadow", value);
}}
>
<SelectTrigger className="h-9 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="none"></SelectItem>
<SelectItem value="sm"></SelectItem>
<SelectItem value="md"></SelectItem>
</SelectContent>
</Select>
</div>
{/* 테두리 표시 */}
<div className="flex items-center space-x-2">
<Checkbox
id="showBorder"
checked={selectedComponent.componentConfig?.showBorder || false}
onCheckedChange={(checked) => {
handleUpdateProperty(selectedComponent.id, "componentConfig.showBorder", checked);
}}
/>
<Label htmlFor="showBorder" className="cursor-pointer text-xs">
</Label>
</div>
</div>
);
default:
// ConfigPanel이 없는 경우 경고 표시
return ( return (
<div className="flex h-full flex-col items-center justify-center p-6 text-center"> <div className="flex h-full flex-col items-center justify-center p-6 text-center">
<Settings className="text-muted-foreground mb-4 h-12 w-12" /> <Settings className="text-muted-foreground mb-4 h-12 w-12" />
<h3 className="mb-2 text-base font-medium"> </h3> <h3 className="mb-2 text-base font-medium"> </h3>
<p className="text-muted-foreground text-sm"> <p className="text-muted-foreground text-sm">
"{componentId || componentType}" . &quot;{fallbackId || componentType}&quot; .
</p> </p>
</div> </div>
); );
}
}; };
// 기본 정보 탭 // 기본 정보 탭

View File

@ -73,7 +73,6 @@ const CONFIG_PANEL_MAP: Record<string, () => Promise<any>> = {
"v2-repeat-container": () => import("@/lib/registry/components/v2-repeat-container/RepeatContainerConfigPanel"), "v2-repeat-container": () => import("@/lib/registry/components/v2-repeat-container/RepeatContainerConfigPanel"),
"repeater-field-group": () => import("@/components/webtypes/config/RepeaterConfigPanel"), "repeater-field-group": () => import("@/components/webtypes/config/RepeaterConfigPanel"),
"v2-repeater": () => import("@/components/v2/config-panels/V2RepeaterConfigPanel"), "v2-repeater": () => import("@/components/v2/config-panels/V2RepeaterConfigPanel"),
"v2-repeater": () => import("@/components/v2/config-panels/V2RepeaterConfigPanel"),
"simple-repeater-table": () => import("@/lib/registry/components/simple-repeater-table/SimpleRepeaterTableConfigPanel"), "simple-repeater-table": () => import("@/lib/registry/components/simple-repeater-table/SimpleRepeaterTableConfigPanel"),
"modal-repeater-table": () => import("@/lib/registry/components/modal-repeater-table/ModalRepeaterTableConfigPanel"), "modal-repeater-table": () => import("@/lib/registry/components/modal-repeater-table/ModalRepeaterTableConfigPanel"),
"repeat-screen-modal": () => import("@/lib/registry/components/repeat-screen-modal/RepeatScreenModalConfigPanel"), "repeat-screen-modal": () => import("@/lib/registry/components/repeat-screen-modal/RepeatScreenModalConfigPanel"),
@ -104,6 +103,24 @@ const CONFIG_PANEL_MAP: Record<string, () => Promise<any>> = {
"category-manager": () => import("@/lib/registry/components/category-manager/CategoryManagerConfigPanel"), "category-manager": () => import("@/lib/registry/components/category-manager/CategoryManagerConfigPanel"),
"universal-form-modal": () => import("@/lib/registry/components/universal-form-modal/UniversalFormModalConfigPanel"), "universal-form-modal": () => import("@/lib/registry/components/universal-form-modal/UniversalFormModalConfigPanel"),
"v2-process-work-standard": () => import("@/lib/registry/components/v2-process-work-standard/ProcessWorkStandardConfigPanel"), "v2-process-work-standard": () => import("@/lib/registry/components/v2-process-work-standard/ProcessWorkStandardConfigPanel"),
// ========== V2 BOM 컴포넌트 ==========
"v2-bom-item-editor": () => import("@/components/v2/config-panels/V2BomItemEditorConfigPanel"),
"v2-bom-tree": () => import("@/components/v2/config-panels/V2BomTreeConfigPanel"),
// ========== 레거시 위젯 (component/onUpdateProperty props 사용) ==========
"card": () => import("@/components/screen/config-panels/CardConfigPanel"),
"dashboard": () => import("@/components/screen/config-panels/DashboardConfigPanel"),
"stats": () => import("@/components/screen/config-panels/StatsCardConfigPanel"),
"stats-card": () => import("@/components/screen/config-panels/StatsCardConfigPanel"),
"progress": () => import("@/components/screen/config-panels/ProgressBarConfigPanel"),
"progress-bar": () => import("@/components/screen/config-panels/ProgressBarConfigPanel"),
"chart": () => import("@/components/screen/config-panels/ChartConfigPanel"),
"chart-basic": () => import("@/components/screen/config-panels/ChartConfigPanel"),
"alert": () => import("@/components/screen/config-panels/AlertConfigPanel"),
"alert-info": () => import("@/components/screen/config-panels/AlertConfigPanel"),
"badge": () => import("@/components/screen/config-panels/BadgeConfigPanel"),
"badge-status": () => import("@/components/screen/config-panels/BadgeConfigPanel"),
}; };
// ConfigPanel 컴포넌트 캐시 // ConfigPanel 컴포넌트 캐시
@ -128,60 +145,30 @@ export async function getComponentConfigPanel(componentId: string): Promise<Reac
try { try {
const module = await importFn(); const module = await importFn();
// 모듈에서 ConfigPanel 컴포넌트 추출 // 모듈에서 ConfigPanel 컴포넌트 추출 (우선순위):
// 1차: PascalCase 변환된 이름으로 찾기 (예: text-input -> TextInputConfigPanel) // 1차: PascalCase 변환된 이름 (예: text-input -> TextInputConfigPanel)
// 2차: v2- 접두사 제거 후 PascalCase 이름으로 찾기 (예: v2-table-list -> TableListConfigPanel) // 2차: v2- 접두사 제거 후 PascalCase (예: v2-table-list -> TableListConfigPanel)
// 3차: 특수 export명들 fallback // 3차: *ConfigPanel로 끝나는 첫 번째 named export
// 4차: default export // 4차: default export
const pascalCaseName = `${toPascalCase(componentId)}ConfigPanel`; const pascalCaseName = `${toPascalCase(componentId)}ConfigPanel`;
// v2- 접두사가 있는 경우 접두사를 제거한 이름도 시도 // v2- 접두사가 있는 경우 접두사를 제거한 이름도 시도
const baseComponentId = componentId.startsWith("v2-") ? componentId.slice(3) : componentId; const baseComponentId = componentId.startsWith("v2-") ? componentId.slice(3) : componentId;
const basePascalCaseName = `${toPascalCase(baseComponentId)}ConfigPanel`; const basePascalCaseName = `${toPascalCase(baseComponentId)}ConfigPanel`;
// 모듈에서 ConfigPanel로 끝나는 첫 번째 named export를 찾는 fallback
const findConfigPanelExport = () => {
for (const key of Object.keys(module)) {
if (key.endsWith("ConfigPanel") && typeof module[key] === "function") {
return module[key];
}
}
return null;
};
const ConfigPanelComponent = const ConfigPanelComponent =
module[pascalCaseName] || module[pascalCaseName] ||
module[basePascalCaseName] || module[basePascalCaseName] ||
// 특수 export명들 findConfigPanelExport() ||
module.RepeaterConfigPanel ||
module.FlowWidgetConfigPanel ||
module.CustomerItemMappingConfigPanel ||
module.SelectedItemsDetailInputConfigPanel ||
module.ButtonConfigPanel ||
module.TableListConfigPanel ||
module.SectionCardConfigPanel ||
module.SectionPaperConfigPanel ||
module.TabsConfigPanel ||
module.V2RepeaterConfigPanel ||
module.V2InputConfigPanel ||
module.V2SelectConfigPanel ||
module.V2DateConfigPanel ||
module.V2ListConfigPanel ||
module.V2MediaConfigPanel ||
module.V2BizConfigPanel ||
module.V2GroupConfigPanel ||
module.V2HierarchyConfigPanel ||
module.V2LayoutConfigPanel ||
module.RepeatContainerConfigPanel ||
module.ScreenSplitPanelConfigPanel ||
module.SimpleRepeaterTableConfigPanel ||
module.ModalRepeaterTableConfigPanel ||
module.RepeatScreenModalConfigPanel ||
module.RelatedDataButtonsConfigPanel ||
module.AutocompleteSearchInputConfigPanel ||
module.EntitySearchInputConfigPanel ||
module.MailRecipientSelectorConfigPanel ||
module.LocationSwapSelectorConfigPanel ||
module.MapConfigPanel ||
module.RackStructureConfigPanel ||
module.AggregationWidgetConfigPanel ||
module.NumberingRuleConfigPanel ||
module.CategoryManagerConfigPanel ||
module.UniversalFormModalConfigPanel ||
module.PivotGridConfigPanel ||
module.TableSearchWidgetConfigPanel ||
module.TaxInvoiceListConfigPanel ||
module.ImageWidgetConfigPanel ||
module.TestInputConfigPanel ||
module.default; module.default;
if (!ConfigPanelComponent) { if (!ConfigPanelComponent) {
@ -522,6 +509,33 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
} }
}; };
// 레거시 위젯 패널 (component/onUpdateProperty props 사용)
const LEGACY_PANELS = new Set([
"card", "dashboard", "stats", "stats-card",
"progress", "progress-bar", "chart", "chart-basic",
"alert", "alert-info", "badge", "badge-status",
]);
if (LEGACY_PANELS.has(componentId)) {
const pseudoComponent = {
id: currentComponent?.id || "temp",
type: "component",
componentConfig: config,
...currentComponent,
};
return (
<ConfigPanelComponent
component={pseudoComponent}
onUpdateProperty={(path: string, value: any) => {
if (path.startsWith("componentConfig.")) {
const key = path.replace("componentConfig.", "");
onChange({ ...config, [key]: value });
}
}}
/>
);
}
// 🆕 수주 등록 관련 컴포넌트들은 간단한 인터페이스 사용 // 🆕 수주 등록 관련 컴포넌트들은 간단한 인터페이스 사용
const isSimpleConfigPanel = [ const isSimpleConfigPanel = [
"autocomplete-search-input", "autocomplete-search-input",