|
toggleGroupCollapse(group.groupKey)}
>
{isCollapsed ? (
diff --git a/frontend/lib/registry/components/text-input/TextInputComponent.tsx b/frontend/lib/registry/components/text-input/TextInputComponent.tsx
index dd516c7e..9ce5fa21 100644
--- a/frontend/lib/registry/components/text-input/TextInputComponent.tsx
+++ b/frontend/lib/registry/components/text-input/TextInputComponent.tsx
@@ -718,7 +718,13 @@ export const TextInputComponent: React.FC = ({
: componentConfig.placeholder || defaultPlaceholder
}
pattern={validationPattern}
- title={webType === "tel" ? "전화번호 형식: 010-1234-5678" : undefined}
+ title={
+ webType === "tel"
+ ? "전화번호 형식: 010-1234-5678"
+ : component.label
+ ? `${component.label}${component.columnName ? ` (${component.columnName})` : ""}`
+ : component.columnName || undefined
+ }
disabled={componentConfig.disabled || false}
required={componentConfig.required || false}
readOnly={componentConfig.readonly || (testAutoGeneration.enabled && testAutoGeneration.type !== "none")}
diff --git a/frontend/lib/utils/buttonActions.ts b/frontend/lib/utils/buttonActions.ts
index 4781c6c4..c4dc8b86 100644
--- a/frontend/lib/utils/buttonActions.ts
+++ b/frontend/lib/utils/buttonActions.ts
@@ -1987,7 +1987,12 @@ export class ButtonActionExecutor {
*/
private static async handleExcelUpload(config: ButtonActionConfig, context: ButtonActionContext): Promise {
try {
- console.log("📤 엑셀 업로드 모달 열기:", { config, context });
+ console.log("📤 엑셀 업로드 모달 열기:", {
+ config,
+ context,
+ userId: context.userId,
+ tableName: context.tableName,
+ });
// 동적 import로 모달 컴포넌트 로드
const { ExcelUploadModal } = await import("@/components/common/ExcelUploadModal");
@@ -2004,11 +2009,28 @@ export class ButtonActionExecutor {
document.body.removeChild(modalContainer);
};
+ // localStorage 디버깅
+ const modalId = `excel-upload-${context.tableName || ""}`;
+ const storageKey = `modal_size_${modalId}_${context.userId || "guest"}`;
+ console.log("🔍 엑셀 업로드 모달 localStorage 확인:", {
+ modalId,
+ userId: context.userId,
+ storageKey,
+ savedSize: localStorage.getItem(storageKey),
+ });
+
root.render(
React.createElement(ExcelUploadModal, {
open: true,
onOpenChange: (open: boolean) => {
- if (!open) closeModal();
+ if (!open) {
+ // 모달 닫을 때 localStorage 확인
+ console.log("🔍 모달 닫을 때 localStorage:", {
+ storageKey,
+ savedSize: localStorage.getItem(storageKey),
+ });
+ closeModal();
+ }
},
tableName: context.tableName || "",
uploadMode: config.excelUploadMode || "insert",
diff --git a/frontend/lib/utils/dbTypeMapping.ts b/frontend/lib/utils/dbTypeMapping.ts
index 77778d37..a34cb847 100644
--- a/frontend/lib/utils/dbTypeMapping.ts
+++ b/frontend/lib/utils/dbTypeMapping.ts
@@ -60,6 +60,16 @@ export const DB_TYPE_TO_WEB_TYPE: Record = {
* 컬럼명 기반 스마트 웹 타입 추론 규칙
*/
export const COLUMN_NAME_TO_WEB_TYPE: Record = {
+ // 이미지 관련
+ image: "image",
+ img: "image",
+ picture: "image",
+ photo: "image",
+ thumbnail: "image",
+ avatar: "image",
+ icon: "image",
+ logo: "image",
+
// 이메일 관련
email: "email",
mail: "email",
diff --git a/frontend/lib/utils/webTypeMapping.ts b/frontend/lib/utils/webTypeMapping.ts
index 07aa0e90..89c3fb2a 100644
--- a/frontend/lib/utils/webTypeMapping.ts
+++ b/frontend/lib/utils/webTypeMapping.ts
@@ -42,6 +42,12 @@ export const WEB_TYPE_COMPONENT_MAPPING: Record = {
// 파일
file: "file-upload",
+ // 이미지
+ image: "image-widget",
+ img: "image-widget",
+ picture: "image-widget",
+ photo: "image-widget",
+
// 버튼
button: "button-primary",
diff --git a/frontend/types/input-type-mapping.ts b/frontend/types/input-type-mapping.ts
index 6943761c..30d87244 100644
--- a/frontend/types/input-type-mapping.ts
+++ b/frontend/types/input-type-mapping.ts
@@ -8,7 +8,7 @@
import { WebType } from "./unified-core";
/**
- * 8개 핵심 입력 타입
+ * 9개 핵심 입력 타입
*/
export type BaseInputType =
| "text" // 텍스트
@@ -18,7 +18,8 @@ export type BaseInputType =
| "entity" // 엔티티
| "select" // 선택박스
| "checkbox" // 체크박스
- | "radio"; // 라디오버튼
+ | "radio" // 라디오버튼
+ | "image"; // 이미지
/**
* 세부 타입 옵션 인터페이스
@@ -92,6 +93,9 @@ export const INPUT_TYPE_DETAIL_TYPES: Record
{ value: "radio-horizontal", label: "가로 라디오", description: "가로 배치" },
{ value: "radio-vertical", label: "세로 라디오", description: "세로 배치" },
],
+
+ // 이미지 → image
+ image: [{ value: "image", label: "이미지", description: "이미지 URL 표시" }],
};
/**
@@ -136,6 +140,9 @@ export function getBaseInputType(webType: WebType): BaseInputType {
// entity
if (webType === "entity") return "entity";
+ // image
+ if (webType === "image") return "image";
+
// 기본값: text
return "text";
}
@@ -167,6 +174,7 @@ export const BASE_INPUT_TYPE_OPTIONS: Array<{ value: BaseInputType; label: strin
{ value: "select", label: "선택박스", description: "드롭다운 선택" },
{ value: "checkbox", label: "체크박스", description: "체크박스/스위치" },
{ value: "radio", label: "라디오버튼", description: "라디오 버튼 그룹" },
+ { value: "image", label: "이미지", description: "이미지 표시" },
];
/**
diff --git a/frontend/types/input-types.ts b/frontend/types/input-types.ts
index 40753195..e172e620 100644
--- a/frontend/types/input-types.ts
+++ b/frontend/types/input-types.ts
@@ -15,7 +15,8 @@ export type InputType =
| "category" // 카테고리
| "select" // 선택박스
| "checkbox" // 체크박스
- | "radio"; // 라디오버튼
+ | "radio" // 라디오버튼
+ | "image"; // 이미지
// 입력 타입 옵션 정의
export interface InputTypeOption {
@@ -97,6 +98,13 @@ export const INPUT_TYPE_OPTIONS: InputTypeOption[] = [
category: "selection",
icon: "Circle",
},
+ {
+ value: "image",
+ label: "이미지",
+ description: "이미지 표시",
+ category: "basic",
+ icon: "Image",
+ },
];
// 카테고리별 입력 타입 그룹화
diff --git a/frontend/types/unified-core.ts b/frontend/types/unified-core.ts
index 0133f2a6..6f7c2b40 100644
--- a/frontend/types/unified-core.ts
+++ b/frontend/types/unified-core.ts
@@ -36,6 +36,7 @@ export type WebType =
| "code" // 공통코드 참조
| "entity" // 엔티티 참조
| "file" // 파일 업로드
+ | "image" // 이미지 표시
| "button"; // 버튼 컴포넌트
/**
|