Remove obsolete end-to-end test scripts and related files for screen and table components in the agent pipeline.

This commit is contained in:
DDD1542
2026-03-09 13:33:01 +09:00
parent d13884d572
commit 7910921c97
34 changed files with 3076 additions and 2001 deletions

View File

@@ -44,6 +44,7 @@ import { useSplitPanel } from "./SplitPanelContext";
import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer";
import { PanelInlineComponent } from "./types";
import { cn } from "@/lib/utils";
import { ResponsiveGridRenderer } from "@/components/screen/ResponsiveGridRenderer";
import { BomExcelUploadModal } from "../v2-bom-tree/BomExcelUploadModal";
export interface SplitPanelLayoutComponentProps extends ComponentRendererProps {
@@ -726,24 +727,21 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
return `${height}px`; // 숫자면 px 추가
};
const componentStyle: React.CSSProperties = isPreview
const componentStyle: React.CSSProperties = isDesignMode
? {
// 반응형 모드: position relative, 그리드 컨테이너가 제공하는 크기 사용
position: "relative",
width: "100%", // 🆕 부모 컨테이너 너비에 맞춤
height: getHeightValue(),
border: "1px solid #e5e7eb",
}
: {
// 디자이너 모드: position absolute
position: "absolute",
left: `${component.style?.positionX || 0}px`,
top: `${component.style?.positionY || 0}px`,
width: "100%", // 🆕 부모 컨테이너 너비에 맞춤 (그리드 기반)
width: "100%",
height: getHeightValue(),
zIndex: component.style?.positionZ || 1,
cursor: isDesignMode ? "pointer" : "default",
cursor: "pointer",
border: isSelected ? "2px solid #3b82f6" : "1px solid #e5e7eb",
}
: {
position: "relative",
width: "100%",
height: getHeightValue(),
};
// 계층 구조 빌드 함수 (트리 구조 유지)
@@ -2975,13 +2973,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<div
ref={containerRef}
style={{
...(isPreview
? {
position: "relative",
height: `${component.style?.height || 600}px`,
border: "1px solid #e5e7eb",
}
: componentStyle),
...componentStyle,
display: "flex",
flexDirection: "row",
}}
@@ -2995,8 +2987,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
>
{/* 좌측 패널 */}
<div
style={{ width: `${leftWidth}%`, minWidth: isPreview ? "0" : `${minLeftWidth}px`, height: "100%" }}
className="border-border flex flex-shrink-0 flex-col border-r"
style={{ width: `${leftWidth}%`, minWidth: isDesignMode ? `${minLeftWidth}px` : "0", height: "100%" }}
className="border-border flex flex-col border-r"
>
<Card className="flex flex-col border-0 shadow-none" style={{ height: "100%" }}>
<CardHeader
@@ -3053,22 +3045,74 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
data-component-id={component.id}
data-panel-side="left"
>
{/* 🆕 커스텀 모드: 디자인/실행 모드 통합 렌더링 */}
{/* 커스텀 모드: 디자인/실행 모드 분기 렌더링 */}
{componentConfig.leftPanel?.components && componentConfig.leftPanel.components.length > 0 ? (
!isDesignMode ? (
// 런타임: ResponsiveGridRenderer로 반응형 렌더링
(() => {
const leftComps = componentConfig.leftPanel!.components;
const canvasW = Math.max(...leftComps.map((c: PanelInlineComponent) => (c.position?.x || 0) + (c.size?.width || 200)), 800);
const canvasH = Math.max(...leftComps.map((c: PanelInlineComponent) => (c.position?.y || 0) + (c.size?.height || 100)), 400);
const compDataList = leftComps.map((c: PanelInlineComponent) => ({
id: c.id,
type: "component" as const,
componentType: c.componentType,
label: c.label,
position: c.position || { x: 0, y: 0 },
size: c.size || { width: 400, height: 300 },
componentConfig: c.componentConfig || {},
style: c.style || {},
tableName: c.componentConfig?.tableName,
columnName: c.componentConfig?.columnName,
webType: c.componentConfig?.webType,
inputType: (c as any).inputType || c.componentConfig?.inputType,
})) as any;
return (
<ResponsiveGridRenderer
components={compDataList}
canvasWidth={canvasW}
canvasHeight={canvasH}
renderComponent={(comp) => (
<DynamicComponentRenderer
component={comp as any}
isDesignMode={false}
isInteractive={true}
formData={{}}
tableName={componentConfig.leftPanel?.tableName}
menuObjid={(props as any).menuObjid}
screenId={(props as any).screenId}
userId={(props as any).userId}
userName={(props as any).userName}
companyCode={companyCode}
allComponents={(props as any).allComponents}
selectedRowsData={localSelectedRowsData}
onSelectedRowsChange={handleLocalSelectedRowsChange}
onFormDataChange={(data: any) => {
if (data?.selectedRowsData && data.selectedRowsData.length > 0) {
setCustomLeftSelectedData(data.selectedRowsData[0]);
setSelectedLeftItem(data.selectedRowsData[0]);
} else if (data?.selectedRowsData && data.selectedRowsData.length === 0) {
setCustomLeftSelectedData({});
setSelectedLeftItem(null);
}
}}
/>
)}
/>
);
})()
) : (
<div className="relative h-full w-full" style={{ minHeight: "100%", minWidth: "100%" }}>
{componentConfig.leftPanel.components.map((comp: PanelInlineComponent) => {
const isSelectedComp = selectedPanelComponentId === comp.id;
const isDraggingComp = draggingCompId === comp.id;
const isResizingComp = resizingCompId === comp.id;
// 드래그/리사이즈 중 표시할 크기/위치
const displayX = isDraggingComp && dragPosition ? dragPosition.x : (comp.position?.x || 0);
const displayY = isDraggingComp && dragPosition ? dragPosition.y : (comp.position?.y || 0);
const displayWidth = isResizingComp && resizeSize ? resizeSize.width : (comp.size?.width || 200);
const displayHeight = isResizingComp && resizeSize ? resizeSize.height : (comp.size?.height || 100);
// 컴포넌트 데이터를 DynamicComponentRenderer 형식으로 변환
// componentConfig의 주요 속성을 최상위로 펼침 (일반 화면의 overrides 플래트닝과 동일)
const componentData = {
id: comp.id,
type: "component" as const,
@@ -3078,16 +3122,13 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
size: { width: displayWidth, height: displayHeight },
componentConfig: comp.componentConfig || {},
style: comp.style || {},
// 파일 업로드/미디어 등이 component.tableName, component.columnName을 직접 참조하므로 펼침
tableName: comp.componentConfig?.tableName,
columnName: comp.componentConfig?.columnName,
webType: comp.componentConfig?.webType,
inputType: comp.inputType || comp.componentConfig?.inputType,
inputType: (comp as any).inputType || comp.componentConfig?.inputType,
};
if (isDesignMode) {
// 디자인 모드: 탭 컴포넌트와 동일하게 실제 컴포넌트 렌더링
return (
return (
<div
key={comp.id}
data-panel-comp-id={comp.id}
@@ -3224,60 +3265,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
</div>
</div>
);
} else {
// 실행 모드: DynamicComponentRenderer로 렌더링
const componentData = {
id: comp.id,
type: "component" as const,
componentType: comp.componentType,
label: comp.label,
position: comp.position || { x: 0, y: 0 },
size: comp.size || { width: 400, height: 300 },
componentConfig: comp.componentConfig || {},
style: comp.style || {},
};
return (
<div
key={comp.id}
className="absolute"
style={{
left: comp.position?.x || 0,
top: comp.position?.y || 0,
width: comp.size?.width || 400,
height: comp.size?.height || 300,
}}
>
<DynamicComponentRenderer
component={componentData as any}
isDesignMode={false}
isInteractive={true}
formData={{}}
tableName={componentConfig.leftPanel?.tableName}
menuObjid={(props as any).menuObjid}
screenId={(props as any).screenId}
userId={(props as any).userId}
userName={(props as any).userName}
companyCode={companyCode}
allComponents={(props as any).allComponents}
selectedRowsData={localSelectedRowsData}
onSelectedRowsChange={handleLocalSelectedRowsChange}
onFormDataChange={(data: any) => {
// 커스텀 모드: 좌측 카드/테이블 선택 시 데이터 캡처
if (data?.selectedRowsData && data.selectedRowsData.length > 0) {
setCustomLeftSelectedData(data.selectedRowsData[0]);
setSelectedLeftItem(data.selectedRowsData[0]);
} else if (data?.selectedRowsData && data.selectedRowsData.length === 0) {
setCustomLeftSelectedData({});
setSelectedLeftItem(null);
}
}}
/>
</div>
);
}
})}
</div>
)
) : (
// 컴포넌트가 없을 때 드롭 영역 표시
<div className="flex h-full w-full flex-col items-center justify-center rounded border-2 border-dashed border-gray-300 bg-gray-50/50">
@@ -3819,8 +3809,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{/* 우측 패널 */}
<div
style={{ width: `${100 - leftWidth}%`, minWidth: isPreview ? "0" : `${minRightWidth}px`, height: "100%" }}
className="flex flex-shrink-0 flex-col border-l border-border/60 bg-muted/5"
style={{ width: `${100 - leftWidth}%`, minWidth: isDesignMode ? `${minRightWidth}px` : "0", height: "100%" }}
className="flex flex-col border-l border-border/60 bg-muted/5"
>
<Card className="flex flex-col border-0 bg-transparent shadow-none" style={{ height: "100%" }}>
<CardHeader
@@ -3909,7 +3899,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
</div>
</div>
)}
<CardContent className="flex-1 overflow-hidden p-4">
<CardContent className="flex-1 overflow-auto p-4">
{/* 추가 탭 컨텐츠 */}
{activeTabIndex > 0 ? (
(() => {
@@ -4185,22 +4175,68 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
data-component-id={component.id}
data-panel-side="right"
>
{/* 🆕 커스텀 모드: 디자인/실행 모드 통합 렌더링 */}
{/* 커스텀 모드: 디자인/실행 모드 분기 렌더링 */}
{componentConfig.rightPanel?.components && componentConfig.rightPanel.components.length > 0 ? (
!isDesignMode ? (
// 런타임: ResponsiveGridRenderer로 반응형 렌더링
(() => {
const rightComps = componentConfig.rightPanel!.components;
const canvasW = Math.max(...rightComps.map((c: PanelInlineComponent) => (c.position?.x || 0) + (c.size?.width || 200)), 800);
const canvasH = Math.max(...rightComps.map((c: PanelInlineComponent) => (c.position?.y || 0) + (c.size?.height || 100)), 400);
const compDataList = rightComps.map((c: PanelInlineComponent) => ({
id: c.id,
type: "component" as const,
componentType: c.componentType,
label: c.label,
position: c.position || { x: 0, y: 0 },
size: c.size || { width: 400, height: 300 },
componentConfig: c.componentConfig || {},
style: c.style || {},
tableName: c.componentConfig?.tableName,
columnName: c.componentConfig?.columnName,
webType: c.componentConfig?.webType,
inputType: (c as any).inputType || c.componentConfig?.inputType,
})) as any;
return (
<ResponsiveGridRenderer
components={compDataList}
canvasWidth={canvasW}
canvasHeight={canvasH}
renderComponent={(comp) => (
<DynamicComponentRenderer
component={comp as any}
isDesignMode={false}
isInteractive={true}
formData={customLeftSelectedData}
onFormDataChange={(fieldName: string, value: any) => {
setCustomLeftSelectedData((prev: Record<string, any>) => ({ ...prev, [fieldName]: value }));
}}
tableName={componentConfig.rightPanel?.tableName || componentConfig.leftPanel?.tableName}
menuObjid={(props as any).menuObjid}
screenId={(props as any).screenId}
userId={(props as any).userId}
userName={(props as any).userName}
companyCode={companyCode}
allComponents={(props as any).allComponents}
selectedRowsData={localSelectedRowsData}
onSelectedRowsChange={handleLocalSelectedRowsChange}
/>
)}
/>
);
})()
) : (
<div className="relative h-full w-full" style={{ minHeight: "100%", minWidth: "100%" }}>
{componentConfig.rightPanel.components.map((comp: PanelInlineComponent) => {
const isSelectedComp = selectedPanelComponentId === comp.id;
const isDraggingComp = draggingCompId === comp.id;
const isResizingComp = resizingCompId === comp.id;
// 드래그/리사이즈 중 표시할 크기/위치
const displayX = isDraggingComp && dragPosition ? dragPosition.x : (comp.position?.x || 0);
const displayY = isDraggingComp && dragPosition ? dragPosition.y : (comp.position?.y || 0);
const displayWidth = isResizingComp && resizeSize ? resizeSize.width : (comp.size?.width || 200);
const displayHeight = isResizingComp && resizeSize ? resizeSize.height : (comp.size?.height || 100);
// 컴포넌트 데이터를 DynamicComponentRenderer 형식으로 변환
// componentConfig의 주요 속성을 최상위로 펼침 (일반 화면의 overrides 플래트닝과 동일)
const componentData = {
id: comp.id,
type: "component" as const,
@@ -4210,16 +4246,13 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
size: { width: displayWidth, height: displayHeight },
componentConfig: comp.componentConfig || {},
style: comp.style || {},
// 파일 업로드/미디어 등이 component.tableName, component.columnName을 직접 참조하므로 펼침
tableName: comp.componentConfig?.tableName,
columnName: comp.componentConfig?.columnName,
webType: comp.componentConfig?.webType,
inputType: comp.inputType || comp.componentConfig?.inputType,
inputType: (comp as any).inputType || comp.componentConfig?.inputType,
};
if (isDesignMode) {
// 디자인 모드: 탭 컴포넌트와 동일하게 실제 컴포넌트 렌더링
return (
return (
<div
key={comp.id}
data-panel-comp-id={comp.id}
@@ -4231,14 +4264,12 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
}}
onClick={(e) => {
e.stopPropagation();
// 패널 컴포넌트 선택 시 탭 내 선택 해제
if (comp.componentType !== "v2-tabs-widget") {
setNestedTabSelectedCompId(undefined);
}
onSelectPanelComponent?.("right", comp.id, comp);
}}
>
{/* 드래그 핸들 - 컴포넌트 외부 상단 */}
<div
className={cn(
"flex h-4 cursor-move items-center justify-between rounded-t border border-b-0 bg-gray-100 px-1",
@@ -4277,7 +4308,6 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
</div>
</div>
{/* 실제 컴포넌트 렌더링 - 핸들 아래에 별도 영역 */}
<div
className={cn(
"relative overflow-hidden rounded-b border bg-white shadow-sm",
@@ -4292,10 +4322,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
height: displayHeight,
}}
>
{/* 🆕 컨테이너 컴포넌트(탭, 분할 패널)는 드롭 이벤트를 받을 수 있어야 함 */}
<div className={cn(
"h-full w-full",
// 탭/분할 패널 같은 컨테이너 컴포넌트는 pointer-events 활성화
(comp.componentType === "v2-tabs-widget" ||
comp.componentType === "tabs-widget" ||
comp.componentType === "v2-split-panel-layout" ||
@@ -4307,16 +4335,11 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
component={componentData as any}
isDesignMode={true}
formData={{}}
// 🆕 중첩된 컴포넌트 업데이트 핸들러 전달
onUpdateComponent={(updatedComp: any) => {
handleNestedComponentUpdate("right", comp.id, updatedComp);
}}
// 🆕 중첩된 탭 내부 컴포넌트 선택 핸들러 - 부모 분할 패널 정보 포함
onSelectTabComponent={(tabId: string, compId: string, tabComp: any) => {
console.log("🔍 [SplitPanel-Right] onSelectTabComponent 호출:", { tabId, compId, tabComp, parentSplitPanelId: component.id });
// 탭 내 컴포넌트 선택 상태 업데이트
setNestedTabSelectedCompId(compId);
// 부모 분할 패널 정보와 함께 전역 이벤트 발생
const event = new CustomEvent("nested-tab-component-select", {
detail: {
tabsComponentId: comp.id,
@@ -4333,20 +4356,16 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
/>
</div>
{/* 리사이즈 가장자리 영역 - 선택된 컴포넌트에만 표시 */}
{isSelectedComp && (
<>
{/* 오른쪽 가장자리 (너비 조절) */}
<div
className="pointer-events-auto absolute right-0 top-0 z-10 h-full w-2 cursor-ew-resize hover:bg-primary/10"
onMouseDown={(e) => handlePanelResizeStart(e, "right", comp, "e")}
/>
{/* 아래 가장자리 (높이 조절) */}
<div
className="pointer-events-auto absolute bottom-0 left-0 z-10 h-2 w-full cursor-ns-resize hover:bg-primary/10"
onMouseDown={(e) => handlePanelResizeStart(e, "right", comp, "s")}
/>
{/* 오른쪽 아래 모서리 (너비+높이 조절) */}
<div
className="pointer-events-auto absolute bottom-0 right-0 z-20 h-3 w-3 cursor-nwse-resize hover:bg-primary/20"
onMouseDown={(e) => handlePanelResizeStart(e, "right", comp, "se")}
@@ -4356,42 +4375,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
</div>
</div>
);
} else {
return (
<div
key={comp.id}
className="absolute"
style={{
left: comp.position?.x || 0,
top: comp.position?.y || 0,
width: comp.size?.width || 400,
height: comp.size?.height || 300,
}}
>
<DynamicComponentRenderer
component={componentData as any}
isDesignMode={false}
isInteractive={true}
formData={customLeftSelectedData}
onFormDataChange={(fieldName: string, value: any) => {
setCustomLeftSelectedData((prev: Record<string, any>) => ({ ...prev, [fieldName]: value }));
}}
tableName={componentConfig.rightPanel?.tableName || componentConfig.leftPanel?.tableName}
menuObjid={(props as any).menuObjid}
screenId={(props as any).screenId}
userId={(props as any).userId}
userName={(props as any).userName}
companyCode={companyCode}
allComponents={(props as any).allComponents}
selectedRowsData={localSelectedRowsData}
onSelectedRowsChange={handleLocalSelectedRowsChange}
/>
</div>
);
}
})}
</div>
)
) : (
// 컴포넌트가 없을 때 드롭 영역 표시
<div className="flex h-full w-full flex-col items-center justify-center rounded border-2 border-dashed border-gray-300 bg-gray-50/50">
@@ -4486,10 +4472,11 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
}));
}
const tableMinWidth = columnsToShow.reduce((sum, col) => sum + (col.width || 100), 0) + 80;
return (
<div className="flex h-full w-full flex-col">
<div className="min-h-0 flex-1 overflow-auto">
<table className="min-w-full">
<table style={{ minWidth: `${tableMinWidth}px` }}>
<thead className="sticky top-0 z-10">
<tr className="border-b-2 border-border/60">
{columnsToShow.map((col, idx) => (
@@ -4612,10 +4599,11 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
const hasDeleteButton = !isDesignMode && (componentConfig.rightPanel?.deleteButton?.enabled ?? true);
const hasActions = hasEditButton || hasDeleteButton;
const tableMinW2 = columnsToDisplay.reduce((sum, col) => sum + (col.width || 100), 0) + 80;
return filteredData.length > 0 ? (
<div className="flex h-full w-full flex-col">
<div className="min-h-0 flex-1 overflow-auto">
<table className="w-full text-sm">
<table className="text-sm" style={{ minWidth: `${tableMinW2}px` }}>
<thead className="sticky top-0 z-10 bg-background">
<tr className="border-b-2 border-border/60">
{columnsToDisplay.map((col) => (