feat: Docker 및 컴포넌트 최적화

- Docker Compose 설정에서 Node.js 메모리 제한을 8192MB로 증가시키고, Next.js telemetry를 비활성화하여 성능을 개선하였습니다.
- Next.js 구성에서 메모리 사용량 최적화를 위한 webpackMemoryOptimizations를 활성화하였습니다.
- ScreenModal 컴포넌트에서 overflow 속성을 조정하여 라벨이 잘리지 않도록 개선하였습니다.
- InteractiveScreenViewerDynamic 컴포넌트에서 라벨 표시 여부를 확인하는 로직을 추가하여 사용자 경험을 향상시켰습니다.
- RealtimePreviewDynamic 컴포넌트에서 라벨 표시 및 디버깅 로그를 추가하여 렌더링 과정을 추적할 수 있도록 하였습니다.
- ImprovedButtonControlConfigPanel에서 controlMode 설정을 추가하여 플로우 제어 기능을 개선하였습니다.
- V2PropertiesPanel에서 라벨 텍스트 및 표시 상태 업데이트 로직을 개선하여 일관성을 높였습니다.
- DynamicComponentRenderer에서 라벨 표시 로직을 개선하여 사용자 정의 스타일을 보다 효과적으로 적용할 수 있도록 하였습니다.
- layoutV2Converter에서 webTypeConfig를 병합하여 버튼 제어 기능과 플로우 가시성을 보존하였습니다.
This commit is contained in:
DDD1542
2026-02-04 18:01:20 +09:00
parent 593209e26e
commit 32139beebc
15 changed files with 295 additions and 130 deletions

View File

@@ -43,13 +43,20 @@ export interface ButtonExecutionResult {
}
interface ControlConfig {
type: "relationship";
relationshipConfig: {
type: "relationship" | "flow";
relationshipConfig?: {
relationshipId: string;
relationshipName: string;
executionTiming: "before" | "after" | "replace";
contextData?: Record<string, any>;
};
// 🆕 플로우 기반 제어 설정
flowConfig?: {
flowId: number;
flowName: string;
executionTiming: "before" | "after" | "replace";
contextData?: Record<string, any>;
};
}
interface ExecutionPlan {
@@ -163,15 +170,22 @@ export class ImprovedButtonActionExecutor {
return plan;
}
// enableDataflowControl 체크를 제거하고 dataflowConfig만 있으면 실행
// 🔧 controlMode가 없으면 flowConfig/relationshipConfig 존재 여부로 자동 판단
const effectiveControlMode = dataflowConfig.controlMode
|| (dataflowConfig.flowConfig ? "flow" : null)
|| (dataflowConfig.relationshipConfig ? "relationship" : null)
|| "none";
console.log("📋 실행 계획 생성:", {
controlMode: dataflowConfig.controlMode,
effectiveControlMode,
hasFlowConfig: !!dataflowConfig.flowConfig,
hasRelationshipConfig: !!dataflowConfig.relationshipConfig,
enableDataflowControl: buttonConfig.enableDataflowControl,
});
// 관계 기반 제어만 지원
if (dataflowConfig.controlMode === "relationship" && dataflowConfig.relationshipConfig) {
// 관계 기반 제어
if (effectiveControlMode === "relationship" && dataflowConfig.relationshipConfig) {
const control: ControlConfig = {
type: "relationship",
relationshipConfig: dataflowConfig.relationshipConfig,
@@ -191,11 +205,34 @@ export class ImprovedButtonActionExecutor {
}
}
// 🆕 플로우 기반 제어
if (effectiveControlMode === "flow" && dataflowConfig.flowConfig) {
const control: ControlConfig = {
type: "flow",
flowConfig: dataflowConfig.flowConfig,
};
console.log("📋 플로우 제어 설정:", dataflowConfig.flowConfig);
switch (dataflowConfig.flowConfig.executionTiming) {
case "before":
plan.beforeControls.push(control);
break;
case "after":
plan.afterControls.push(control);
break;
case "replace":
plan.afterControls.push(control);
plan.hasReplaceControl = true;
break;
}
}
return plan;
}
/**
* 🔥 제어 실행 (관계 또는 외부호출)
* 🔥 제어 실행 (관계 또는 플로우)
*/
private static async executeControls(
controls: ControlConfig[],
@@ -206,8 +243,16 @@ export class ImprovedButtonActionExecutor {
for (const control of controls) {
try {
// 관계 실행만 지원
const result = await this.executeRelationship(control.relationshipConfig, formData, context);
let result: ExecutionResult;
// 🆕 제어 타입에 따라 분기 처리
if (control.type === "flow" && control.flowConfig) {
result = await this.executeFlow(control.flowConfig, formData, context);
} else if (control.type === "relationship" && control.relationshipConfig) {
result = await this.executeRelationship(control.relationshipConfig, formData, context);
} else {
throw new Error(`지원하지 않는 제어 타입: ${control.type}`);
}
results.push(result);
@@ -215,7 +260,7 @@ export class ImprovedButtonActionExecutor {
if (!result.success) {
throw new Error(result.message);
}
} catch (error) {
} catch (error: any) {
console.error(`제어 실행 실패 (${control.type}):`, error);
results.push({
success: false,
@@ -230,6 +275,61 @@ export class ImprovedButtonActionExecutor {
return results;
}
/**
* 🆕 플로우 실행
*/
private static async executeFlow(
config: {
flowId: number;
flowName: string;
executionTiming: "before" | "after" | "replace";
contextData?: Record<string, any>;
},
formData: Record<string, any>,
context: ButtonExecutionContext,
): Promise<ExecutionResult> {
const startTime = Date.now();
try {
console.log(`🔄 플로우 실행 시작: ${config.flowName} (ID: ${config.flowId})`);
// 플로우 실행 API 호출
const response = await apiClient.post(`/api/dataflow/node-flows/${config.flowId}/execute`, {
formData,
contextData: config.contextData || {},
selectedRows: context.selectedRows || [],
flowSelectedData: context.flowSelectedData || [],
screenId: context.screenId,
companyCode: context.companyCode,
userId: context.userId,
});
const executionTime = Date.now() - startTime;
if (response.data?.success) {
console.log(`✅ 플로우 실행 성공: ${config.flowName}`, response.data);
return {
success: true,
message: `플로우 "${config.flowName}" 실행 완료`,
executionTime,
data: response.data,
};
} else {
throw new Error(response.data?.message || "플로우 실행 실패");
}
} catch (error: any) {
const executionTime = Date.now() - startTime;
console.error(`❌ 플로우 실행 실패: ${config.flowName}`, error);
return {
success: false,
message: `플로우 "${config.flowName}" 실행 실패: ${error.message}`,
executionTime,
error: error.message,
};
}
}
/**
* 🔥 관계 실행
*/