Files
invyone/frontend/types/input-type-mapping.ts
T
johngreen 8f92fb2368 refactor(테이블타입): 3-layer 분리 — DB 12개 유지, UI 8개 한정, widget variant
- input-type-mapping.ts: BaseInputType 10개 → UserSelectableInputType 8개 (박창현 image 2). vexplor_rps INPUT_TYPE_DETAIL_TYPES 포팅, select/checkbox/radio variant 를 code base 로 흡수
- input-types.ts: USER_SELECTABLE_INPUT_TYPE_ORDER/LABELS re-export (InputType 12개는 그대로)
- getDetailType.ts (신규): getWidgetVariants / getDefaultWidgetVariant helper
- 드롭다운 호출처 7개 8개 제한: ColumnDetailPanel, AddColumnModal, ColumnDefinitionTable, tableMngList/page.tsx, TableSettingModal, TypeOverviewStrip, types.ts
- ColumnDetailPanel: Legacy row 드롭다운 disabled + v5-glow-sm Alert 배너
- backward shim: BaseInputType / BASE_INPUT_TYPE_OPTIONS / getBaseInputType 등 V2/Properties/DetailSettingsPanel 호환

운영 DB 96.6% 가 이미 8개 안 (V0, 35,316 row). DB zero touch, mapper 5곳 보호.

spec: .omc/specs/deep-dive-table-type-storage-ui-separation.md (v3.2)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:43:26 +09:00

187 lines
9.7 KiB
TypeScript

/** 박창현 image 2 의 8개 — 사용자가 테이블 타입 관리에서 직접 고를 수 있는 base */
export type UserSelectableInputType =
| "text" | "number" | "date"
| "code" | "entity"
| "numbering" | "file" | "image";
/** 화면관리 widget 의 세부 variant */
export interface WidgetVariantOption {
value: string;
label: string;
description: string;
}
/**
* 8개 base 별 widget variant 매핑.
* vexplor_rps `input-type-mapping.ts:37-102` 의 variant 그대로 포팅.
* 박창현 결정 (Q3): select/checkbox/radio base 의 variant 는 모두 code base 로 흡수.
*/
export const INPUT_TYPE_DETAIL_TYPES: Record<UserSelectableInputType, WidgetVariantOption[]> = {
text: [
{ value: "text", label: "일반 텍스트", description: "기본 텍스트 입력" },
{ value: "email", label: "이메일", description: "이메일 주소 입력" },
{ value: "tel", label: "전화번호", description: "전화번호 입력" },
{ value: "url", label: "URL", description: "웹사이트 주소 입력" },
{ value: "password", label: "비밀번호", description: "마스킹 입력" },
{ value: "textarea", label: "여러 줄 텍스트", description: "긴 텍스트 영역" },
],
number: [
{ value: "number", label: "정수", description: "정수 숫자 입력" },
{ value: "decimal", label: "소수", description: "소수점 포함" },
{ value: "currency", label: "통화", description: "₩ 1,000 형식" },
{ value: "percentage", label: "퍼센트", description: "50% 형식" },
],
date: [
{ value: "date", label: "날짜", description: "YYYY-MM-DD" },
{ value: "datetime", label: "날짜+시간", description: "날짜와 시간" },
{ value: "time", label: "시간", description: "HH:mm" },
{ value: "daterange", label: "기간", description: "시작일 ~ 종료일" },
{ value: "month", label: "월", description: "YYYY-MM" },
{ value: "year", label: "년", description: "YYYY" },
],
code: [
{ value: "code", label: "코드 선택박스", description: "드롭다운으로 코드 선택" },
{ value: "code-autocomplete", label: "코드 자동완성", description: "코드/코드명 검색" },
{ value: "code-radio", label: "코드 라디오", description: "라디오 버튼 그룹" },
{ value: "code-radio-horizontal", label: "가로 라디오", description: "가로 배치 라디오" },
{ value: "code-radio-vertical", label: "세로 라디오", description: "세로 배치 라디오" },
{ value: "dropdown", label: "검색 선택박스", description: "검색 기능 포함 (vexplor_rps select base)" },
{ value: "multiselect", label: "다중 선택", description: "여러 항목 선택 (vexplor_rps select base)" },
{ value: "autocomplete", label: "자동완성", description: "입력하면 자동완성 제안 (vexplor_rps select base)" },
{ value: "checkbox", label: "체크박스", description: "단일 체크박스 (vexplor_rps checkbox base)" },
{ value: "checkbox-group", label: "체크박스 그룹", description: "여러 체크박스 (vexplor_rps checkbox base)" },
{ value: "boolean", label: "On/Off 스위치", description: "boolean 스위치 (vexplor_rps checkbox base)" },
],
entity: [
{ value: "entity", label: "엔티티 참조", description: "다른 테이블 데이터 참조" },
{ value: "entity-autocomplete", label: "엔티티 자동완성", description: "검색 결과 inline 표시" },
{ value: "entity-popup", label: "엔티티 팝업", description: "별도 검색 팝업" },
],
file: [
{ value: "file", label: "단일 파일", description: "파일 1개 첨부" },
{ value: "file-list", label: "다중 파일", description: "여러 파일 첨부" },
{ value: "file-drop", label: "드래그 앤 드롭", description: "drop zone 형태" },
],
image: [
{ value: "image", label: "이미지", description: "이미지 1장 표시/업로드" },
{ value: "image-gallery", label: "이미지 갤러리", description: "여러 장 grid 표시" },
{ value: "image-upload", label: "이미지 업로드", description: "크롭/리사이즈 포함" },
],
numbering: [
{ value: "numbering", label: "자동 채번", description: "옵션설정의 채번 규칙으로 자동 생성" },
],
};
/** 8개 base 의 한글 라벨 */
export const USER_SELECTABLE_INPUT_TYPE_LABELS: Record<UserSelectableInputType, string> = {
text: "텍스트",
number: "숫자",
date: "날짜",
code: "코드",
entity: "테이블참조",
numbering: "채번",
file: "파일",
image: "이미지",
};
/** 8개 base 의 순서 (드롭다운/카드 표시 순서) */
export const USER_SELECTABLE_INPUT_TYPE_ORDER: UserSelectableInputType[] = [
"text", "number", "date",
"code", "entity",
"numbering", "file", "image",
];
export function isUserSelectableInputType(value: string): value is UserSelectableInputType {
return USER_SELECTABLE_INPUT_TYPE_ORDER.includes(value as UserSelectableInputType);
}
// ─────────────────────────────────────────────────────────────────────────
// Backward Shim — 사용처 3곳 (V2PropertiesPanel/PropertiesPanel/DetailSettingsPanel) 임시 호환
// ─────────────────────────────────────────────────────────────────────────
/**
* @deprecated v3.2: BaseInputType 은 UserSelectableInputType (8개) 로 대체.
* 이 export 는 backward shim — 사용처 3곳 임시 호환. 후속 PR 에서 strangle.
*/
export type BaseInputType =
| UserSelectableInputType
| "textarea"
| "select"
| "checkbox"
| "radio";
/**
* @deprecated v3.2: WidgetVariantOption 로 대체.
* 사용처 3곳의 DetailTypeOption import 호환용.
*/
export type DetailTypeOption = WidgetVariantOption;
/**
* @deprecated v3.2: UserSelectableInputType 의 8개로 사용 권장.
* 사용처 3곳의 BASE_INPUT_TYPE_OPTIONS import 호환용.
*/
export const BASE_INPUT_TYPE_OPTIONS: Array<{ value: BaseInputType; label: string; description: string }> = [
{ value: "text", label: "텍스트", description: "텍스트 입력 필드" },
{ value: "textarea", label: "텍스트 에리어", description: "여러 줄 텍스트 입력 (legacy — text base 의 variant)" },
{ value: "number", label: "숫자", description: "숫자 입력 필드" },
{ value: "date", label: "날짜", description: "날짜/시간 선택" },
{ value: "code", label: "코드", description: "공통 코드 선택" },
{ value: "entity", label: "엔티티", description: "다른 테이블 참조" },
{ value: "select", label: "선택박스", description: "드롭다운 선택 (legacy — code base 의 variant)" },
{ value: "checkbox", label: "체크박스", description: "체크박스/스위치 (legacy — code base 의 variant)" },
{ value: "radio", label: "라디오버튼", description: "라디오 버튼 그룹 (legacy — code base 의 variant)" },
{ value: "image", label: "이미지", description: "이미지 표시" },
{ value: "numbering", label: "자동 채번", description: "옵션설정 기반 자동 번호" },
{ value: "file", label: "파일", description: "파일 업로드" },
];
/**
* @deprecated v3.2: webType → UserSelectableInputType 로 매핑 권장 (`getUserSelectableInputType`).
* 사용처 3곳의 getBaseInputType 호환용.
*/
export function getBaseInputType(webType: string): BaseInputType {
if (["text", "email", "tel", "url", "password"].includes(webType)) return "text";
if (webType === "textarea") return "textarea";
if (["number", "decimal", "currency", "percentage"].includes(webType)) return "number";
if (["date", "datetime", "time", "daterange", "month", "year"].includes(webType)) return "date";
if (["code", "code-autocomplete", "code-radio", "code-radio-horizontal", "code-radio-vertical"].includes(webType)) return "code";
if (["select", "dropdown", "multiselect", "autocomplete"].includes(webType)) return "select";
if (["checkbox", "boolean", "checkbox-group"].includes(webType)) return "checkbox";
if (["radio", "radio-horizontal", "radio-vertical"].includes(webType)) return "radio";
if (webType === "entity" || webType.startsWith("entity-")) return "entity";
if (webType === "image" || webType.startsWith("image-")) return "image";
if (webType === "file" || webType.startsWith("file-")) return "file";
if (webType === "numbering") return "numbering";
return "text";
}
/** 신규 권장 함수 — UserSelectableInputType 직접 반환 */
export function getUserSelectableInputType(webType: string): UserSelectableInputType {
const base = getBaseInputType(webType);
if (base === "textarea") return "text";
if (base === "select" || base === "checkbox" || base === "radio") return "code";
return base as UserSelectableInputType;
}
/**
* @deprecated v3.2: getWidgetVariants (lib/utils/getDetailType.ts) 권장.
* 사용처의 getDetailTypes import 호환용.
*/
export function getDetailTypes(baseInputType: BaseInputType): DetailTypeOption[] {
// legacy base → UserSelectableInputType 매핑 후 variant 조회
let key: UserSelectableInputType;
if (baseInputType === "textarea") key = "text";
else if (baseInputType === "select" || baseInputType === "checkbox" || baseInputType === "radio") key = "code";
else key = baseInputType;
return INPUT_TYPE_DETAIL_TYPES[key] ?? [];
}
/**
* @deprecated v3.2: getDefaultWidgetVariant (lib/utils/getDetailType.ts) 권장.
* 사용처의 getDefaultDetailType import 호환용.
*/
export function getDefaultDetailType(baseInputType: BaseInputType): string {
const variants = getDetailTypes(baseInputType);
return variants[0]?.value ?? baseInputType;
}