Files
invyone/frontend/lib/utils/getComponentConfigPanel.tsx
T
DDD1542 2f398ae0b3 chore: 제어모드 IDE 작업 + v2/legacy 레지스트리 컴포넌트 폐기
- 제어모드 IDE: ControlCardPanel, control/ide/* (Canvas/LeftRail/RightRail/PanZoomStage/V3RuleNode 등), schemas, lib/api/control
- 레지스트리 정리: aggregation-widget, status-count, section-card/paper, table-list(legacy/v2), tabs-widget 폐기 → table/_shared/ 로 통합
- InvLegacyButtonConfigPanel cp 마이그레이션
- canonical data view cleanup 후속 노트
2026-05-19 21:31:03 +09:00

538 lines
25 KiB
TypeScript

/**
* 컴포넌트 ID로 해당 컴포넌트의 ConfigPanel을 동적으로 로드하는 유틸리티
*/
import React from "react";
import type { ConfigPanelContext } from "@/lib/registry/components/common/ConfigPanelTypes";
// 컴포넌트별 ConfigPanel 동적 import 맵
//
// ★ 2026-04-11: INVYONE 통합 컴포넌트는 여기에 명시 등록 필요.
// `ComponentDefinition.config_panel` 필드는 이 파일에서 읽지 않음.
// Phase 마다 새 통합 컴포넌트 추가 시 아래 "INVYONE 통합" 섹션에 한 줄 추가.
// 관련 문서: notes/gbpark/2026-04-11-component-unification-plan.md §10.5
const CONFIG_PANEL_MAP: Record<string, () => Promise<any>> = {
// ========== INVYONE 통합 컴포넌트 (2026-04-11, Phase A~) ==========
"divider": () => import("@/lib/registry/components/divider/InvDividerConfigPanel"),
"title": () => import("@/lib/registry/components/title/InvTitleConfigPanel"),
"button": () => import("@/lib/registry/components/button/InvButtonConfigPanel"),
"search": () => import("@/lib/registry/components/search/InvSearchConfigPanel"),
"input": () => import("@/components/v2/config-panels/InvFieldConfigPanel"),
"stats": () => import("@/lib/registry/components/stats/InvStatsConfigPanel"),
"table": () => import("@/lib/registry/components/table/InvTableConfigPanel"),
"container": () => import("@/lib/registry/components/container/InvContainerConfigPanel"),
// ========== V2 컴포넌트 ==========
// V2 입력/선택 폐기 (2026-05-12) — input canonical 로 흡수. alias / fallback / schema 미제공.
"v2-list": () => import("@/components/v2/config-panels/InvDataConfigPanel"),
// v2-media — Phase D.5 폐기. canonical input (FilePicker) 으로 흡수, ConfigPanel 미제공.
"v2-biz": () => import("@/components/v2/config-panels/V2BizConfigPanel"),
"v2-group": () => import("@/components/v2/config-panels/V2GroupConfigPanel"),
"v2-hierarchy": () => import("@/components/v2/config-panels/V2HierarchyConfigPanel"),
"v2-layout": () => import("@/components/v2/config-panels/V2LayoutConfigPanel"),
"v2-repeater": () => import("@/components/v2/config-panels/InvDataConfigPanel"),
// ========== 기본 입력 컴포넌트 ==========
// Phase E / F.1 에서 기본 입력 6종 + radio-basic + toggle-switch 가 canonical
// input 으로 흡수 — InvFieldConfigPanel ("input") 이 단일 진실의 원천.
// file-upload — Phase D.5 폐기. test-input — Phase F.2 폐기 (CLI demo 잔재).
// ========== 버튼 ==========
"button-primary": () => import("@/components/screen/config-panels/ButtonConfigPanel"),
// v2-button-primary: hidden 호환 — InvLegacy 패널 사용 (옛 화면 config 스키마 보존)
"v2-button-primary": () => import("@/components/v2/config-panels/InvLegacyButtonConfigPanel"),
// ========== 표시 컴포넌트 ==========
"text-display": () => import("@/lib/registry/components/text-display/TextDisplayConfigPanel"),
// v2-text-display: hidden 호환 — InvLegacy 패널 사용
"v2-text-display": () => import("@/components/v2/config-panels/InvLegacyTextConfigPanel"),
// image-display / image-widget — Phase D.5 폐기. canonical input 의 file 분기로 흡수.
"divider-line": () => import("@/lib/registry/components/divider-line/DividerLineConfigPanel"),
// v2-divider-line: hidden 호환 — InvLegacy 패널 사용
"v2-divider-line": () => import("@/components/v2/config-panels/InvLegacyDividerConfigPanel"),
// ========== 레이아웃/컨테이너 ==========
// ★ 2026-05-19 canonical container alias 로 라우팅되는 옛 ConfigPanel 직접 import 제거.
// - section-card / v2-section-card / section-paper / v2-section-paper → CONFIG_PANEL_ALIAS["..."]="container"
// - accordion-basic → canonical container skeleton 부족 → 직접 import 보존
"accordion-basic": () => import("@/lib/registry/components/accordion-basic/AccordionBasicConfigPanel"),
// split-panel-layout 계열은 alias 없음 (master-detail UX 다름) → 직접 import 보존
"split-panel-layout": () => import("@/lib/registry/components/split-panel-layout/SplitPanelLayoutConfigPanel"),
"v2-split-panel-layout": () => import("@/lib/registry/components/v2-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"),
"v2-split-line": () => import("@/lib/registry/components/v2-split-line/SplitLineConfigPanel"),
// ========== 테이블/리스트 ==========
// ★ 2026-05-19 table-list / v2-table-list → CONFIG_PANEL_ALIAS["..."]="table" 로 라우팅
"table-search-widget": () => import("@/lib/registry/components/table-search-widget/TableSearchWidgetConfigPanel"),
"v2-table-search-widget": () => import("@/lib/registry/components/v2-table-search-widget/TableSearchWidgetConfigPanel"),
"tax-invoice-list": () => import("@/lib/registry/components/tax-invoice-list/TaxInvoiceListConfigPanel"),
// ========== 리피터/반복 ==========
// ★ canonical container.containerType=repeater skeleton 부족 → 직접 import 보존
"repeat-container": () => import("@/lib/registry/components/repeat-container/RepeatContainerConfigPanel"),
"v2-repeat-container": () => import("@/lib/registry/components/v2-repeat-container/RepeatContainerConfigPanel"),
"repeater-field-group": () => import("@/components/webtypes/config/RepeaterConfigPanel"),
"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"),
"v2-location-swap-selector": () => import("@/lib/registry/components/domain/v2-location-swap-selector/LocationSwapSelectorConfigPanel"),
// ========== 특수 컴포넌트 ==========
"flow-widget": () => import("@/components/screen/config-panels/FlowWidgetConfigPanel"),
// ★ 2026-05-19 tabs-widget / v2-tabs-widget / tabs / v2-tabs / aggregation-widget /
// v2-aggregation-widget 모두 CONFIG_PANEL_ALIAS 로 canonical container/stats 라우팅
"map": () => import("@/lib/registry/components/domain/map/MapConfigPanel"),
"rack-structure": () => import("@/lib/registry/components/rack-structure/RackStructureConfigPanel"),
"v2-rack-structure": () => import("@/lib/registry/components/domain/v2-rack-structure/RackStructureConfigPanel"),
// numbering-rule / v2-numbering-rule: 폐기 (2026-05-11). admin 페이지 /admin/systemMng/numberingRuleList 로 대체
"category-manager": () => import("@/lib/registry/components/category-manager/CategoryManagerConfigPanel"),
"universal-form-modal": () => import("@/lib/registry/components/universal-form-modal/UniversalFormModalConfigPanel"),
"v2-process-work-standard": () => import("@/lib/registry/components/domain/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 사용) ==========
// ★ "stats" key 는 위 INVYONE 통합 섹션에서 정의됨 — 여기 중복 정의 금지 (덮어씀 → 통합 패널 안 보임)
"card": () => import("@/components/screen/config-panels/CardConfigPanel"),
"dashboard": () => import("@/components/screen/config-panels/DashboardConfigPanel"),
"stats-card": () => import("@/components/screen/config-panels/StatsCardConfigPanel"),
"progress": () => import("@/components/screen/config-panels/ProgressBarConfigPanel"),
"progress-bar": () => import("@/components/screen/config-panels/ProgressBarConfigPanel"),
// Phase G.3 — canonical chart (recharts 기반). 옛 placeholder ChartConfigPanel 은 미사용.
"chart": () => import("@/lib/registry/components/chart/InvChartConfigPanel"),
"chart-basic": () => import("@/lib/registry/components/chart/InvChartConfigPanel"),
// Phase G.3.1 — canonical card-list / grouped-table
"card-list": () => import("@/lib/registry/components/card-list/InvCardListConfigPanel"),
"grouped-table": () => import("@/lib/registry/components/grouped-table/InvGroupedTableConfigPanel"),
"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"),
};
const configPanelCache = new Map<string, React.ComponentType<any>>();
/**
* 컴포넌트 ID로 ConfigPanel 컴포넌트를 동적으로 로드
*/
// ── Phase E: v2-* → 통합 컴포넌트 ConfigPanel alias ──
// ★ v2-button-primary / v2-divider-line / v2-text-display 는 alias 제외:
// hidden 호환 컴포넌트의 옛 화면 config 스키마가 통합 컴포넌트와 다르므로
// InvLegacy 패널 (위 CONFIG_PANEL_MAP) 로 직접 매핑되어야 함.
// ★ 2026-05-19: tabs/v2-tabs/tabs-widget 추가 (CONFIG_PANEL_MAP 옛 import 제거).
// accordion-basic 은 canonical container.containerType=accordion skeleton 부족 →
// 직접 ConfigPanel 사용 (alias 제외).
const CONFIG_PANEL_ALIAS: Record<string, string> = {
"divider-line": "divider", "v2-split-line": "divider",
"text-display": "title",
"button-primary": "button",
"v2-table-search-widget": "search", "table-search-widget": "search",
"v2-aggregation-widget": "stats", "aggregation-widget": "stats",
"v2-status-count": "stats",
"v2-table-list": "table", "table-list": "table",
"v2-tabs-widget": "container", "tabs-widget": "container",
"tabs": "container", "v2-tabs": "container",
"v2-section-card": "container", "v2-section-paper": "container",
"section-card": "container", "section-paper": "container",
"v2-repeat-container": "container",
};
export async function getComponentConfigPanel(componentId: string): Promise<React.ComponentType<any> | null> {
// alias 리졸브: v2-* → 통합 컴포넌트
const resolvedId = CONFIG_PANEL_ALIAS[componentId] ?? componentId;
if (configPanelCache.has(resolvedId)) {
return configPanelCache.get(resolvedId)!;
}
const importFn = CONFIG_PANEL_MAP[resolvedId] ?? CONFIG_PANEL_MAP[componentId];
if (!importFn) {
return null;
}
try {
const module = await importFn();
// 모듈에서 ConfigPanel 컴포넌트 추출 (우선순위):
// 1차: PascalCase 변환된 이름 (예: mail-recipient-selector -> MailRecipientSelectorConfigPanel)
// 2차: v2- 접두사 제거 후 PascalCase (예: v2-table-list -> TableListConfigPanel)
// 3차: *ConfigPanel로 끝나는 첫 번째 named export
// 4차: default export
const pascalCaseName = `${toPascalCase(componentId)}ConfigPanel`;
const baseComponentId = componentId.startsWith("v2-") ? componentId.slice(3) : componentId;
const basePascalCaseName = `${toPascalCase(baseComponentId)}ConfigPanel`;
const findConfigPanelExport = () => {
for (const key of Object.keys(module)) {
if (key.endsWith("ConfigPanel") && typeof module[key] === "function") {
return module[key];
}
}
return null;
};
const ConfigPanelComponent =
module[pascalCaseName] ||
module[basePascalCaseName] ||
findConfigPanelExport() ||
module.default;
if (!ConfigPanelComponent) {
console.error(`컴포넌트 "${componentId}"의 ConfigPanel을 모듈에서 찾을 수 없습니다.`);
return null;
}
configPanelCache.set(resolvedId, ConfigPanelComponent);
return ConfigPanelComponent;
} catch (error) {
console.error(`컴포넌트 "${componentId}"의 ConfigPanel 로드 실패:`, error);
return null;
}
}
export function hasComponentConfigPanel(componentId: string): boolean {
const resolved = CONFIG_PANEL_ALIAS[componentId] ?? componentId;
return resolved in CONFIG_PANEL_MAP || componentId in CONFIG_PANEL_MAP;
}
export function getSupportedConfigPanelComponents(): string[] {
return Object.keys(CONFIG_PANEL_MAP);
}
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;
allComponents?: any[];
currentComponent?: any;
componentType?: string;
}
export const DynamicComponentConfigPanel: React.FC<ComponentConfigPanelProps> = ({
componentId,
config,
onChange,
screenTableName,
tableColumns,
tables,
menuObjid,
allComponents,
currentComponent,
componentType,
}) => {
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[]>([]);
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) {
if (mounted) {
setError(err instanceof Error ? err.message : String(err));
setLoading(false);
}
}
}
loadConfigPanel();
return () => { mounted = false; };
}, [componentId]);
React.useEffect(() => {
setSelectedTableColumns(tableColumns);
}, [tableColumns]);
// repeater-field-group / selected-items-detail-input에서 전체 테이블 목록 로드
// ── 모든 컴포넌트에서 전체 DB 테이블 목록 로드 ──
React.useEffect(() => {
const loadAllTables = async () => {
try {
const { tableManagementApi } = await import("@/lib/api/tableManagement");
const response = await tableManagementApi.getTableList();
if (response.success && response.data) {
setAllTablesList(response.data);
}
} catch (_) {
// 전체 테이블 목록 로드 실패 시 무시
}
};
loadAllTables();
}, []);
// selected-items-detail-input: 초기 sourceTable/targetTable 컬럼 로드
React.useEffect(() => {
if (componentId !== "selected-items-detail-input") return;
const loadColumns = async (tableName: string, setter: React.Dispatch<React.SetStateAction<any[]>>, includeCodeInfo?: 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,
...(includeCodeInfo ? { codeInfo: col.codeInfo || col.code_info } : {}),
}));
setter(columns);
} catch (_) {
setter([]);
}
};
if (config.sourceTable) loadColumns(config.sourceTable, setSourceTableColumns);
if (config.targetTable) loadColumns(config.targetTable, setTargetTableColumns, true);
}, [componentId, config.sourceTable, config.targetTable]);
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,
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>
</div>
<p className="mt-1 text-xs text-muted-foreground"> .</p>
</div>
);
}
if (error) {
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>
</div>
<p className="mt-1 text-xs text-destructive"> : {error}</p>
</div>
);
}
if (!ConfigPanelComponent) {
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>
</div>
<p className="mt-1 text-xs text-amber-500"> &quot;{componentId}&quot; .</p>
</div>
);
}
// 테이블 변경 핸들러
const handleTableChange = async (tableName: string) => {
try {
const existingTable = tables?.find((t) => t.tableName === tableName);
if (existingTable?.columns?.length > 0) {
setSelectedTableColumns(existingTable.columns);
return;
}
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,
web_type: 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,
codeInfo: col.codeInfo || col.code_info,
codeValue: col.codeValue || col.code_value,
}));
setSelectedTableColumns(columns);
} catch (_) {
setSelectedTableColumns([]);
}
};
const handleSourceTableChange = async (tableName: string) => {
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,
}));
setSourceTableColumns(columns);
} catch (_) {
setSourceTableColumns([]);
}
};
const handleTargetTableChange = async (tableName: string) => {
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,
codeInfo: col.codeInfo || col.code_info,
}));
setTargetTableColumns(columns);
} catch (_) {
setTargetTableColumns([]);
}
};
// --- 특수 래퍼: 레거시 위젯 (component/onUpdateProperty props) ---
// ★ 2026-05-19 canonical stats / chart / chart-basic 은 config/onChange props 패턴 →
// LEGACY_PANELS 에서 제외 (component/onUpdateProperty 전달 시 빈 패널 버그 방지).
// stats-card 는 옛 dashboard placeholder 위젯으로 유지.
const LEGACY_PANELS = new Set([
"card", "dashboard", "stats-card",
"progress", "progress-bar",
"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 });
}
}}
/>
);
}
// --- 특수 래퍼: ButtonConfigPanel (component/onUpdateProperty props) ---
if (componentId === "button-primary" || componentId === "v2-button-primary") {
const componentForButton = currentComponent || {
id: "temp",
type: "component",
componentType: componentId,
componentConfig: config,
};
return (
<ConfigPanelComponent
component={componentForButton}
onUpdateProperty={(path: string, value: any) => {
if (path.startsWith("componentConfig.")) {
const configPath = path.replace("componentConfig.", "");
const pathParts = configPath.split(".");
const currentConfig = componentForButton.componentConfig || {};
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]] = {};
current = current[pathParts[i]];
}
current[pathParts[pathParts.length - 1]] = value;
onChange(newConfig);
} else {
const currentConfig = componentForButton.componentConfig || {};
onChange({ ...currentConfig, [path]: value });
}
}}
allComponents={allComponents}
currentTableName={screenTableName}
/>
);
}
// --- 통일된 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}
context={context}
screenTableName={screenTableName}
tableName={screenTableName}
columnName={currentComponent?.columnName || config?.columnName || config?.fieldName}
tableColumns={selectedTableColumns}
tables={allTablesList.length > 0 ? allTablesList : tables}
allTables={allTablesList.length > 0 ? allTablesList : tables}
onTableChange={handleTableChange}
menuObjid={menuObjid}
allComponents={allComponents}
currentComponent={currentComponent}
screenComponents={screenComponents}
inputType={currentComponent?.inputType || config?.inputType}
componentType={componentType || componentId}
sourceTableColumns={sourceTableColumns}
targetTableColumns={targetTableColumns}
onSourceTableChange={handleSourceTableChange}
onTargetTableChange={handleTargetTableChange}
/>
);
};