테스트테이블 생성 및 오류 수정
This commit is contained in:
@@ -166,7 +166,10 @@ export class ButtonActionExecutor {
|
||||
|
||||
const primaryKeys = primaryKeyResult.data || [];
|
||||
const primaryKeyValue = this.extractPrimaryKeyValueFromDB(formData, primaryKeys);
|
||||
const isUpdate = primaryKeyValue !== null && primaryKeyValue !== undefined && primaryKeyValue !== "";
|
||||
|
||||
// 단순히 기본키 값 존재 여부로 판단 (임시)
|
||||
// TODO: 실제 테이블에서 기본키로 레코드 존재 여부 확인하는 API 필요
|
||||
const isUpdate = false; // 현재는 항상 INSERT로 처리
|
||||
|
||||
console.log("💾 저장 모드 판단 (DB 기반):", {
|
||||
tableName,
|
||||
@@ -316,12 +319,67 @@ export class ButtonActionExecutor {
|
||||
if (selectedRowsData && selectedRowsData.length > 0) {
|
||||
console.log(`다중 삭제 액션 실행: ${selectedRowsData.length}개 항목`, selectedRowsData);
|
||||
|
||||
// 테이블의 기본키 조회
|
||||
let primaryKeys: string[] = [];
|
||||
if (tableName) {
|
||||
try {
|
||||
const primaryKeysResult = await DynamicFormApi.getTablePrimaryKeys(tableName);
|
||||
if (primaryKeysResult.success && primaryKeysResult.data) {
|
||||
primaryKeys = primaryKeysResult.data;
|
||||
console.log(`🔑 테이블 ${tableName}의 기본키:`, primaryKeys);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("기본키 조회 실패, 폴백 방법 사용:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 각 선택된 항목을 삭제
|
||||
for (const rowData of selectedRowsData) {
|
||||
// 더 포괄적인 ID 찾기 (테이블 구조에 따라 다양한 필드명 시도)
|
||||
const deleteId = rowData.id || rowData.objid || rowData.pk || rowData.ID || rowData.OBJID || rowData.PK;
|
||||
let deleteId: any = null;
|
||||
|
||||
// 1순위: 데이터베이스에서 조회한 기본키 사용
|
||||
if (primaryKeys.length > 0) {
|
||||
const primaryKey = primaryKeys[0]; // 첫 번째 기본키 사용
|
||||
deleteId = rowData[primaryKey];
|
||||
console.log(`📊 기본키 ${primaryKey}로 ID 추출:`, deleteId);
|
||||
}
|
||||
|
||||
// 2순위: 폴백 - 일반적인 ID 필드명들 시도
|
||||
if (!deleteId) {
|
||||
deleteId =
|
||||
rowData.id ||
|
||||
rowData.objid ||
|
||||
rowData.pk ||
|
||||
rowData.ID ||
|
||||
rowData.OBJID ||
|
||||
rowData.PK ||
|
||||
// 테이블별 기본키 패턴들
|
||||
rowData.sales_no ||
|
||||
rowData.contract_no ||
|
||||
rowData.order_no ||
|
||||
rowData.seq_no ||
|
||||
rowData.code ||
|
||||
rowData.code_id ||
|
||||
rowData.user_id ||
|
||||
rowData.menu_id;
|
||||
|
||||
// _no로 끝나는 필드들 찾기
|
||||
if (!deleteId) {
|
||||
const noField = Object.keys(rowData).find((key) => key.endsWith("_no") && rowData[key]);
|
||||
if (noField) deleteId = rowData[noField];
|
||||
}
|
||||
|
||||
// _id로 끝나는 필드들 찾기
|
||||
if (!deleteId) {
|
||||
const idField = Object.keys(rowData).find((key) => key.endsWith("_id") && rowData[key]);
|
||||
if (idField) deleteId = rowData[idField];
|
||||
}
|
||||
|
||||
console.log(`🔍 폴백 방법으로 ID 추출:`, deleteId);
|
||||
}
|
||||
|
||||
console.log("선택된 행 데이터:", rowData);
|
||||
console.log("추출된 deleteId:", deleteId);
|
||||
console.log("최종 추출된 deleteId:", deleteId);
|
||||
|
||||
if (deleteId) {
|
||||
console.log("다중 데이터 삭제:", { tableName, screenId, id: deleteId });
|
||||
@@ -332,7 +390,9 @@ export class ButtonActionExecutor {
|
||||
}
|
||||
} else {
|
||||
console.error("삭제 ID를 찾을 수 없습니다. 행 데이터:", rowData);
|
||||
throw new Error(`삭제 ID를 찾을 수 없습니다. 사용 가능한 필드: ${Object.keys(rowData).join(", ")}`);
|
||||
throw new Error(
|
||||
`삭제 ID를 찾을 수 없습니다. 기본키: ${primaryKeys.join(", ")}, 사용 가능한 필드: ${Object.keys(rowData).join(", ")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
189
frontend/lib/utils/domPropsFilter.ts
Normal file
189
frontend/lib/utils/domPropsFilter.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* DOM props 필터링 유틸리티
|
||||
* React 전용 props들을 DOM 요소에 전달되지 않도록 필터링합니다.
|
||||
*/
|
||||
|
||||
// DOM에 전달하면 안 되는 React 전용 props 목록
|
||||
const REACT_ONLY_PROPS = new Set([
|
||||
// 컴포넌트 관련
|
||||
"component",
|
||||
"componentConfig",
|
||||
"config",
|
||||
"isSelected",
|
||||
"isDesignMode",
|
||||
"isInteractive",
|
||||
"size",
|
||||
"position",
|
||||
|
||||
// 이벤트 핸들러 (React 이벤트 외)
|
||||
"onFormDataChange",
|
||||
"onRefresh",
|
||||
"onClose",
|
||||
"onZoneComponentDrop",
|
||||
"onZoneClick",
|
||||
"onSelectedRowsChange",
|
||||
"onUpdateLayout",
|
||||
|
||||
// 데이터 관련
|
||||
"formData",
|
||||
"originalData",
|
||||
"selectedScreen",
|
||||
"allComponents",
|
||||
"refreshKey",
|
||||
|
||||
// 화면/테이블 관련
|
||||
"screenId",
|
||||
"tableName",
|
||||
|
||||
// 상태 관련
|
||||
"mode",
|
||||
"isInModal",
|
||||
|
||||
// 테이블 관련
|
||||
"selectedRows",
|
||||
"selectedRowsData",
|
||||
|
||||
// 추가된 React 전용 props
|
||||
"allComponents",
|
||||
]);
|
||||
|
||||
// DOM에 안전하게 전달할 수 있는 표준 HTML 속성들
|
||||
const SAFE_DOM_PROPS = new Set([
|
||||
// 표준 HTML 속성
|
||||
"id",
|
||||
"className",
|
||||
"style",
|
||||
"title",
|
||||
"lang",
|
||||
"dir",
|
||||
"role",
|
||||
"tabIndex",
|
||||
"accessKey",
|
||||
"contentEditable",
|
||||
"draggable",
|
||||
"hidden",
|
||||
"spellCheck",
|
||||
"translate",
|
||||
|
||||
// ARIA 속성 (aria-로 시작)
|
||||
// data 속성 (data-로 시작)
|
||||
|
||||
// 표준 이벤트 핸들러
|
||||
"onClick",
|
||||
"onDoubleClick",
|
||||
"onMouseDown",
|
||||
"onMouseUp",
|
||||
"onMouseOver",
|
||||
"onMouseOut",
|
||||
"onMouseEnter",
|
||||
"onMouseLeave",
|
||||
"onMouseMove",
|
||||
"onKeyDown",
|
||||
"onKeyUp",
|
||||
"onKeyPress",
|
||||
"onFocus",
|
||||
"onBlur",
|
||||
"onChange",
|
||||
"onInput",
|
||||
"onSubmit",
|
||||
"onReset",
|
||||
"onDragStart",
|
||||
"onDragEnd",
|
||||
"onDragOver",
|
||||
"onDragEnter",
|
||||
"onDragLeave",
|
||||
"onDrop",
|
||||
"onScroll",
|
||||
"onWheel",
|
||||
"onLoad",
|
||||
"onError",
|
||||
"onResize",
|
||||
]);
|
||||
|
||||
/**
|
||||
* props에서 React 전용 속성들을 제거하고 DOM 안전한 props만 반환
|
||||
*/
|
||||
export function filterDOMProps<T extends Record<string, any>>(props: T): Partial<T> {
|
||||
const filtered: Partial<T> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
// React 전용 props는 제외
|
||||
if (REACT_ONLY_PROPS.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// aria- 또는 data- 속성은 안전하게 포함
|
||||
if (key.startsWith("aria-") || key.startsWith("data-")) {
|
||||
filtered[key as keyof T] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 안전한 DOM props만 포함
|
||||
if (SAFE_DOM_PROPS.has(key)) {
|
||||
filtered[key as keyof T] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* props를 React 전용과 DOM 안전한 것으로 분리
|
||||
*/
|
||||
export function separateProps<T extends Record<string, any>>(
|
||||
props: T,
|
||||
): {
|
||||
reactProps: Partial<T>;
|
||||
domProps: Partial<T>;
|
||||
} {
|
||||
const reactProps: Partial<T> = {};
|
||||
const domProps: Partial<T> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
if (REACT_ONLY_PROPS.has(key)) {
|
||||
reactProps[key as keyof T] = value;
|
||||
} else if (key.startsWith("aria-") || key.startsWith("data-") || SAFE_DOM_PROPS.has(key)) {
|
||||
domProps[key as keyof T] = value;
|
||||
}
|
||||
// 둘 다 해당하지 않는 경우 무시 (안전을 위해)
|
||||
}
|
||||
|
||||
return { reactProps, domProps };
|
||||
}
|
||||
|
||||
/**
|
||||
* React 전용 props 여부 확인
|
||||
*/
|
||||
export function isReactOnlyProp(propName: string): boolean {
|
||||
return REACT_ONLY_PROPS.has(propName);
|
||||
}
|
||||
|
||||
/**
|
||||
* DOM 안전 props 여부 확인
|
||||
*/
|
||||
export function isDOMSafeProp(propName: string): boolean {
|
||||
return SAFE_DOM_PROPS.has(propName) || propName.startsWith("aria-") || propName.startsWith("data-");
|
||||
}
|
||||
|
||||
/**
|
||||
* 디버깅용: 필터링된 props 로깅
|
||||
*/
|
||||
export function logFilteredProps<T extends Record<string, any>>(
|
||||
originalProps: T,
|
||||
componentName: string = "Component",
|
||||
): void {
|
||||
const { reactProps, domProps } = separateProps(originalProps);
|
||||
|
||||
console.group(`🔍 ${componentName} Props 필터링`);
|
||||
console.log("📥 원본 props:", Object.keys(originalProps));
|
||||
console.log("⚛️ React 전용 props:", Object.keys(reactProps));
|
||||
console.log("🌐 DOM 안전 props:", Object.keys(domProps));
|
||||
|
||||
// React 전용 props가 DOM에 전달될 뻔한 경우 경고
|
||||
const reactPropsKeys = Object.keys(reactProps);
|
||||
if (reactPropsKeys.length > 0) {
|
||||
console.warn("⚠️ 다음 React 전용 props가 필터링되었습니다:", reactPropsKeys);
|
||||
}
|
||||
|
||||
console.groupEnd();
|
||||
}
|
||||
Reference in New Issue
Block a user