521 lines
23 KiB
TypeScript
521 lines
23 KiB
TypeScript
/**
|
||
* 컴포넌트 ID로 해당 컴포넌트의 ConfigPanel을 동적으로 로드하는 유틸리티
|
||
*/
|
||
|
||
import React from "react";
|
||
|
||
// 컴포넌트별 ConfigPanel 동적 import 맵
|
||
// 모든 ConfigPanel이 있는 컴포넌트를 여기에 등록해야 슬롯/중첩 컴포넌트에서 전용 설정 패널이 표시됨
|
||
const CONFIG_PANEL_MAP: Record<string, () => Promise<any>> = {
|
||
// ========== 기본 입력 컴포넌트 ==========
|
||
"text-input": () => import("@/lib/registry/components/text-input/TextInputConfigPanel"),
|
||
"number-input": () => import("@/lib/registry/components/number-input/NumberInputConfigPanel"),
|
||
"date-input": () => import("@/lib/registry/components/date-input/DateInputConfigPanel"),
|
||
"textarea-basic": () => import("@/lib/registry/components/textarea-basic/TextareaBasicConfigPanel"),
|
||
"select-basic": () => import("@/lib/registry/components/select-basic/SelectBasicConfigPanel"),
|
||
"checkbox-basic": () => import("@/lib/registry/components/checkbox-basic/CheckboxBasicConfigPanel"),
|
||
"radio-basic": () => import("@/lib/registry/components/radio-basic/RadioBasicConfigPanel"),
|
||
"toggle-switch": () => import("@/lib/registry/components/toggle-switch/ToggleSwitchConfigPanel"),
|
||
"file-upload": () => import("@/lib/registry/components/file-upload/FileUploadConfigPanel"),
|
||
"slider-basic": () => import("@/lib/registry/components/slider-basic/SliderBasicConfigPanel"),
|
||
"test-input": () => import("@/lib/registry/components/test-input/TestInputConfigPanel"),
|
||
|
||
// ========== 버튼 ==========
|
||
"button-primary": () => import("@/components/screen/config-panels/ButtonConfigPanel"),
|
||
|
||
// ========== 표시 컴포넌트 ==========
|
||
"text-display": () => import("@/lib/registry/components/text-display/TextDisplayConfigPanel"),
|
||
"image-display": () => import("@/lib/registry/components/image-display/ImageDisplayConfigPanel"),
|
||
"divider-line": () => import("@/lib/registry/components/divider-line/DividerLineConfigPanel"),
|
||
"image-widget": () => import("@/lib/registry/components/image-widget/ImageWidgetConfigPanel"),
|
||
|
||
// ========== 레이아웃/컨테이너 ==========
|
||
"accordion-basic": () => import("@/lib/registry/components/accordion-basic/AccordionBasicConfigPanel"),
|
||
"card-display": () => import("@/lib/registry/components/card-display/CardDisplayConfigPanel"),
|
||
"section-card": () => import("@/lib/registry/components/section-card/SectionCardConfigPanel"),
|
||
"section-paper": () => import("@/lib/registry/components/section-paper/SectionPaperConfigPanel"),
|
||
"split-panel-layout": () => import("@/lib/registry/components/split-panel-layout/SplitPanelLayoutConfigPanel"),
|
||
"split-panel-layout2": () => import("@/lib/registry/components/split-panel-layout2/SplitPanelLayout2ConfigPanel"),
|
||
"screen-split-panel": () => import("@/lib/registry/components/screen-split-panel/ScreenSplitPanelConfigPanel"),
|
||
"conditional-container": () => import("@/lib/registry/components/conditional-container/ConditionalContainerConfigPanel"),
|
||
|
||
// ========== 테이블/리스트 ==========
|
||
"table-list": () => import("@/lib/registry/components/table-list/TableListConfigPanel"),
|
||
"pivot-grid": () => import("@/lib/registry/components/pivot-grid/PivotGridConfigPanel"),
|
||
"table-search-widget": () => import("@/lib/registry/components/table-search-widget/TableSearchWidgetConfigPanel"),
|
||
"tax-invoice-list": () => import("@/lib/registry/components/tax-invoice-list/TaxInvoiceListConfigPanel"),
|
||
|
||
// ========== 리피터/반복 ==========
|
||
"repeat-container": () => import("@/lib/registry/components/repeat-container/RepeatContainerConfigPanel"),
|
||
"repeater-field-group": () => import("@/components/webtypes/config/RepeaterConfigPanel"),
|
||
"unified-repeater": () => import("@/components/unified/config-panels/UnifiedRepeaterConfigPanel"),
|
||
"simple-repeater-table": () => import("@/lib/registry/components/simple-repeater-table/SimpleRepeaterTableConfigPanel"),
|
||
"modal-repeater-table": () => import("@/lib/registry/components/modal-repeater-table/ModalRepeaterTableConfigPanel"),
|
||
"repeat-screen-modal": () => import("@/lib/registry/components/repeat-screen-modal/RepeatScreenModalConfigPanel"),
|
||
"related-data-buttons": () => import("@/lib/registry/components/related-data-buttons/RelatedDataButtonsConfigPanel"),
|
||
|
||
// ========== 검색/선택 ==========
|
||
"autocomplete-search-input": () => import("@/lib/registry/components/autocomplete-search-input/AutocompleteSearchInputConfigPanel"),
|
||
"entity-search-input": () => import("@/lib/registry/components/entity-search-input/EntitySearchInputConfigPanel"),
|
||
"selected-items-detail-input": () => import("@/lib/registry/components/selected-items-detail-input/SelectedItemsDetailInputConfigPanel"),
|
||
"customer-item-mapping": () => import("@/lib/registry/components/customer-item-mapping/CustomerItemMappingConfigPanel"),
|
||
"mail-recipient-selector": () => import("@/lib/registry/components/mail-recipient-selector/MailRecipientSelectorConfigPanel"),
|
||
"location-swap-selector": () => import("@/lib/registry/components/location-swap-selector/LocationSwapSelectorConfigPanel"),
|
||
|
||
// ========== 특수 컴포넌트 ==========
|
||
"flow-widget": () => import("@/components/screen/config-panels/FlowWidgetConfigPanel"),
|
||
"tabs-widget": () => import("@/components/screen/config-panels/TabsConfigPanel"),
|
||
"map": () => import("@/lib/registry/components/map/MapConfigPanel"),
|
||
"rack-structure": () => import("@/lib/registry/components/rack-structure/RackStructureConfigPanel"),
|
||
"aggregation-widget": () => import("@/lib/registry/components/aggregation-widget/AggregationWidgetConfigPanel"),
|
||
"v2-aggregation-widget": () => import("@/lib/registry/components/v2-aggregation-widget/AggregationWidgetConfigPanel"),
|
||
"numbering-rule": () => import("@/lib/registry/components/numbering-rule/NumberingRuleConfigPanel"),
|
||
"category-manager": () => import("@/lib/registry/components/category-manager/CategoryManagerConfigPanel"),
|
||
"universal-form-modal": () => import("@/lib/registry/components/universal-form-modal/UniversalFormModalConfigPanel"),
|
||
};
|
||
|
||
// 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;
|
||
}
|
||
|
||
try {
|
||
const module = await importFn();
|
||
|
||
// 모듈에서 ConfigPanel 컴포넌트 추출
|
||
// 1차: PascalCase 변환된 이름으로 찾기 (예: text-input -> TextInputConfigPanel)
|
||
// 2차: 특수 export명들 fallback
|
||
// 3차: default export
|
||
const pascalCaseName = `${toPascalCase(componentId)}ConfigPanel`;
|
||
const ConfigPanelComponent =
|
||
module[pascalCaseName] ||
|
||
// 특수 export명들
|
||
module.RepeaterConfigPanel ||
|
||
module.FlowWidgetConfigPanel ||
|
||
module.CustomerItemMappingConfigPanel ||
|
||
module.SelectedItemsDetailInputConfigPanel ||
|
||
module.ButtonConfigPanel ||
|
||
module.SectionCardConfigPanel ||
|
||
module.SectionPaperConfigPanel ||
|
||
module.TabsConfigPanel ||
|
||
module.UnifiedRepeaterConfigPanel ||
|
||
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;
|
||
|
||
if (!ConfigPanelComponent) {
|
||
console.error(`컴포넌트 "${componentId}"의 ConfigPanel을 모듈에서 찾을 수 없습니다.`);
|
||
return null;
|
||
}
|
||
|
||
// 캐시에 저장
|
||
configPanelCache.set(componentId, ConfigPanelComponent);
|
||
|
||
return ConfigPanelComponent;
|
||
} catch (error) {
|
||
console.error(`컴포넌트 "${componentId}"의 ConfigPanel 로드 실패:`, error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 컴포넌트 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("-")
|
||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||
.join("");
|
||
}
|
||
|
||
/**
|
||
* 컴포넌트 설정 패널을 렌더링하는 React 컴포넌트
|
||
*/
|
||
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; // 🆕 현재 컴포넌트 정보
|
||
}
|
||
|
||
export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> = ({
|
||
componentId,
|
||
config,
|
||
onChange,
|
||
screenTableName,
|
||
tableColumns,
|
||
tables,
|
||
menuObjid,
|
||
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;
|
||
};
|
||
}, [componentId]);
|
||
|
||
// tableColumns가 변경되면 selectedTableColumns도 업데이트
|
||
React.useEffect(() => {
|
||
setSelectedTableColumns(tableColumns);
|
||
}, [tableColumns]);
|
||
|
||
// RepeaterConfigPanel과 selected-items-detail-input에서 전체 테이블 목록 로드
|
||
React.useEffect(() => {
|
||
if (componentId === "repeater-field-group" || componentId === "selected-items-detail-input") {
|
||
const loadAllTables = async () => {
|
||
try {
|
||
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);
|
||
}
|
||
};
|
||
loadAllTables();
|
||
}
|
||
}, [componentId]);
|
||
|
||
// 🆕 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);
|
||
|
||
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();
|
||
}
|
||
|
||
// 대상 테이블 컬럼 로드
|
||
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();
|
||
}
|
||
}
|
||
}, [componentId, config.sourceTable, config.targetTable]);
|
||
|
||
if (loading) {
|
||
return (
|
||
<div className="rounded-md border border-dashed border-gray-300 bg-gray-50 p-4 w-full">
|
||
<div className="flex items-center gap-2 text-gray-600">
|
||
<span className="text-sm font-medium">⏳ 로딩 중...</span>
|
||
</div>
|
||
<p className="mt-1 text-xs text-gray-500">설정 패널을 불러오는 중입니다.</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
if (error) {
|
||
return (
|
||
<div className="rounded-md border border-dashed border-red-300 bg-red-50 p-4 w-full">
|
||
<div className="flex items-center gap-2 text-red-600">
|
||
<span className="text-sm font-medium">⚠️ 로드 실패</span>
|
||
</div>
|
||
<p className="mt-1 text-xs text-red-500">설정 패널을 불러올 수 없습니다: {error}</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
if (!ConfigPanelComponent) {
|
||
console.warn(`⚠️ DynamicComponentConfigPanel: ${componentId} ConfigPanelComponent가 null`);
|
||
return (
|
||
<div className="rounded-md border border-dashed border-yellow-300 bg-yellow-50 p-4 w-full">
|
||
<div className="flex items-center gap-2 text-yellow-600">
|
||
<span className="text-sm font-medium">⚠️ 설정 패널 없음</span>
|
||
</div>
|
||
<p className="mt-1 text-xs text-yellow-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) {
|
||
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,
|
||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||
dataType: col.dataType || col.data_type || col.dbType,
|
||
webType: col.webType || col.web_type,
|
||
input_type: col.inputType || col.input_type,
|
||
widgetType: col.widgetType || col.widget_type || col.webType || col.web_type,
|
||
isNullable: col.isNullable || col.is_nullable,
|
||
required: col.required !== undefined ? col.required : col.isNullable === "NO" || col.is_nullable === "NO",
|
||
columnDefault: col.columnDefault || col.column_default,
|
||
characterMaximumLength: col.characterMaximumLength || col.character_maximum_length,
|
||
codeCategory: col.codeCategory || col.code_category,
|
||
codeValue: col.codeValue || col.code_value,
|
||
}));
|
||
|
||
setSelectedTableColumns(columns);
|
||
} catch (error) {
|
||
console.error("❌ 테이블 변경 오류:", error);
|
||
// 오류 발생 시 빈 배열
|
||
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 추가
|
||
}));
|
||
|
||
console.log("✅ 원본 테이블 컬럼 로드 완료:", columns.length);
|
||
setSourceTableColumns(columns);
|
||
} catch (error) {
|
||
console.error("❌ 원본 테이블 컬럼 로드 실패:", error);
|
||
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 추가
|
||
}));
|
||
|
||
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);
|
||
setTargetTableColumns([]);
|
||
}
|
||
};
|
||
|
||
// 🆕 수주 등록 관련 컴포넌트들은 간단한 인터페이스 사용
|
||
const isSimpleConfigPanel = [
|
||
"autocomplete-search-input",
|
||
"modal-repeater-table",
|
||
"conditional-container",
|
||
].includes(componentId);
|
||
|
||
if (isSimpleConfigPanel) {
|
||
return <ConfigPanelComponent config={config} onConfigChange={onChange} />;
|
||
}
|
||
|
||
// 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} // 🆕 대상 테이블 변경 핸들러
|
||
/>
|
||
);
|
||
}
|
||
|
||
// 🆕 allComponents를 screenComponents 형태로 변환 (집계 위젯 등에서 사용)
|
||
const screenComponents = React.useMemo(() => {
|
||
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,
|
||
}));
|
||
}, [allComponents]);
|
||
|
||
return (
|
||
<ConfigPanelComponent
|
||
config={config}
|
||
onChange={onChange}
|
||
onConfigChange={onChange} // TableListConfigPanel을 위한 추가 prop
|
||
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} // 🆕 집계 위젯 등에서 사용하는 컴포넌트 목록
|
||
/>
|
||
);
|
||
};
|