From 3d6ce26f9d43cca9ed44a9c112d39a4c7255eca3 Mon Sep 17 00:00:00 2001 From: kjs Date: Fri, 31 Oct 2025 11:10:09 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=A0=9C=EB=AA=A9=20=ED=8E=B8=EC=A7=91=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TableListConfigPanel에 테이블 제목 입력 필드 추가 - 제목 표시 우선순위: 사용자 입력 제목 → 테이블 라벨명 → 테이블명 - 사용자가 제목을 비워두면 자동으로 테이블 라벨명 또는 테이블명 표시 - 화면 편집기에서 테이블 제목을 자유롭게 수정 가능 --- .../table-list/TableListComponent.tsx | 8 +++++-- .../table-list/TableListConfigPanel.tsx | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index 497b42b7..9ee27c36 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -874,7 +874,9 @@ export const TableListComponent: React.FC = ({
{tableConfig.showHeader && (
-

{tableConfig.title || tableLabel}

+

+ {tableConfig.title || tableLabel || finalSelectedTable} +

)} @@ -936,7 +938,9 @@ export const TableListComponent: React.FC = ({ {/* 헤더 */} {tableConfig.showHeader && (
-

{tableConfig.title || tableLabel}

+

+ {tableConfig.title || tableLabel || finalSelectedTable} +

)} diff --git a/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx b/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx index 6b977155..f268e625 100644 --- a/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx +++ b/frontend/lib/registry/components/table-list/TableListConfigPanel.tsx @@ -727,6 +727,30 @@ export const TableListConfigPanel: React.FC = ({
테이블 리스트 설정
+ {/* 테이블 제목 설정 */} +
+
+

테이블 제목

+
+
+
+ + handleChange("title", e.target.value)} + placeholder="테이블 제목 입력..." + className="h-8 text-xs" + /> +

+ 우선순위: 사용자 입력 제목 → 테이블 라벨명 → 테이블명 +

+
+
+ {/* 가로 스크롤 및 컬럼 고정 */}
-- 2.43.0 From 27d278ca8ce2ed8aa0896dead59b21c23ea5a13a Mon Sep 17 00:00:00 2001 From: kjs Date: Fri, 31 Oct 2025 17:12:29 +0900 Subject: [PATCH 2/4] =?UTF-8?q?debug:=20=EC=A0=9C=EC=96=B4=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=8B=A4=ED=96=89=20=EB=94=94=EB=B2=84=EA=B9=85=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 제어관리가 실행되지 않는 원인을 파악하기 위한 상세 로그 추가 - 각 컴포넌트의 타입, 액션, 제어관리 설정 여부 출력 - 제어관리 설정이 없는 경우 명시적인 로그 출력 - 조건 불만족 시 어떤 조건이 맞지 않는지 확인 가능 --- backend-node/src/services/dynamicFormService.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/backend-node/src/services/dynamicFormService.ts b/backend-node/src/services/dynamicFormService.ts index 8a943b96..2955633f 100644 --- a/backend-node/src/services/dynamicFormService.ts +++ b/backend-node/src/services/dynamicFormService.ts @@ -1355,9 +1355,20 @@ export class DynamicFormService { console.log(`📋 화면 컴포넌트 조회 결과:`, screenLayouts.length); // 저장 버튼 중에서 제어관리가 활성화된 것 찾기 + let controlConfigFound = false; for (const layout of screenLayouts) { const properties = layout.properties as any; + // 디버깅: 모든 컴포넌트 정보 출력 + console.log(`🔍 컴포넌트 검사:`, { + componentId: layout.component_id, + componentType: properties?.componentType, + actionType: properties?.componentConfig?.action?.type, + enableDataflowControl: properties?.webTypeConfig?.enableDataflowControl, + hasDataflowConfig: !!properties?.webTypeConfig?.dataflowConfig, + hasDiagramId: !!properties?.webTypeConfig?.dataflowConfig?.selectedDiagramId, + }); + // 버튼 컴포넌트이고 저장 액션이며 제어관리가 활성화된 경우 if ( properties?.componentType === "button-primary" && @@ -1365,6 +1376,7 @@ export class DynamicFormService { properties?.webTypeConfig?.enableDataflowControl === true && properties?.webTypeConfig?.dataflowConfig?.selectedDiagramId ) { + controlConfigFound = true; const diagramId = properties.webTypeConfig.dataflowConfig.selectedDiagramId; const relationshipId = @@ -1417,6 +1429,10 @@ export class DynamicFormService { break; } } + + if (!controlConfigFound) { + console.log(`ℹ️ 제어관리 설정이 없습니다. (화면 ID: ${screenId})`); + } } catch (error) { console.error("❌ 제어관리 설정 확인 및 실행 오류:", error); // 에러를 다시 던지지 않음 - 메인 저장 프로세스에 영향 주지 않기 위해 -- 2.43.0 From 9a674b66863349de22ea540230ee5b83dbe64030 Mon Sep 17 00:00:00 2001 From: kjs Date: Fri, 31 Oct 2025 17:16:47 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=EB=B2=84=ED=8A=BC=20=EC=A0=9C?= =?UTF-8?q?=EC=96=B4=EA=B4=80=EB=A6=AC=20=EB=85=B8=EB=93=9C=20=ED=94=8C?= =?UTF-8?q?=EB=A1=9C=EC=9A=B0=20=EC=8B=A4=ED=96=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 프론트엔드: - ImprovedButtonControlConfigPanel에서 selectedDiagramId 저장 추가 - 플로우 선택 시 flowConfig와 함께 selectedDiagramId도 저장 - selectedRelationshipId는 null로 설정 (노드 플로우는 관계 불필요) 백엔드: - dynamicFormService에서 relationshipId 유무에 따라 실행 방식 분기 - relationshipId가 없으면 NodeFlowExecutionService.executeFlow() 실행 - relationshipId가 있으면 기존 dataflowControlService.executeDataflowControl() 실행 - 노드 플로우 실행 시 formData를 contextData로 전달 원인: - 기존에는 flowConfig만 저장하고 selectedDiagramId를 저장하지 않음 - 백엔드에서 selectedDiagramId가 없어서 제어관리 실행 조건 불만족 - 관계 기반 제어와 노드 플로우를 구분하지 못함 --- .../src/services/dynamicFormService.ts | 35 +++++++++++++++++-- .../ImprovedButtonControlConfigPanel.tsx | 16 ++++++--- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/backend-node/src/services/dynamicFormService.ts b/backend-node/src/services/dynamicFormService.ts index 2955633f..e7a9a10f 100644 --- a/backend-node/src/services/dynamicFormService.ts +++ b/backend-node/src/services/dynamicFormService.ts @@ -1389,9 +1389,37 @@ export class DynamicFormService { triggerType, }); - // 제어관리 실행 - const controlResult = - await this.dataflowControlService.executeDataflowControl( + // 노드 플로우 실행 (relationshipId가 없는 경우 노드 플로우로 간주) + let controlResult: any; + + if (!relationshipId) { + // 노드 플로우 실행 + console.log(`🚀 노드 플로우 실행 (flowId: ${diagramId})`); + const { NodeFlowExecutionService } = await import("./nodeFlowExecutionService"); + + const executionResult = await NodeFlowExecutionService.executeFlow(diagramId, { + sourceData: [savedData], + dataSourceType: "formData", + buttonId: "save-button", + screenId: screenId, + userId: userId, + formData: savedData, + }); + + controlResult = { + success: executionResult.success, + message: executionResult.message, + executedActions: executionResult.executedNodes?.map((node: any) => ({ + nodeId: node.nodeId, + status: node.status, + duration: node.duration, + })), + errors: executionResult.errors, + }; + } else { + // 관계 기반 제어관리 실행 + console.log(`🎯 관계 기반 제어관리 실행 (relationshipId: ${relationshipId})`); + controlResult = await this.dataflowControlService.executeDataflowControl( diagramId, relationshipId, triggerType, @@ -1399,6 +1427,7 @@ export class DynamicFormService { tableName, userId ); + } console.log(`🎯 제어관리 실행 결과:`, controlResult); diff --git a/frontend/components/screen/config-panels/ImprovedButtonControlConfigPanel.tsx b/frontend/components/screen/config-panels/ImprovedButtonControlConfigPanel.tsx index 35e1befe..18a51bba 100644 --- a/frontend/components/screen/config-panels/ImprovedButtonControlConfigPanel.tsx +++ b/frontend/components/screen/config-panels/ImprovedButtonControlConfigPanel.tsx @@ -63,11 +63,17 @@ export const ImprovedButtonControlConfigPanel: React.FC { const selectedFlow = flows.find((f) => f.flowId.toString() === flowId); if (selectedFlow) { - onUpdateProperty("webTypeConfig.dataflowConfig.flowConfig", { - flowId: selectedFlow.flowId, - flowName: selectedFlow.flowName, - executionTiming: "before", // 기본값 - contextData: {}, + // 전체 dataflowConfig 업데이트 (selectedDiagramId 포함) + onUpdateProperty("webTypeConfig.dataflowConfig", { + ...dataflowConfig, + selectedDiagramId: selectedFlow.flowId, // 백엔드에서 사용 + selectedRelationshipId: null, // 노드 플로우는 관계 ID 불필요 + flowConfig: { + flowId: selectedFlow.flowId, + flowName: selectedFlow.flowName, + executionTiming: "before", // 기본값 + contextData: {}, + }, }); } }; -- 2.43.0 From e42675616ba790e6a9e05b9fb3619c8bef6a8ede Mon Sep 17 00:00:00 2001 From: kjs Date: Fri, 31 Oct 2025 17:21:47 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=EC=A0=9C=EC=96=B4=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=20=EB=B0=8F=20=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - frontend: screen.ts에 saveScreenLayout 함수 추가 (ScreenDesigner_new.tsx가 호출하던 누락된 함수) - frontend: ScreenDesigner_new.tsx 저장 시 디버깅 로그 추가 - backend: screenManagementService.ts에 dataflowConfig 저장 확인 로그 추가 문제 원인: - ScreenDesigner_new.tsx가 호출하던 screenApi.saveScreenLayout 함수가 정의되지 않음 - 이로 인해 레이아웃 저장이 실패했을 가능성 해결: - saveScreenLayout 함수를 추가하여 정상적인 레이아웃 저장 가능 - 디버깅 로그를 통해 실제로 selectedDiagramId가 저장되는지 확인 가능 --- backend-node/src/services/screenManagementService.ts | 5 +++++ frontend/components/screen/ScreenDesigner_new.tsx | 12 ++++++++++++ frontend/lib/api/screen.ts | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/backend-node/src/services/screenManagementService.ts b/backend-node/src/services/screenManagementService.ts index 198c850b..f3c3d133 100644 --- a/backend-node/src/services/screenManagementService.ts +++ b/backend-node/src/services/screenManagementService.ts @@ -1278,6 +1278,11 @@ export class ScreenManagementService { }, }; + // 🔍 디버깅: webTypeConfig.dataflowConfig 확인 + if ((component as any).webTypeConfig?.dataflowConfig) { + console.log(`🔍 컴포넌트 ${component.id}의 dataflowConfig:`, JSON.stringify((component as any).webTypeConfig.dataflowConfig, null, 2)); + } + await query( `INSERT INTO screen_layouts ( screen_id, component_type, component_id, parent_id, diff --git a/frontend/components/screen/ScreenDesigner_new.tsx b/frontend/components/screen/ScreenDesigner_new.tsx index 16a50f3f..46c3ffdf 100644 --- a/frontend/components/screen/ScreenDesigner_new.tsx +++ b/frontend/components/screen/ScreenDesigner_new.tsx @@ -263,6 +263,18 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD try { setIsSaving(true); + + // 🔍 디버깅: 저장할 레이아웃 데이터 확인 + console.log("🔍 레이아웃 저장 요청:", { + screenId: selectedScreen.screenId, + componentsCount: layout.components.length, + components: layout.components.map(c => ({ + id: c.id, + type: c.type, + webTypeConfig: (c as any).webTypeConfig, + })), + }); + const response = await screenApi.saveScreenLayout(selectedScreen.screenId, layout); if (response.success) { toast.success("화면이 저장되었습니다."); diff --git a/frontend/lib/api/screen.ts b/frontend/lib/api/screen.ts index b8b77f85..695e5a51 100644 --- a/frontend/lib/api/screen.ts +++ b/frontend/lib/api/screen.ts @@ -151,6 +151,12 @@ export const screenApi = { await apiClient.post(`/screen-management/screens/${screenId}/layout`, layoutData); }, + // 화면 레이아웃 저장 (ScreenDesigner_new.tsx용) + saveScreenLayout: async (screenId: number, layoutData: LayoutData): Promise> => { + const response = await apiClient.post(`/screen-management/screens/${screenId}/layout`, layoutData); + return response.data; + }, + // 화면 레이아웃 조회 getLayout: async (screenId: number): Promise => { const response = await apiClient.get(`/screen-management/screens/${screenId}/layout`); -- 2.43.0