Compare commits

..

No commits in common. "23be8a0eeec7440b3e9cadc42db3ee6482ce5c8c" and "67e838dc03494e528e78d573bb38200cfc4e8d0d" have entirely different histories.

7 changed files with 32 additions and 120 deletions

View File

@ -34,9 +34,6 @@ export default function ScreenViewPage() {
// 테이블 새로고침을 위한 키 (값이 변경되면 테이블이 리렌더링됨) // 테이블 새로고침을 위한 키 (값이 변경되면 테이블이 리렌더링됨)
const [tableRefreshKey, setTableRefreshKey] = useState(0); const [tableRefreshKey, setTableRefreshKey] = useState(0);
// 플로우 새로고침을 위한 키 (값이 변경되면 플로우 데이터가 리렌더링됨)
const [flowRefreshKey, setFlowRefreshKey] = useState(0);
// 편집 모달 상태 // 편집 모달 상태
const [editModalOpen, setEditModalOpen] = useState(false); const [editModalOpen, setEditModalOpen] = useState(false);
const [editModalConfig, setEditModalConfig] = useState<{ const [editModalConfig, setEditModalConfig] = useState<{
@ -253,13 +250,6 @@ export default function ScreenViewPage() {
setTableRefreshKey((prev) => prev + 1); setTableRefreshKey((prev) => prev + 1);
setSelectedRowsData([]); // 선택 해제 setSelectedRowsData([]); // 선택 해제
}} }}
flowRefreshKey={flowRefreshKey}
onFlowRefresh={() => {
console.log("🔄 플로우 새로고침 요청됨");
setFlowRefreshKey((prev) => prev + 1);
setFlowSelectedData([]); // 선택 해제
setFlowSelectedStepId(null);
}}
formData={formData} formData={formData}
onFormDataChange={(fieldName, value) => { onFormDataChange={(fieldName, value) => {
console.log("📝 폼 데이터 변경:", fieldName, "=", value); console.log("📝 폼 데이터 변경:", fieldName, "=", value);

View File

@ -45,8 +45,6 @@ interface RealtimePreviewProps {
onFlowSelectedDataChange?: (selectedData: any[], stepId: number | null) => void; onFlowSelectedDataChange?: (selectedData: any[], stepId: number | null) => void;
refreshKey?: number; refreshKey?: number;
onRefresh?: () => void; onRefresh?: () => void;
flowRefreshKey?: number;
onFlowRefresh?: () => void;
// 폼 데이터 관련 props // 폼 데이터 관련 props
formData?: Record<string, any>; formData?: Record<string, any>;
@ -103,8 +101,6 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
onFlowSelectedDataChange, onFlowSelectedDataChange,
refreshKey, refreshKey,
onRefresh, onRefresh,
flowRefreshKey,
onFlowRefresh,
formData, formData,
onFormDataChange, onFormDataChange,
}) => { }) => {
@ -303,8 +299,6 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
onFlowSelectedDataChange={onFlowSelectedDataChange} onFlowSelectedDataChange={onFlowSelectedDataChange}
refreshKey={refreshKey} refreshKey={refreshKey}
onRefresh={onRefresh} onRefresh={onRefresh}
flowRefreshKey={flowRefreshKey}
onFlowRefresh={onFlowRefresh}
formData={formData} formData={formData}
onFormDataChange={onFormDataChange} onFormDataChange={onFormDataChange}
/> />

View File

@ -32,11 +32,9 @@ interface FlowWidgetProps {
component: FlowComponent; component: FlowComponent;
onStepClick?: (stepId: number, stepName: string) => void; onStepClick?: (stepId: number, stepName: string) => void;
onSelectedDataChange?: (selectedData: any[], stepId: number | null) => void; onSelectedDataChange?: (selectedData: any[], stepId: number | null) => void;
flowRefreshKey?: number; // 새로고침 키
onFlowRefresh?: () => void; // 새로고침 완료 콜백
} }
export function FlowWidget({ component, onStepClick, onSelectedDataChange, flowRefreshKey, onFlowRefresh }: FlowWidgetProps) { export function FlowWidget({ component, onStepClick, onSelectedDataChange }: FlowWidgetProps) {
const [flowData, setFlowData] = useState<FlowDefinition | null>(null); const [flowData, setFlowData] = useState<FlowDefinition | null>(null);
const [steps, setSteps] = useState<FlowStep[]>([]); const [steps, setSteps] = useState<FlowStep[]>([]);
const [stepCounts, setStepCounts] = useState<Record<number, number>>({}); const [stepCounts, setStepCounts] = useState<Record<number, number>>({});
@ -68,66 +66,23 @@ export function FlowWidget({ component, onStepClick, onSelectedDataChange, flowR
const showStepCount = config.showStepCount !== false && component.showStepCount !== false; // 기본값 true const showStepCount = config.showStepCount !== false && component.showStepCount !== false; // 기본값 true
const allowDataMove = config.allowDataMove || component.allowDataMove || false; const allowDataMove = config.allowDataMove || component.allowDataMove || false;
console.log("🔍 FlowWidget 렌더링:", {
// 선택된 스텝의 데이터를 다시 로드하는 함수 component,
const refreshStepData = async () => { componentConfig: config,
if (!flowId) return; flowId,
flowName,
try { displayMode,
// 스텝 카운트는 항상 업데이트 (선택된 스텝 유무와 관계없이) showStepCount,
const countsResponse = await getAllStepCounts(flowId); allowDataMove,
console.log("📊 스텝 카운트 API 응답:", countsResponse);
if (countsResponse.success && countsResponse.data) {
// Record 형태로 변환
const countsMap: Record<number, number> = {};
if (Array.isArray(countsResponse.data)) {
countsResponse.data.forEach((item: any) => {
countsMap[item.stepId] = item.count;
}); });
} else if (typeof countsResponse.data === 'object') {
Object.assign(countsMap, countsResponse.data);
}
console.log("✅ 스텝 카운트 업데이트:", countsMap);
setStepCounts(countsMap);
}
// 선택된 스텝이 있으면 해당 스텝의 데이터도 새로고침
if (selectedStepId) {
setStepDataLoading(true);
const response = await getStepDataList(flowId, selectedStepId, 1, 100);
if (!response.success) {
throw new Error(response.message || "데이터를 불러올 수 없습니다");
}
const rows = response.data?.records || [];
setStepData(rows);
// 컬럼 추출
if (rows.length > 0) {
setStepDataColumns(Object.keys(rows[0]));
} else {
setStepDataColumns([]);
}
// 선택 초기화
setSelectedRows(new Set());
onSelectedDataChange?.([], selectedStepId);
}
} catch (err: any) {
console.error("❌ 플로우 새로고침 실패:", err);
toast.error(err.message || "데이터를 새로고치는데 실패했습니다");
} finally {
if (selectedStepId) {
setStepDataLoading(false);
}
}
};
useEffect(() => { useEffect(() => {
console.log("🔍 FlowWidget useEffect 실행:", {
flowId,
hasFlowId: !!flowId,
config,
});
if (!flowId) { if (!flowId) {
setLoading(false); setLoading(false);
return; return;
@ -189,14 +144,6 @@ export function FlowWidget({ component, onStepClick, onSelectedDataChange, flowR
loadFlowData(); loadFlowData();
}, [flowId, showStepCount]); }, [flowId, showStepCount]);
// flowRefreshKey가 변경될 때마다 스텝 데이터 새로고침
useEffect(() => {
if (flowRefreshKey !== undefined && flowRefreshKey > 0 && flowId) {
console.log("🔄 플로우 새로고침 실행, flowRefreshKey:", flowRefreshKey);
refreshStepData();
}
}, [flowRefreshKey]);
// 스텝 클릭 핸들러 // 스텝 클릭 핸들러
const handleStepClick = async (stepId: number, stepName: string) => { const handleStepClick = async (stepId: number, stepName: string) => {
if (onStepClick) { if (onStepClick) {

View File

@ -105,9 +105,6 @@ export interface DynamicComponentRendererProps {
onFlowSelectedDataChange?: (selectedData: any[], stepId: number | null) => void; onFlowSelectedDataChange?: (selectedData: any[], stepId: number | null) => void;
// 테이블 새로고침 키 // 테이블 새로고침 키
refreshKey?: number; refreshKey?: number;
// 플로우 새로고침 키
flowRefreshKey?: number;
onFlowRefresh?: () => void;
// 편집 모드 // 편집 모드
mode?: "view" | "edit"; mode?: "view" | "edit";
// 모달 내에서 렌더링 여부 // 모달 내에서 렌더링 여부
@ -189,8 +186,6 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
flowSelectedStepId, flowSelectedStepId,
onFlowSelectedDataChange, onFlowSelectedDataChange,
refreshKey, refreshKey,
flowRefreshKey, // Added this
onFlowRefresh, // Added this
onConfigChange, onConfigChange,
isPreview, isPreview,
autoGeneration, autoGeneration,
@ -312,9 +307,6 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
// 설정 변경 핸들러 전달 // 설정 변경 핸들러 전달
onConfigChange, onConfigChange,
refreshKey, refreshKey,
// 플로우 새로고침 키
flowRefreshKey,
onFlowRefresh,
// 반응형 모드 플래그 전달 // 반응형 모드 플래그 전달
isPreview, isPreview,
// 디자인 모드 플래그 전달 - isPreview와 명확히 구분 // 디자인 모드 플래그 전달 - isPreview와 명확히 구분

View File

@ -29,7 +29,6 @@ export interface ButtonPrimaryComponentProps extends ComponentRendererProps {
tableName?: string; tableName?: string;
onRefresh?: () => void; onRefresh?: () => void;
onClose?: () => void; onClose?: () => void;
onFlowRefresh?: () => void;
// 폼 데이터 관련 // 폼 데이터 관련
originalData?: Record<string, any>; // 부분 업데이트용 원본 데이터 originalData?: Record<string, any>; // 부분 업데이트용 원본 데이터
@ -65,7 +64,6 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
tableName, tableName,
onRefresh, onRefresh,
onClose, onClose,
onFlowRefresh,
selectedRows, selectedRows,
selectedRowsData, selectedRowsData,
flowSelectedData, flowSelectedData,
@ -420,14 +418,8 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
}); });
// 삭제 액션인데 선택된 데이터가 없으면 경고 메시지 표시하고 중단 // 삭제 액션인데 선택된 데이터가 없으면 경고 메시지 표시하고 중단
const hasDataToDelete = if (processedConfig.action.type === "delete" && (!selectedRowsData || selectedRowsData.length === 0)) {
(selectedRowsData && selectedRowsData.length > 0) || (flowSelectedData && flowSelectedData.length > 0); console.log("⚠️ 삭제할 데이터가 선택되지 않았습니다.");
if (processedConfig.action.type === "delete" && !hasDataToDelete) {
console.log("⚠️ 삭제할 데이터가 선택되지 않았습니다.", {
hasSelectedRowsData: !!(selectedRowsData && selectedRowsData.length > 0),
hasFlowSelectedData: !!(flowSelectedData && flowSelectedData.length > 0),
});
toast.warning("삭제할 항목을 먼저 선택해주세요."); toast.warning("삭제할 항목을 먼저 선택해주세요.");
return; return;
} }
@ -440,7 +432,6 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
onFormDataChange, onFormDataChange,
onRefresh, onRefresh,
onClose, onClose,
onFlowRefresh, // 플로우 새로고침 콜백 추가
// 테이블 선택된 행 정보 추가 // 테이블 선택된 행 정보 추가
selectedRows, selectedRows,
selectedRowsData, selectedRowsData,
@ -526,7 +517,6 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
onSelectedRowsChange: _onSelectedRowsChange, onSelectedRowsChange: _onSelectedRowsChange,
flowSelectedData: _flowSelectedData, // 플로우 선택 데이터 필터링 flowSelectedData: _flowSelectedData, // 플로우 선택 데이터 필터링
flowSelectedStepId: _flowSelectedStepId, // 플로우 선택 스텝 ID 필터링 flowSelectedStepId: _flowSelectedStepId, // 플로우 선택 스텝 ID 필터링
onFlowRefresh: _onFlowRefresh, // 플로우 새로고침 콜백 필터링
originalData: _originalData, // 부분 업데이트용 원본 데이터 필터링 originalData: _originalData, // 부분 업데이트용 원본 데이터 필터링
refreshKey: _refreshKey, // 필터링 추가 refreshKey: _refreshKey, // 필터링 추가
isInModal: _isInModal, // 필터링 추가 isInModal: _isInModal, // 필터링 추가

View File

@ -20,12 +20,23 @@ export class FlowWidgetRenderer extends AutoRegisteringComponentRenderer {
})(); })();
render(): React.ReactElement { render(): React.ReactElement {
console.log("🎨🎨🎨 FlowWidgetRenderer - render 호출 시작 🎨🎨🎨");
console.log("🎨 FlowWidgetRenderer - render 호출:", {
componentId: this.props.component.id,
hasOnFlowSelectedDataChange: !!this.props.onFlowSelectedDataChange,
onFlowSelectedDataChangeType: typeof this.props.onFlowSelectedDataChange,
allPropsKeys: Object.keys(this.props),
allPropsValues: this.props,
});
console.log("🎨🎨🎨 FlowWidget에 전달할 prop:", {
hasComponent: !!this.props.component,
hasOnSelectedDataChange: !!this.props.onFlowSelectedDataChange,
});
return ( return (
<FlowWidget <FlowWidget
component={this.props.component as any} component={this.props.component as any}
onSelectedDataChange={this.props.onFlowSelectedDataChange} onSelectedDataChange={this.props.onFlowSelectedDataChange}
flowRefreshKey={this.props.flowRefreshKey}
onFlowRefresh={this.props.onFlowRefresh}
/> />
); );
} }

View File

@ -59,7 +59,6 @@ export interface ButtonActionContext {
onFormDataChange?: (fieldName: string, value: any) => void; onFormDataChange?: (fieldName: string, value: any) => void;
onClose?: () => void; onClose?: () => void;
onRefresh?: () => void; onRefresh?: () => void;
onFlowRefresh?: () => void; // 플로우 새로고침 콜백
// 테이블 선택된 행 정보 (다중 선택 액션용) // 테이블 선택된 행 정보 (다중 선택 액션용)
selectedRows?: any[]; selectedRows?: any[];
@ -217,9 +216,7 @@ export class ButtonActionExecutor {
throw new Error("저장에 필요한 정보가 부족합니다. (테이블명 또는 화면ID 누락)"); throw new Error("저장에 필요한 정보가 부족합니다. (테이블명 또는 화면ID 누락)");
} }
// 테이블과 플로우 모두 새로고침
context.onRefresh?.(); context.onRefresh?.();
context.onFlowRefresh?.();
return true; return true;
} catch (error) { } catch (error) {
console.error("저장 오류:", error); console.error("저장 오류:", error);
@ -405,16 +402,7 @@ export class ButtonActionExecutor {
} }
console.log(`✅ 다중 삭제 성공: ${dataToDelete.length}개 항목`); console.log(`✅ 다중 삭제 성공: ${dataToDelete.length}개 항목`);
// 데이터 소스에 따라 적절한 새로고침 호출
if (flowSelectedData && flowSelectedData.length > 0) {
console.log("🔄 플로우 데이터 삭제 완료, 플로우 새로고침 호출");
context.onFlowRefresh?.(); // 플로우 새로고침
} else {
console.log("🔄 테이블 데이터 삭제 완료, 테이블 새로고침 호출");
context.onRefresh?.(); // 테이블 새로고침 context.onRefresh?.(); // 테이블 새로고침
}
return true; return true;
} }