[agent-pipeline] pipe-20260311052455-y968 round-2
This commit is contained in:
parent
b329b52036
commit
d358de60d6
|
|
@ -54,3 +54,27 @@ export interface ConfigPanelBuilderProps<T = any> {
|
|||
tableColumns?: ConfigOption[];
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 설정 패널에 전달되는 화면/컴포넌트 컨텍스트 정보
|
||||
*/
|
||||
export interface ConfigPanelContext {
|
||||
tables?: any[];
|
||||
tableColumns?: any[];
|
||||
screenTableName?: string;
|
||||
menuObjid?: number;
|
||||
allComponents?: any[];
|
||||
currentComponent?: any;
|
||||
allTables?: any[];
|
||||
screenComponents?: any[];
|
||||
currentScreenCompanyCode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 모든 ConfigPanel이 공통으로 받는 표준 Props
|
||||
*/
|
||||
export interface StandardConfigPanelProps {
|
||||
config: Record<string, any>;
|
||||
onChange: (config: Record<string, any>) => void;
|
||||
context?: ConfigPanelContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import type { ConfigPanelContext } from "@/lib/registry/components/common/ConfigPanelTypes";
|
||||
|
||||
// 컴포넌트별 ConfigPanel 동적 import 맵
|
||||
// 모든 ConfigPanel이 있는 컴포넌트를 여기에 등록해야 슬롯/중첩 컴포넌트에서 전용 설정 패널이 표시됨
|
||||
const CONFIG_PANEL_MAP: Record<string, () => Promise<any>> = {
|
||||
// ========== V2 컴포넌트 ==========
|
||||
"v2-input": () => import("@/components/v2/config-panels/V2InputConfigPanel"),
|
||||
|
|
@ -123,22 +123,18 @@ const CONFIG_PANEL_MAP: Record<string, () => Promise<any>> = {
|
|||
"badge-status": () => import("@/components/screen/config-panels/BadgeConfigPanel"),
|
||||
};
|
||||
|
||||
// ConfigPanel 컴포넌트 캐시
|
||||
const configPanelCache = new Map<string, React.ComponentType<any>>();
|
||||
|
||||
/**
|
||||
* 컴포넌트 ID로 ConfigPanel 컴포넌트를 동적으로 로드
|
||||
*/
|
||||
export async function getComponentConfigPanel(componentId: string): Promise<React.ComponentType<any> | null> {
|
||||
// 캐시에서 먼저 확인
|
||||
if (configPanelCache.has(componentId)) {
|
||||
return configPanelCache.get(componentId)!;
|
||||
}
|
||||
|
||||
// 매핑에서 import 함수 찾기
|
||||
const importFn = CONFIG_PANEL_MAP[componentId];
|
||||
if (!importFn) {
|
||||
console.warn(`컴포넌트 "${componentId}"에 대한 ConfigPanel을 찾을 수 없습니다.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -151,11 +147,9 @@ export async function getComponentConfigPanel(componentId: string): Promise<Reac
|
|||
// 3차: *ConfigPanel로 끝나는 첫 번째 named export
|
||||
// 4차: default export
|
||||
const pascalCaseName = `${toPascalCase(componentId)}ConfigPanel`;
|
||||
// v2- 접두사가 있는 경우 접두사를 제거한 이름도 시도
|
||||
const baseComponentId = componentId.startsWith("v2-") ? componentId.slice(3) : componentId;
|
||||
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") {
|
||||
|
|
@ -176,9 +170,7 @@ export async function getComponentConfigPanel(componentId: string): Promise<Reac
|
|||
return null;
|
||||
}
|
||||
|
||||
// 캐시에 저장
|
||||
configPanelCache.set(componentId, ConfigPanelComponent);
|
||||
|
||||
return ConfigPanelComponent;
|
||||
} catch (error) {
|
||||
console.error(`컴포넌트 "${componentId}"의 ConfigPanel 로드 실패:`, error);
|
||||
|
|
@ -186,24 +178,14 @@ export async function getComponentConfigPanel(componentId: string): Promise<Reac
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 컴포넌트 ID가 ConfigPanel을 지원하는지 확인
|
||||
*/
|
||||
export function hasComponentConfigPanel(componentId: string): boolean {
|
||||
return componentId in CONFIG_PANEL_MAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* 지원되는 모든 컴포넌트 ID 목록 조회
|
||||
*/
|
||||
export function getSupportedConfigPanelComponents(): string[] {
|
||||
return Object.keys(CONFIG_PANEL_MAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* kebab-case를 PascalCase로 변환
|
||||
* text-input → TextInput
|
||||
*/
|
||||
function toPascalCase(str: string): string {
|
||||
return str
|
||||
.split("-")
|
||||
|
|
@ -218,12 +200,12 @@ export interface ComponentConfigPanelProps {
|
|||
componentId: string;
|
||||
config: Record<string, any>;
|
||||
onChange: (config: Record<string, any>) => void;
|
||||
screenTableName?: string; // 화면에서 지정한 테이블명
|
||||
tableColumns?: any[]; // 테이블 컬럼 정보
|
||||
tables?: any[]; // 전체 테이블 목록
|
||||
menuObjid?: number; // 🆕 메뉴 OBJID (코드/카테고리/채번규칙 스코프용)
|
||||
allComponents?: any[]; // 🆕 현재 화면의 모든 컴포넌트 (연쇄 드롭다운 부모 감지용)
|
||||
currentComponent?: any; // 🆕 현재 컴포넌트 정보
|
||||
screenTableName?: string;
|
||||
tableColumns?: any[];
|
||||
tables?: any[];
|
||||
menuObjid?: number;
|
||||
allComponents?: any[];
|
||||
currentComponent?: any;
|
||||
}
|
||||
|
||||
export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> = ({
|
||||
|
|
@ -237,53 +219,41 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
|
|||
allComponents,
|
||||
currentComponent,
|
||||
}) => {
|
||||
// 모든 useState를 최상단에 선언 (Hooks 규칙)
|
||||
const [ConfigPanelComponent, setConfigPanelComponent] = React.useState<React.ComponentType<any> | null>(null);
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
const [selectedTableColumns, setSelectedTableColumns] = React.useState(tableColumns);
|
||||
const [allTablesList, setAllTablesList] = React.useState<any[]>([]);
|
||||
|
||||
// 🆕 selected-items-detail-input 전용 상태
|
||||
const [sourceTableColumns, setSourceTableColumns] = React.useState<any[]>([]);
|
||||
const [targetTableColumns, setTargetTableColumns] = React.useState<any[]>([]);
|
||||
|
||||
React.useEffect(() => {
|
||||
let mounted = true;
|
||||
|
||||
async function loadConfigPanel() {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const component = await getComponentConfigPanel(componentId);
|
||||
|
||||
if (mounted) {
|
||||
setConfigPanelComponent(() => component);
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`❌ DynamicComponentConfigPanel: ${componentId} 로드 실패:`, err);
|
||||
if (mounted) {
|
||||
setError(err instanceof Error ? err.message : String(err));
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadConfigPanel();
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
return () => { mounted = false; };
|
||||
}, [componentId]);
|
||||
|
||||
// tableColumns가 변경되면 selectedTableColumns도 업데이트
|
||||
React.useEffect(() => {
|
||||
setSelectedTableColumns(tableColumns);
|
||||
}, [tableColumns]);
|
||||
|
||||
// RepeaterConfigPanel과 selected-items-detail-input에서 전체 테이블 목록 로드
|
||||
// repeater-field-group / selected-items-detail-input에서 전체 테이블 목록 로드
|
||||
React.useEffect(() => {
|
||||
if (componentId === "repeater-field-group" || componentId === "selected-items-detail-input") {
|
||||
const loadAllTables = async () => {
|
||||
|
|
@ -291,100 +261,57 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
|
|||
const { tableManagementApi } = await import("@/lib/api/tableManagement");
|
||||
const response = await tableManagementApi.getTableList();
|
||||
if (response.success && response.data) {
|
||||
console.log(`✅ 전체 테이블 목록 로드 완료 (${componentId}):`, response.data.length);
|
||||
setAllTablesList(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("전체 테이블 목록 로드 실패:", error);
|
||||
} catch (_) {
|
||||
// 전체 테이블 목록 로드 실패 시 무시
|
||||
}
|
||||
};
|
||||
loadAllTables();
|
||||
}
|
||||
}, [componentId]);
|
||||
|
||||
// 🆕 selected-items-detail-input: 초기 sourceTable/targetTable 컬럼 로드
|
||||
// selected-items-detail-input: 초기 sourceTable/targetTable 컬럼 로드
|
||||
React.useEffect(() => {
|
||||
if (componentId === "selected-items-detail-input") {
|
||||
console.log("🔍 selected-items-detail-input 초기 설정:", config);
|
||||
|
||||
// 원본 테이블 컬럼 로드
|
||||
if (config.sourceTable) {
|
||||
const loadSourceColumns = async () => {
|
||||
try {
|
||||
const { tableTypeApi } = await import("@/lib/api/screen");
|
||||
const columnsResponse = await tableTypeApi.getColumns(config.sourceTable);
|
||||
if (componentId !== "selected-items-detail-input") return;
|
||||
|
||||
const columns = (columnsResponse || []).map((col: any) => ({
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||||
dataType: col.dataType || col.data_type || col.dbType,
|
||||
inputType: col.inputType || col.input_type, // 🆕 inputType 추가
|
||||
}));
|
||||
|
||||
console.log("✅ 원본 테이블 컬럼 초기 로드 완료:", columns.length);
|
||||
setSourceTableColumns(columns);
|
||||
} catch (error) {
|
||||
console.error("❌ 원본 테이블 컬럼 초기 로드 실패:", error);
|
||||
}
|
||||
};
|
||||
loadSourceColumns();
|
||||
const loadColumns = async (tableName: string, setter: React.Dispatch<React.SetStateAction<any[]>>, includeCodeCategory?: boolean) => {
|
||||
try {
|
||||
const { tableTypeApi } = await import("@/lib/api/screen");
|
||||
const columnsResponse = await tableTypeApi.getColumns(tableName);
|
||||
const columns = (columnsResponse || []).map((col: any) => ({
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||||
dataType: col.dataType || col.data_type || col.dbType,
|
||||
inputType: col.inputType || col.input_type,
|
||||
...(includeCodeCategory ? { codeCategory: col.codeCategory || col.code_category } : {}),
|
||||
}));
|
||||
setter(columns);
|
||||
} catch (_) {
|
||||
setter([]);
|
||||
}
|
||||
|
||||
// 대상 테이블 컬럼 로드
|
||||
if (config.targetTable) {
|
||||
const loadTargetColumns = async () => {
|
||||
try {
|
||||
const { tableTypeApi } = await import("@/lib/api/screen");
|
||||
const columnsResponse = await tableTypeApi.getColumns(config.targetTable);
|
||||
};
|
||||
|
||||
const columns = (columnsResponse || []).map((col: any) => ({
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||||
dataType: col.dataType || col.data_type || col.dbType,
|
||||
inputType: col.inputType || col.input_type, // 🆕 inputType 추가
|
||||
codeCategory: col.codeCategory || col.code_category, // 🆕 codeCategory 추가
|
||||
}));
|
||||
|
||||
console.log("✅ 대상 테이블 컬럼 초기 로드 완료:", columns.length);
|
||||
setTargetTableColumns(columns);
|
||||
} catch (error) {
|
||||
console.error("❌ 대상 테이블 컬럼 초기 로드 실패:", error);
|
||||
}
|
||||
};
|
||||
loadTargetColumns();
|
||||
}
|
||||
}
|
||||
if (config.sourceTable) loadColumns(config.sourceTable, setSourceTableColumns);
|
||||
if (config.targetTable) loadColumns(config.targetTable, setTargetTableColumns, true);
|
||||
}, [componentId, config.sourceTable, config.targetTable]);
|
||||
|
||||
// 🆕 allComponents를 screenComponents 형태로 변환 (집계 위젯 등에서 사용)
|
||||
// Hooks 규칙: 조건부 return 전에 선언해야 함
|
||||
const screenComponents = React.useMemo(() => {
|
||||
if (!allComponents) {
|
||||
console.log("[getComponentConfigPanel] allComponents is undefined or null");
|
||||
return [];
|
||||
}
|
||||
console.log("[getComponentConfigPanel] allComponents 변환 시작:", allComponents.length, "개");
|
||||
const result = allComponents.map((comp: any) => {
|
||||
const columnName = comp.columnName || comp.componentConfig?.columnName || comp.componentConfig?.fieldName;
|
||||
console.log(`[getComponentConfigPanel] comp: ${comp.id}, type: ${comp.componentType || comp.type}, columnName: ${columnName}`);
|
||||
return {
|
||||
id: comp.id,
|
||||
componentType: comp.componentType || comp.type,
|
||||
label: comp.label || comp.name || comp.id,
|
||||
tableName: comp.componentConfig?.tableName || comp.tableName,
|
||||
// 🆕 폼 필드 인식용 columnName 추가
|
||||
columnName,
|
||||
};
|
||||
});
|
||||
console.log("[getComponentConfigPanel] screenComponents 변환 완료:", result);
|
||||
return result;
|
||||
if (!allComponents) return [];
|
||||
return allComponents.map((comp: any) => ({
|
||||
id: comp.id,
|
||||
componentType: comp.componentType || comp.type,
|
||||
label: comp.label || comp.name || comp.id,
|
||||
tableName: comp.componentConfig?.tableName || comp.tableName,
|
||||
columnName: comp.columnName || comp.componentConfig?.columnName || comp.componentConfig?.fieldName,
|
||||
}));
|
||||
}, [allComponents]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="rounded-md border border-dashed border-input bg-muted p-4 w-full">
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<span className="text-sm font-medium">⏳ 로딩 중...</span>
|
||||
<span className="text-sm font-medium">로딩 중...</span>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-muted-foreground">설정 패널을 불러오는 중입니다.</p>
|
||||
</div>
|
||||
|
|
@ -395,7 +322,7 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
|
|||
return (
|
||||
<div className="rounded-md border border-dashed border-destructive/30 bg-destructive/10 p-4 w-full">
|
||||
<div className="flex items-center gap-2 text-destructive">
|
||||
<span className="text-sm font-medium">⚠️ 로드 실패</span>
|
||||
<span className="text-sm font-medium">로드 실패</span>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-destructive">설정 패널을 불러올 수 없습니다: {error}</p>
|
||||
</div>
|
||||
|
|
@ -403,31 +330,26 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
|
|||
}
|
||||
|
||||
if (!ConfigPanelComponent) {
|
||||
console.warn(`⚠️ DynamicComponentConfigPanel: ${componentId} ConfigPanelComponent가 null`);
|
||||
return (
|
||||
<div className="rounded-md border border-dashed border-amber-300 bg-amber-50 p-4 w-full">
|
||||
<div className="flex items-center gap-2 text-amber-600">
|
||||
<span className="text-sm font-medium">⚠️ 설정 패널 없음</span>
|
||||
<span className="text-sm font-medium">설정 패널 없음</span>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-amber-500">컴포넌트 "{componentId}"에 대한 설정 패널이 없습니다.</p>
|
||||
<p className="mt-1 text-xs text-amber-500">컴포넌트 "{componentId}"에 대한 설정 패널이 없습니다.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 테이블 변경 핸들러 - 선택된 테이블의 컬럼을 동적으로 로드
|
||||
// 테이블 변경 핸들러
|
||||
const handleTableChange = async (tableName: string) => {
|
||||
try {
|
||||
// 먼저 tables에서 찾아보기 (이미 컬럼이 있는 경우)
|
||||
const existingTable = tables?.find((t) => t.tableName === tableName);
|
||||
if (existingTable && existingTable.columns && existingTable.columns.length > 0) {
|
||||
if (existingTable?.columns?.length > 0) {
|
||||
setSelectedTableColumns(existingTable.columns);
|
||||
return;
|
||||
}
|
||||
|
||||
// 컬럼이 없으면 tableTypeApi로 조회 (ScreenDesigner와 동일한 방식)
|
||||
const { tableTypeApi } = await import("@/lib/api/screen");
|
||||
const columnsResponse = await tableTypeApi.getColumns(tableName);
|
||||
|
||||
const columns = (columnsResponse || []).map((col: any) => ({
|
||||
tableName: col.tableName || tableName,
|
||||
columnName: col.columnName || col.column_name,
|
||||
|
|
@ -443,73 +365,46 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
|
|||
codeCategory: col.codeCategory || col.code_category,
|
||||
codeValue: col.codeValue || col.code_value,
|
||||
}));
|
||||
|
||||
setSelectedTableColumns(columns);
|
||||
} catch (error) {
|
||||
console.error("❌ 테이블 변경 오류:", error);
|
||||
// 오류 발생 시 빈 배열
|
||||
} catch (_) {
|
||||
setSelectedTableColumns([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 🆕 원본 테이블 컬럼 로드 핸들러 (selected-items-detail-input용)
|
||||
const handleSourceTableChange = async (tableName: string) => {
|
||||
console.log("🔄 원본 테이블 변경:", tableName);
|
||||
try {
|
||||
const { tableTypeApi } = await import("@/lib/api/screen");
|
||||
const columnsResponse = await tableTypeApi.getColumns(tableName);
|
||||
|
||||
const columns = (columnsResponse || []).map((col: any) => ({
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||||
dataType: col.dataType || col.data_type || col.dbType,
|
||||
inputType: col.inputType || col.input_type, // 🆕 inputType 추가
|
||||
inputType: col.inputType || col.input_type,
|
||||
}));
|
||||
|
||||
console.log("✅ 원본 테이블 컬럼 로드 완료:", columns.length);
|
||||
setSourceTableColumns(columns);
|
||||
} catch (error) {
|
||||
console.error("❌ 원본 테이블 컬럼 로드 실패:", error);
|
||||
} catch (_) {
|
||||
setSourceTableColumns([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 🆕 대상 테이블 컬럼 로드 핸들러 (selected-items-detail-input용)
|
||||
const handleTargetTableChange = async (tableName: string) => {
|
||||
console.log("🔄 대상 테이블 변경:", tableName);
|
||||
try {
|
||||
const { tableTypeApi } = await import("@/lib/api/screen");
|
||||
const columnsResponse = await tableTypeApi.getColumns(tableName);
|
||||
|
||||
console.log("📡 [handleTargetTableChange] API 응답 (원본):", {
|
||||
totalColumns: columnsResponse.length,
|
||||
sampleColumns: columnsResponse.slice(0, 3),
|
||||
currency_code_raw: columnsResponse.find((c: any) => (c.columnName || c.column_name) === 'currency_code')
|
||||
});
|
||||
|
||||
const columns = (columnsResponse || []).map((col: any) => ({
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||||
dataType: col.dataType || col.data_type || col.dbType,
|
||||
inputType: col.inputType || col.input_type, // 🆕 inputType 추가
|
||||
codeCategory: col.codeCategory || col.code_category, // 🆕 codeCategory 추가
|
||||
inputType: col.inputType || col.input_type,
|
||||
codeCategory: col.codeCategory || col.code_category,
|
||||
}));
|
||||
|
||||
console.log("✅ 대상 테이블 컬럼 변환 완료:", {
|
||||
tableName,
|
||||
totalColumns: columns.length,
|
||||
currency_code: columns.find((c: any) => c.columnName === "currency_code"),
|
||||
discount_rate: columns.find((c: any) => c.columnName === "discount_rate")
|
||||
});
|
||||
|
||||
setTargetTableColumns(columns);
|
||||
} catch (error) {
|
||||
console.error("❌ 대상 테이블 컬럼 로드 실패:", error);
|
||||
} catch (_) {
|
||||
setTargetTableColumns([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 레거시 위젯 패널 (component/onUpdateProperty props 사용)
|
||||
// --- 특수 래퍼: 레거시 위젯 (component/onUpdateProperty props) ---
|
||||
const LEGACY_PANELS = new Set([
|
||||
"card", "dashboard", "stats", "stats-card",
|
||||
"progress", "progress-bar", "chart", "chart-basic",
|
||||
|
|
@ -536,94 +431,31 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
|
|||
);
|
||||
}
|
||||
|
||||
// 🆕 수주 등록 관련 컴포넌트들은 간단한 인터페이스 사용
|
||||
const isSimpleConfigPanel = [
|
||||
"autocomplete-search-input",
|
||||
"modal-repeater-table",
|
||||
"conditional-container",
|
||||
].includes(componentId);
|
||||
|
||||
if (isSimpleConfigPanel) {
|
||||
return <ConfigPanelComponent config={config} onConfigChange={onChange} />;
|
||||
}
|
||||
|
||||
// 🆕 V2 컴포넌트들은 전용 props 사용
|
||||
if (componentId.startsWith("v2-")) {
|
||||
return (
|
||||
<ConfigPanelComponent
|
||||
config={config}
|
||||
onChange={onChange}
|
||||
menuObjid={menuObjid}
|
||||
inputType={currentComponent?.inputType || config?.inputType}
|
||||
screenTableName={screenTableName}
|
||||
tableColumns={selectedTableColumns}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// entity-search-input은 currentComponent 정보 필요 (참조 테이블 자동 로드용)
|
||||
// 그리고 allComponents 필요 (연쇄관계 부모 필드 선택용)
|
||||
if (componentId === "entity-search-input") {
|
||||
return (
|
||||
<ConfigPanelComponent
|
||||
config={config}
|
||||
onConfigChange={onChange}
|
||||
currentComponent={currentComponent}
|
||||
allComponents={allComponents}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// 🆕 selected-items-detail-input은 특별한 props 사용
|
||||
if (componentId === "selected-items-detail-input") {
|
||||
return (
|
||||
<ConfigPanelComponent
|
||||
config={config}
|
||||
onChange={onChange}
|
||||
sourceTableColumns={sourceTableColumns} // 🆕 원본 테이블 컬럼
|
||||
targetTableColumns={targetTableColumns} // 🆕 대상 테이블 컬럼
|
||||
allTables={allTablesList.length > 0 ? allTablesList : tables} // 전체 테이블 목록 (동적 로드 or 전달된 목록)
|
||||
screenTableName={screenTableName} // 🆕 현재 화면의 테이블명 (자동 설정용)
|
||||
onSourceTableChange={handleSourceTableChange} // 🆕 원본 테이블 변경 핸들러
|
||||
onTargetTableChange={handleTargetTableChange} // 🆕 대상 테이블 변경 핸들러
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// 🆕 ButtonConfigPanel은 component와 onUpdateProperty를 사용
|
||||
// --- 특수 래퍼: ButtonConfigPanel (component/onUpdateProperty props) ---
|
||||
if (componentId === "button-primary" || componentId === "v2-button-primary") {
|
||||
// currentComponent가 있으면 그것을 사용, 없으면 config에서 component 구조 생성
|
||||
const componentForButton = currentComponent || {
|
||||
id: "temp",
|
||||
type: "component",
|
||||
componentType: componentId,
|
||||
componentConfig: config,
|
||||
};
|
||||
|
||||
return (
|
||||
<ConfigPanelComponent
|
||||
component={componentForButton}
|
||||
onUpdateProperty={(path: string, value: any) => {
|
||||
// path가 componentConfig로 시작하면 내부 경로 추출
|
||||
if (path.startsWith("componentConfig.")) {
|
||||
const configPath = path.replace("componentConfig.", "");
|
||||
const pathParts = configPath.split(".");
|
||||
|
||||
// 중첩된 경로 처리 - 현재 config를 기반으로 새 config 생성
|
||||
const currentConfig = componentForButton.componentConfig || {};
|
||||
const newConfig = JSON.parse(JSON.stringify(currentConfig)); // deep clone
|
||||
const newConfig = JSON.parse(JSON.stringify(currentConfig));
|
||||
let current: any = newConfig;
|
||||
for (let i = 0; i < pathParts.length - 1; i++) {
|
||||
if (!current[pathParts[i]]) {
|
||||
current[pathParts[i]] = {};
|
||||
}
|
||||
if (!current[pathParts[i]]) current[pathParts[i]] = {};
|
||||
current = current[pathParts[i]];
|
||||
}
|
||||
current[pathParts[pathParts.length - 1]] = value;
|
||||
|
||||
onChange(newConfig);
|
||||
} else {
|
||||
// 직접 config 속성 변경
|
||||
const currentConfig = componentForButton.componentConfig || {};
|
||||
onChange({ ...currentConfig, [path]: value });
|
||||
}
|
||||
|
|
@ -634,20 +466,38 @@ export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> =
|
|||
);
|
||||
}
|
||||
|
||||
// --- 통일된 props: 모든 일반 패널에 동일한 props 전달 ---
|
||||
const context: ConfigPanelContext = {
|
||||
tables,
|
||||
tableColumns: selectedTableColumns,
|
||||
screenTableName,
|
||||
menuObjid,
|
||||
allComponents,
|
||||
currentComponent,
|
||||
allTables: allTablesList.length > 0 ? allTablesList : tables,
|
||||
screenComponents,
|
||||
};
|
||||
|
||||
return (
|
||||
<ConfigPanelComponent
|
||||
config={config}
|
||||
onChange={onChange}
|
||||
onConfigChange={onChange} // TableListConfigPanel을 위한 추가 prop
|
||||
onConfigChange={onChange}
|
||||
context={context}
|
||||
screenTableName={screenTableName}
|
||||
tableColumns={selectedTableColumns} // 동적으로 변경되는 컬럼 전달
|
||||
tables={tables} // 기본 테이블 목록 (현재 화면의 테이블만)
|
||||
allTables={componentId === "repeater-field-group" ? allTablesList : tables} // RepeaterConfigPanel만 전체 테이블
|
||||
onTableChange={handleTableChange} // 테이블 변경 핸들러 전달
|
||||
menuObjid={menuObjid} // 🆕 메뉴 OBJID 전달
|
||||
allComponents={allComponents} // 🆕 현재 화면의 모든 컴포넌트 (연쇄 드롭다운 부모 감지용)
|
||||
currentComponent={currentComponent} // 🆕 현재 컴포넌트 정보
|
||||
screenComponents={screenComponents} // 🆕 집계 위젯 등에서 사용하는 컴포넌트 목록
|
||||
tableColumns={selectedTableColumns}
|
||||
tables={tables}
|
||||
allTables={allTablesList.length > 0 ? allTablesList : tables}
|
||||
onTableChange={handleTableChange}
|
||||
menuObjid={menuObjid}
|
||||
allComponents={allComponents}
|
||||
currentComponent={currentComponent}
|
||||
screenComponents={screenComponents}
|
||||
inputType={currentComponent?.inputType || config?.inputType}
|
||||
sourceTableColumns={sourceTableColumns}
|
||||
targetTableColumns={targetTableColumns}
|
||||
onSourceTableChange={handleSourceTableChange}
|
||||
onTargetTableChange={handleTargetTableChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue