Consolidate canonical input migration
Build & Deploy to K8s / build-and-deploy (push) Failing after 11m17s
Build & Deploy to K8s / build-and-deploy (push) Failing after 11m17s
Remove legacy v2 input/select and file/media runtimes, add canonical option/file loaders, and document Codex handoff.
This commit is contained in:
@@ -2,27 +2,27 @@
|
||||
|
||||
날짜: 2026-05-07 ~ 2026-05-11
|
||||
작업자: gbpark
|
||||
컨텍스트: 인비원스튜디오의 입력 컴포넌트 (input / v2-input / v2-select / 옛 6개) 가 분산되어 외형·모델 들쭉날쭉. **canonical 1안 (InvFieldConfigPanel + InputComponent)** 으로 통합 중.
|
||||
컨텍스트: 인비원스튜디오의 입력 계열을 **FieldConfig / DataPort 계약을 지키는 canonical `input`** 으로 통합 중. 설정 패널은 계약을 편집하는 UI일 뿐, 진실의 원천은 `frontend/types/invyone-component.ts` 의 FieldConfig / DataPort.
|
||||
|
||||
---
|
||||
|
||||
## 0. 핵심 원칙
|
||||
|
||||
- INVYONE = VEX 의 2세대 리뉴얼. **운영 단계 아님** → 옛 키 fallback / 호환 부담 X. 깨끗한 canonical 1안.
|
||||
- 옛것이 남아있으면 통합 아님. **1 패널 1 컴포넌트**.
|
||||
- FieldConfig 가 유일한 필드 규격이고, DataPort / Connection 이 컴포넌트 통신 계약.
|
||||
- 옛것이 남아있으면 통합 아님. V2 입력/선택은 구현체·alias·fallback·DB 마이그 대상이 아니라 제거 대상.
|
||||
- GPT-5.5 (codex:rescue) 와 단계마다 교차 검증.
|
||||
|
||||
## 1. 큰 그림 (목표 형태)
|
||||
|
||||
```
|
||||
[8 통합 컴포넌트] = [8 단일 ConfigPanel + 단일 캔버스 컴포넌트]
|
||||
input → InvFieldConfigPanel + InputComponent (text/number/money/date/single/multi/autonum/formula/audit/file)
|
||||
[8 통합 컴포넌트] = [FieldConfig/DataPort 계약을 소비하는 단일 캔버스 컴포넌트]
|
||||
input → FieldConfig + DataPort + InputComponent (text/number/money/date/single/multi/autonum/formula/audit/file)
|
||||
table → InvTableConfigPanel
|
||||
search · button · title · divider · stats · container
|
||||
|
||||
[옛 V2 / 옛 6개 컴포넌트] → 기능 이식 후 폐기
|
||||
V2Input.tsx (1286줄)
|
||||
V2Select.tsx (1350줄)
|
||||
옛 입력/선택 본체 2개 — 삭제 완료, 필요한 기능은 canonical input 으로 흡수
|
||||
date-input / text-input / number-input / select-basic / checkbox-basic / textarea-basic 의 자체 캔버스 컴포넌트 6개
|
||||
```
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
- ✅ `DynamicComponentRenderer.tsx:418-453` 의 fieldType / dbInputType → v2-input/v2-select **강제 swap 분기 통째 제거**
|
||||
- ✅ `webTypeMapping.ts` 의 text 계열 9개 (text/email/password/tel/url/textarea/number/decimal/label) → `input`
|
||||
- ✅ 기본 fallback 도 `v2-input` → `input`
|
||||
- ✅ 초기 fallback 도 `input` canonical 로 정리했고, Phase D.2 에서 V2 입력/선택 fallback 자체 제거
|
||||
|
||||
### Phase 4 — InputComponent 외형 통일
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
- ✅ `RadioPicker` 신규 — single + mode=radio (라디오 button list)
|
||||
- ✅ `CheckboxListPicker` 신규 — multi + mode=check (체크박스 list, maxSelect 차단)
|
||||
- ✅ InputComponent select 분기 — mode 따라 4 picker 분기 (Single/Multi/Radio/CheckboxList)
|
||||
- ✅ ConfigPanel "선택 방식" 옵션을 multi prop 따라 분기 — single: dropdown/combobox/radio/toggle, multi: dropdown/combobox/check/tag
|
||||
- ✅ ConfigPanel "선택 방식" 옵션을 multi prop 따라 분기 — single: dropdown/combobox/radio/toggle, multi: dropdown/combobox/check/swap/tag
|
||||
- ✅ TYPE_VOLATILE_FIELDS 에 `maxSelect` 추가 (`mode` 는 기존)
|
||||
|
||||
### Phase B.4 추가 정리 — 외각 box + 복수 선택 토글
|
||||
@@ -117,6 +117,355 @@
|
||||
|
||||
## 2026-05-11 진행 (이번 세션)
|
||||
|
||||
### Phase C 보정 — entity 는 code-name 옵션 source (2026-05-12)
|
||||
|
||||
**배경**: 1차 C에서 `format=entity` 를 검색 모달로 해석했으나 사용자 점검으로 계약 오류 확인.
|
||||
INVYONE input 의 entity 는 DB FK 를 직접 걸 수 없는 경우 화면 설정에서 참조 테이블과
|
||||
저장 값/표시 라벨 컬럼을 지정해 code-name 옵션을 가져오는 선택형이다.
|
||||
검색 모달은 별도 `entity-search-input` 계열의 책임이지 canonical input entity 의 기본 동작이 아니다.
|
||||
|
||||
**변경**:
|
||||
- ✅ `useOptionLoader` — `source=entity` 를 `/entity/{entityTable}/options?value={entityValueColumn}&label={entityLabelColumn}` 로 로드
|
||||
- `config.ref.table/valueColumn/displayColumn` 도 같은 계약으로 처리
|
||||
- ✅ `InputComponent` — `type=single|multi + format=entity` 는 select 계열 picker 로 렌더
|
||||
- 단일 entity: `SingleSelectPicker` (검색 가능 dropdown)
|
||||
- 다중 entity: `MultiSelectPicker` / `mode=check` / `mode=swap` 지원
|
||||
- ✅ 잘못 추가된 canonical input 전용 `EntityPicker` 모달 경로 제거
|
||||
- ✅ `V2PropertiesPanel` / `InvFieldConfigPanel` — 참조 테이블 목록에서
|
||||
`table_name/display_name` 과 `tableName/displayName` 을 모두 정규화
|
||||
|
||||
**미구현 (후속)**:
|
||||
- 옵션 필터 (`filters`) 의 runtime query 전달
|
||||
|
||||
### Phase C.2 — v2-input/v2-select 재유입 차단 (2026-05-12)
|
||||
|
||||
**배경**: 목표는 V2 입력/선택 컴포넌트를 계속 쓰는 게 아니라, 필요한 기능만 `input` canonical 로 흡수하는 것. 그런데 webType 매핑과 renderer 우회로가 여전히 `v2-select` 를 생성/호출하고 있었음.
|
||||
|
||||
**변경**:
|
||||
- ✅ `webTypeMapping.ts` — radio/checkbox/boolean/code/entity/category 모두 `componentType: "input"` 으로 변경
|
||||
- ✅ `DynamicComponentRenderer.tsx` — category 고급 모드에서 `V2SelectRenderer` 를 직접 require 하던 분기 제거
|
||||
- ✅ `components/index.ts` — `v2-input/V2InputRenderer`, `v2-select/V2SelectRenderer` auto-register import 제거
|
||||
- ✅ `registerV2Components.ts` — `v2-input`, `v2-select` 레지스트리 등록 제거
|
||||
- ✅ `InputComponent.tsx` — `format="entity"` 는 select 계열 picker 로 라우팅
|
||||
- ✅ `useOptionLoader.ts` — `entityTable/entityValueColumn/entityLabelColumn` 로 code-name options 로드
|
||||
- ✅ `ScreenSettingModal.tsx` — 폼 필드 자동 추가 시 `text-input` 대신 `input` canonical 생성
|
||||
|
||||
**검증**:
|
||||
- `git diff --check` 통과
|
||||
- `npx tsc --noEmit --pretty false` 는 기존 전역 타입 오류로 실패. 변경 파일 필터 기준 신규 오류 없음.
|
||||
|
||||
### Phase C — entity 선택형 보정 (2026-05-12 완료)
|
||||
|
||||
**배경**: input entity 는 마스터 데이터 (거래처/품목/사원) 의 참조 테이블에서 저장 값(code)과
|
||||
표시 라벨(name)을 지정해 옵션으로 가져오는 기능. DB FK 강제 대신 화면 레벨에서 code-name 참조를 건다.
|
||||
|
||||
**변경**:
|
||||
- ✅ `InputComponent.tsx` — case "entity" 는 모달이 아니라 `SingleSelectPicker` / `MultiSelectPicker`
|
||||
- ✅ `useOptionLoader.ts` — entity source option loading 추가
|
||||
- ✅ `frontend/lib/registry/components/input/entity-picker.tsx` 삭제 — canonical input 에 모달 검색 재유입 방지
|
||||
|
||||
**관련 파일 맵 업데이트**:
|
||||
- canonical: `frontend/lib/registry/components/input/use-option-loader.ts` 의 `source=entity`
|
||||
- 별도 검색 UI: `lib/registry/components/entity-search-input/` 는 명시 검색 컴포넌트가 필요할 때만 사용
|
||||
|
||||
### Phase C.3 — entity code-name 안정화 (2026-05-12)
|
||||
|
||||
**배경**: 1차 C 후 사용자 점검 — InvFieldConfigPanel 의 entity 설정 UI 에서 참조 테이블 dropdown 이
|
||||
가끔 비고, value/label 컬럼을 바꾼 뒤에도 옵션이 갱신되지 않는 케이스 확인. 검색 모달 재유입은
|
||||
없어야 한다는 계약은 그대로 유지.
|
||||
|
||||
**점검 결과 — 이미 정상**:
|
||||
- `V2PropertiesPanel.normalizeConfigPanelTables` — `tableName/displayName` 과 `table_name/display_name` 모두 흡수.
|
||||
InvFieldConfigPanel 에 `tables` / `allTables` 정규화된 값 전달
|
||||
- `InvFieldConfigPanel.normalizeTableSelectOptions` — 동일하게 양쪽 키 흡수. EntityOptions 호출 시
|
||||
`allTables.length > 0 ? allTables : tables` 폴백
|
||||
- `InvFieldConfigPanel.loadColumnsForTable` — `columnName/column_name` + `displayName/display_name` 흡수
|
||||
- `InputComponent.tsx` case "entity" — `SingleSelectPicker` / `MultiSelectPicker` / `CheckboxListPicker` /
|
||||
`SwapPicker` 로만 라우팅. 모달 / EntityPicker import 없음
|
||||
- `useOptionLoader.ts` source=entity — `/entity/{entityTable}/options?value={...}&label={...}` 로 fetch.
|
||||
응답 shape (`data[]`, `data.success+data`, `data.options`) 정상 normalize
|
||||
|
||||
**수정 — fetchUrl dep 누락 (옵션 갱신 안 되는 진짜 원인)**:
|
||||
- `use-option-loader.ts` 의 `fetchUrl` useMemo 의존성 배열에 다음 6개 추가:
|
||||
- `config.entityTable` / `config.entityValueColumn` / `config.entityLabelColumn`
|
||||
- `config.ref?.table` / `config.ref?.valueColumn` / `config.ref?.displayColumn`
|
||||
- ref 객체 자체를 dep 으로 넣지 않은 이유: 객체 reference 변동만으로 effect 폭주를 방지하기 위해
|
||||
내부 키만 추출
|
||||
|
||||
**디자인 모드 가드**:
|
||||
- `useOptionLoader` 는 `isDesignMode === true` 시 `needsFetch = false` 로 fetch 자체 skip
|
||||
- `InvFieldConfigPanel` 의 테이블/컬럼 목록 로드는 별도 경로 (apiClient 직접 호출, isDesignMode 무관)
|
||||
→ 설정 패널 동작은 그대로 허용
|
||||
|
||||
**canonical input 에 모달 재유입 없음 (확인)**:
|
||||
- `rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx` → 0건
|
||||
|
||||
### Phase C.4 — option filters runtime 적용 (2026-05-12)
|
||||
|
||||
**배경**: `OptionFilter[]` 가 InvFieldConfigPanel 에 저장만 되고 runtime 에 반영되지 않았음.
|
||||
canonical input 의 entity / distinct / db source 에서 filter 를 실제 query 로 전달해 결과 옵션을 좁힌다.
|
||||
검색 모달 재유입 / v2-input·v2-select 재도입 / FieldConfig·DataPort 축소는 모두 금지.
|
||||
|
||||
**변경**:
|
||||
- ✅ `use-option-loader.ts` — `OptionLoaderConfig.filters?: OptionFilter[]` 추가
|
||||
- ✅ `OptionUserContext` 타입 신규 — `companyCode / userId / deptCode / userName`
|
||||
- ✅ `UseOptionLoaderArgs.userContext` 추가 — `value_type === "user"` 필터 치환용
|
||||
- ✅ `resolveFilters(filters, formData, userContext)` 헬퍼 — 치환 규칙:
|
||||
- `column` trim 후 빈 값 → skip
|
||||
- `value_type=static` → `f.value` 그대로
|
||||
- `value_type=field` → `formData[field_ref]`, 값 없으면 skip
|
||||
- `value_type=user` → `userContext[user_field]`, 값 없으면 skip
|
||||
- `isNull / isNotNull` → value 없이 통과
|
||||
- `in / notIn` → 배열 또는 `"a,b,c"` 문자열 모두 trim 된 배열로 정규화
|
||||
- ✅ `resolvedFiltersJson` useMemo — runtime 치환 결과를 `JSON.stringify` 로 stable string 화.
|
||||
결과가 빈 배열이면 `undefined` (URL 에 query 자체 미추가)
|
||||
- ✅ `fetchUrl` useMemo — `filters=` URL-encoded JSON 으로 append:
|
||||
- **entity**: `/entity/{table}/options?value={v}&label={l}&filters={...}` (1순위)
|
||||
- **distinct / select**: `/entity/{table}/distinct/{column}?filters={...}`
|
||||
- **db (legacy)**: `/entity/{table}/options?value={v}&label={l}&filters={...}`
|
||||
- **code / category / api**: 백엔드 endpoint 가 filter 스펙을 정의하지 않아 미적용 (TODO 주석 명시)
|
||||
- ✅ `fetchUrl` dep 배열에 `resolvedFiltersJson` 추가 → filter 값 변경 시 URL 재생성 → cache key 자동 신규화
|
||||
- ✅ `resolvedFiltersJson` 자체의 dep — `config.filters`, `formData`, `userContext` 4 키 (객체 reference 폭주 방지)
|
||||
- ✅ `InputComponent.tsx` — props 에서 `companyCode / user_id / dept_code / user_name` 등 camel/snake 모두 흡수해
|
||||
`userContext` 객체 구성 후 `useOptionLoader` 에 전달. DOM noise 누설 방지를 위해 destructure 목록에 4개 추가
|
||||
|
||||
**filter 치환 예시 — entity URL**:
|
||||
```
|
||||
config.entityTable = "tb_customer";
|
||||
config.entityValueColumn = "customer_code";
|
||||
config.entityLabelColumn = "customer_name";
|
||||
config.filters = [
|
||||
{ column: "is_active", operator: "=", value_type: "static", value: "Y" },
|
||||
{ column: "company_code", operator: "=", value_type: "user", user_field: "companyCode" },
|
||||
];
|
||||
// runtime 사용자 companyCode = "C0001"
|
||||
|
||||
→ /entity/tb_customer/options?value=customer_code&label=customer_name
|
||||
&filters=%5B%7B%22column%22%3A%22is_active%22%2C%22operator%22%3A%22%3D%22%2C%22value%22%3A%22Y%22%7D%2C%7B%22column%22%3A%22company_code%22%2C%22operator%22%3A%22%3D%22%2C%22value%22%3A%22C0001%22%7D%5D
|
||||
```
|
||||
|
||||
**cache / race / design mode 영향**:
|
||||
- **cache**: 기존 `responseCache: Map<url, options>`. filters 값이 바뀌면 URL 이 신규 → cache key 자동 신규.
|
||||
이전 결과는 그대로 보존되어 같은 필터로 돌아오면 즉시 hit
|
||||
- **race**: 기존 `reqIdRef` + `cancelled` flag 유지. URL 변경 시 in-flight 요청 결과 무시
|
||||
- **design mode**: 기존 `isDesignMode === true` 면 `needsFetch=false` 로 fetch skip 흐름 그대로. filter resolver
|
||||
는 dep 평가 단계에서만 도는 정도이고 API 호출 자체가 없음
|
||||
|
||||
**InvFieldConfigPanel UI**: 이미 filters 입력 UI 존재. 이번 단계는 runtime 전달만 보완, UI/문구 변경 없음.
|
||||
|
||||
**검증**:
|
||||
- `git diff --check` — whitespace 0
|
||||
- `rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles` — 0건
|
||||
- `rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx` — 0건
|
||||
- `tsc` 변경 파일 (`use-option-loader`, `InputComponent`) 신규 오류 0건
|
||||
|
||||
### Phase D.4 — file / image / img → canonical input 통합 (2026-05-12)
|
||||
|
||||
**배경**: webTypeMapping 의 `file / image / img` 와 DynamicWebTypeRenderer 의 강제 분기가
|
||||
여전히 `v2-file-upload / FileUploadComponent / ImageWidget` 로 빠지고 있었음. canonical input
|
||||
에 file 분기는 기존부터 있었지만 native `<input type=file>` 단독이라 미리보기 / 다중 칩 / 삭제
|
||||
UX 가 빠져 있었음. 옛 본체 파일 삭제는 사용처 0건 확인 후 별도 phase.
|
||||
|
||||
**변경**:
|
||||
- ✅ `frontend/lib/registry/components/input/file-picker.tsx` 신규 — `FilePicker`
|
||||
- props: `value / onChange / accept / multiple / maxFiles / disabled / readonly / placeholder / showPreview / className`
|
||||
- 값 형태: `File | string | Array<File | string> | null` (서버 저장된 path 문자열도 흡수)
|
||||
- 이미지면 `URL.createObjectURL` preview thumbnail (cleanup 효과 포함, 메모리 누수 방지)
|
||||
- SSR/Node 경로에서 `File` 전역이 없을 수 있어 `typeof File !== "undefined"` 가드 적용
|
||||
- 그 외 파일은 `FileText` 아이콘 + 파일명 (max-w-160 truncate + tooltip)
|
||||
- 다중 시 `maxFiles` 초과 자르기 + 한도 도달 시 `+추가` 버튼 disabled
|
||||
- `disabled / readonly` → `lockEdit` 통합 (선택/삭제/추가 모두 차단)
|
||||
- 같은 파일 재선택 가능하도록 hidden input value 매번 초기화
|
||||
- ✅ `frontend/lib/registry/components/input/types.ts` — `InputConfig` 에 `maxFiles / showPreview` 추가
|
||||
- ✅ `frontend/lib/registry/components/input/InputComponent.tsx` — case "file"
|
||||
- native `<input type=file>` 단독 → **FilePicker** 호출
|
||||
- `format === "image"` 면 자동 `accept="image/*"` + `showPreview=true`
|
||||
- `format === "doc"` 면 `.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx`
|
||||
- 사용자 명시 `accept / showPreview` 가 있으면 그 값 우선
|
||||
- fallback webType 에 `img / picture / photo` 도 file 로 흡수
|
||||
- ✅ `frontend/lib/utils/webTypeMapping.ts`
|
||||
- `file / image / img` 의 `WEB_TYPE_V2_MAPPING` 항목 → `componentType: "input"` 으로 변경
|
||||
- config triple: `{ kind: "attach", type: "file", format: "file" | "image", accept, multiple, maxFiles, showPreview }`
|
||||
- `WEB_TYPE_COMPONENT_MAPPING` 도 `file/image/img → "input"`
|
||||
- ✅ `frontend/lib/registry/DynamicWebTypeRenderer.tsx`
|
||||
- `webType === "file" / "image" / "img" / "picture" / "photo"` 와 `props.component?.type === "file"` 모두
|
||||
canonical `InputComponent` 로 라우팅 (file config triple 주입). 옛 `FileUploadComponent` / `ImageWidget`
|
||||
직접 import 분기 3곳 제거 (참조만 끊고 파일 자체는 잔존 — 별도 phase)
|
||||
- 기존 타입 mismatch 보정: `webType/web_type` 양쪽 prop 흡수, `defaultConfig` → `default_config`
|
||||
- ✅ `frontend/components/screen/panels/ComponentsPanel.tsx` — hidden 목록 주석 갱신
|
||||
- "→ V2Media" / "→ v2-media (image)" / "통합 미디어" 등을 "→ canonical input (type='file', format='image')" 로 우회
|
||||
- `v2-media` / `v2-file-upload` 두 항목은 hidden 유지 (생성 차단)
|
||||
- ✅ `notes/...` 본 노트 — Phase D.4 기록
|
||||
|
||||
**file / image / img 가 이제 어떤 config 로 input 생성되는지 예시**:
|
||||
|
||||
```jsonc
|
||||
// webType = "file"
|
||||
{
|
||||
"componentType": "input",
|
||||
"config": {
|
||||
"kind": "attach",
|
||||
"type": "file",
|
||||
"format": "file",
|
||||
"accept": "*/*",
|
||||
"multiple": true,
|
||||
"maxFiles": 10
|
||||
}
|
||||
}
|
||||
|
||||
// webType = "image" 또는 "img"
|
||||
{
|
||||
"componentType": "input",
|
||||
"config": {
|
||||
"kind": "attach",
|
||||
"type": "file",
|
||||
"format": "image",
|
||||
"accept": "image/*",
|
||||
"multiple": false,
|
||||
"maxFiles": 1,
|
||||
"showPreview": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**FieldConfig / DataPort 영향**: **0건**
|
||||
- `frontend/types/invyone-component.ts` 의 FieldType / FieldConfig / DataPort / Connection 변경 없음
|
||||
- `frontend/lib/dataPort/runtime.ts` 변경 없음
|
||||
- 추가된 `InputConfig.maxFiles` / `InputConfig.showPreview` 는 input 컴포넌트 내부 옵션 (FieldConfig 와는 별개 — InputComponent 의 InvField triple 흡수 후 props 분리)
|
||||
|
||||
**남은 old file/media 삭제 후보 (다음 phase)**:
|
||||
- `frontend/lib/registry/components/file-upload/FileUploadComponent.tsx` + `index.ts` + `FileUploadConfigPanel.tsx`
|
||||
- `frontend/lib/registry/components/v2-file-upload/` 폴더 통째
|
||||
- `frontend/lib/registry/components/v2-media/` 폴더 통째 (`V2MediaRenderer` + config 패널)
|
||||
- `frontend/components/v2/V2Media.tsx` 본체 + V2Media 관련 타입 / 데모 / 매핑
|
||||
- `frontend/lib/registry/components/image-widget/` + `image-display/`
|
||||
- `frontend/components/screen/widgets/types/ImageWidget.tsx`
|
||||
- **사전 확인 필요**: 위 컴포넌트들이 외부에서 import 되는 경로 grep 후 0건일 때만 삭제
|
||||
|
||||
**검증**:
|
||||
- ✅ `git diff --check` — whitespace 0
|
||||
- ✅ `rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer"` — 0건 유지
|
||||
- ✅ `rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\""` — 새 생성/매핑 경로 **0건**
|
||||
- ✅ `rg "EntityPicker|entity-picker|EntitySearchModal" canonical input 경로` — 0건 유지
|
||||
- ✅ `tsc` 변경 파일 신규 오류 0건 (`DynamicWebTypeRenderer` 의 기존 `webType`/`defaultConfig` mismatch 도 함께 정리)
|
||||
|
||||
### Phase D.5 — canonical file 저장 파이프라인 + old file/media 런타임 차단 (2026-05-12)
|
||||
|
||||
**배경**: Phase D.4 에서 file/image/img 새 생성 경로는 canonical input 으로 통합. 본 phase 는
|
||||
(1) canonical input file 값이 master save 흐름에서 누락되지 않게 보완 + (2) 옛 file-upload /
|
||||
image-widget / image-display / v2-media / v2-file-upload 의 런타임 / registry / ConfigPanel
|
||||
경로 차단. 옛 본체 파일 자체 삭제는 외부 import 정밀 분석 후 별도 phase.
|
||||
|
||||
**canonical file 저장값 변환 정책 (master save)**:
|
||||
- `InteractiveScreenViewerDynamic.handleSaveAction` 의 `masterFormData` 구성 단계 보강
|
||||
- 파일 컬럼 식별 (`isFileColumnComponent`):
|
||||
- 옛: `componentType ∈ {v2-media, file-upload}` 또는 `url.includes(...)` (호환용)
|
||||
- canonical: `componentType === "input"` && (`config.type === "file"` || `config.kind === "attach"` || `config.format ∈ {file, image, doc}`)
|
||||
- 보정: `componentConfig / config / overrides` 세 저장 위치를 모두 흡수. 컬럼명도 `column_name / columnName` 양쪽 키를 같은 우선순위로 확인.
|
||||
- 값 별 처리:
|
||||
- `null / undefined` → 그대로
|
||||
- `string / string[]` → 이미 저장된 path/id 로 보고 유지 (업로드 skip)
|
||||
- `File / File[]` → `uploadFiles` (POST `/files/upload`) 호출 → 응답 `FileInfo[].id ?? server_path ?? server_filename` 로 치환
|
||||
- 혼합 (`(File | string)[]`) → string 유지 + File 만 업로드 후 합쳐서 배열로
|
||||
- 업로드 실패 시 안전하게 string 만 유지 (브라우저 `File` 객체가 saveData 에 들어가지 않도록)
|
||||
- 파일 컬럼이 아닌 배열 값은 종전대로 repeater 로 보고 제외
|
||||
- 파일 컬럼은 더 이상 repeater 오인 제외 대상이 아님
|
||||
|
||||
**제거한 old runtime / register / config 경로**:
|
||||
- `InteractiveScreenViewerDynamic.tsx` — `FileUploadComponent` import 제거, `isFileComponent` import 제거,
|
||||
`if (isFileComponent(comp)) return renderFileComponent(comp)` 분기 제거, `renderFileComponent` 함수 통째 제거,
|
||||
`uploadFilesAndCreateData` 직접 import 제거 (`uploadFiles` 동적 import 가 master save 안에서 대체)
|
||||
- `lib/registry/components/index.ts` — `file-upload/FileUploadRenderer`, `image-widget/ImageWidgetRenderer`,
|
||||
`image-display/ImageDisplayRenderer`, `v2-media/V2MediaRenderer`, `v2-file-upload/V2FileUploadRenderer`
|
||||
auto-register import 5개 모두 제거
|
||||
- `lib/utils/getComponentConfigPanel.tsx` — `CONFIG_PANEL_MAP` 의 `v2-media / file-upload / image-display / image-widget` mapping 4개 제거
|
||||
- `components/screen/panels/V2PropertiesPanel.tsx` — `v2ConfigPanels` 의 `v2-media` 매핑 제거
|
||||
- `lib/schemas/componentConfig.ts` — `v2MediaOverridesSchema` 정의 + `componentOverridesRegistry` 의 `v2-media` 등록 + `componentDefaultsRegistry` 의 `v2-media` 기본값 모두 제거
|
||||
- `components/v2/registerV2Components.ts` — `V2Media` / `V2MediaConfigPanel` import + v2-media `ComponentDefinition` 등록 제거
|
||||
- `components/v2/V2ComponentRenderer.tsx` — `isV2Media` / `V2Media` import + `if (isV2Media(props)) return <V2Media>` 분기 제거
|
||||
- `components/v2/V2ComponentsDemo.tsx` — `V2Media` import + media TabsTrigger + media TabsContent 통째 제거
|
||||
- `components/v2/index.ts` — `V2Media` export + V2Media 타입 re-export (`V2MediaType / V2MediaConfig / V2MediaProps`) 제거
|
||||
- `components/v2/config-panels/index.ts` — `V2MediaConfigPanel` export 제거
|
||||
- `types/v2-components.ts` — `V2MediaType / V2MediaConfig / V2MediaProps` 인터페이스 + `isV2Media` 가드 + `V2ComponentType` / `V2ComponentProps` 유니온의 V2Media 멤버 + `LEGACY_TO_V2_MAP` 의 file-upload/image-widget → V2Media 매핑 제거
|
||||
- `components/v2/V2Media.tsx` — D.6 삭제 전까지 전체 tsc 가 중앙 타입 제거로 바로 깨지지 않도록 로컬 orphan `V2MediaProps` 만 임시 정의. 런타임/register/config 경로는 이미 차단됨.
|
||||
- `app/(main)/screens/[screenId]/page.tsx` — `compType?.includes("v2-media")` / `compType?.includes("file-upload")` 중복 매칭 제거 (이미 `includes("input")` 으로 흡수됨)
|
||||
|
||||
**보존한 shared file viewer 유틸**:
|
||||
|
||||
| 파일 | 보존 이유 |
|
||||
|---|---|
|
||||
| `frontend/lib/registry/components/file-upload/FileViewerModal.tsx` | `GlobalFileViewer.tsx`, `FileAttachmentDetailModal.tsx` 가 import. 단독 파일 뷰어 모달. canonical input 과 무관한 shared util |
|
||||
| `frontend/lib/registry/components/file-upload/FileManagerModal.tsx` | `FileUploadComponent` (옛 본체) 가 사용. FileViewerModal 사용. 본체 삭제 시 함께 검토 |
|
||||
| `frontend/lib/registry/components/file-upload/types.ts` (있다면) | FileViewerModal/FileManagerModal 의 타입 의존성 |
|
||||
|
||||
**검증**:
|
||||
- ✅ `git diff --check` — 0건
|
||||
- ✅ `rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer"` — 0건
|
||||
- ✅ `rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\""` — 0건
|
||||
- ✅ `rg "EntityPicker|entity-picker|EntitySearchModal" canonical input 경로` — 0건
|
||||
- ✅ `rg "FileUploadComponent" frontend/lib frontend/components frontend/app frontend/types`:
|
||||
- 잔존 매치는 모두 (a) 폴더 내부 자기 자신 정의 (`file-upload/`, `v2-file-upload/`) (b) 폴더 내부 V2Media 본체의 import (V2Media 도 폐기 표시됨) (c) Phase D.4/D.5 주석. **외부 runtime 직접 import 0건**
|
||||
- ✅ `rg "V2Media|v2-media|V2FileUpload|v2-file-upload"`:
|
||||
- 잔존은 폐기 폴더 내부 정의 / 옛 본체 (V2Media.tsx / V2FileUploadConfigPanel.tsx) / 폐기 주석. **외부 신규 runtime/config/register 참조 0건**
|
||||
- ✅ `tsc` 변경 파일 신규 오류 0건 (전역 잔존 오류는 모두 기존 camelCase ↔ snake_case 미스매치)
|
||||
|
||||
**다음 phase 에서 실제 삭제 가능한 파일/폴더 (사전 import 0건 재확인 필요)**:
|
||||
|
||||
| 경로 | 사전 확인 명령 | 비고 |
|
||||
|---|---|---|
|
||||
| `frontend/lib/registry/components/v2-file-upload/` (FileViewerModal/FileManagerModal 제외 가능성 검토) | `rg "v2-file-upload\\|V2FileUpload"` | 폴더 자체 정의만 잔존 |
|
||||
| `frontend/lib/registry/components/v2-media/` | `rg "v2-media\\|V2MediaRenderer"` | 폴더 자체 정의만 잔존 |
|
||||
| `frontend/components/v2/V2Media.tsx` | `rg "V2Media\\b"` | 외부 import 0건 확인됨 |
|
||||
| `frontend/components/v2/config-panels/V2MediaConfigPanel.tsx` | `rg "V2MediaConfigPanel"` | 외부 import 0건 확인됨 |
|
||||
| `frontend/components/v2/config-panels/V2FileUploadConfigPanel.tsx` | `rg "V2FileUploadConfigPanel"` | 외부 사용 없음 |
|
||||
| `frontend/lib/registry/components/image-widget/` | `rg "image-widget\\|ImageWidget"` | DynamicWebTypeRenderer 의 옛 ImageWidget import 는 Phase D.4 에서 제거됨 |
|
||||
| `frontend/lib/registry/components/image-display/` | `rg "image-display"` | config panel mapping 제거됨 |
|
||||
| `frontend/lib/registry/components/file-upload/FileUploadComponent.tsx`, `FileUploadRenderer.tsx`, `FileUploadConfigPanel.tsx` | 위 grep | **FileViewerModal / FileManagerModal / types 만 잔존시키고 본체 3 파일만 삭제** |
|
||||
| `frontend/components/screen/widgets/types/ImageWidget.tsx` | `rg "ImageWidget"` | DynamicWebTypeRenderer 분기 제거됨 |
|
||||
|
||||
**Phase D.6 (제안)**: 위 후보를 각각 grep 0건 확인 후 `git rm`. `FileUploadComponent` 본체만 삭제하고 `FileViewerModal / FileManagerModal / types` 는 보존 (GlobalFileViewer / FileAttachmentDetailModal 의존성).
|
||||
|
||||
### Phase D.6 — old file/media 본체 실제 삭제 (2026-05-12)
|
||||
|
||||
**배경**: Phase D.4 / D.5 에서 file/image/img 진입 경로는 canonical input + FilePicker 로 전부 통합되고,
|
||||
옛 file/media 본체의 runtime / register / config 경로도 차단됨. 이 phase 는 사용처 0건이 된 옛 본체를
|
||||
실제 `git rm` 으로 삭제. shared file viewer 유틸은 `GlobalFileViewer` / `FileAttachmentDetailModal` /
|
||||
`FileComponentConfigPanel` 의존성이 있어 보존.
|
||||
|
||||
**삭제 (git rm)**:
|
||||
- 폴더 통째: `lib/registry/components/v2-file-upload/` (8 파일) · `v2-media/` (2 파일) · `image-widget/` (3 파일) · `image-display/` (6 파일)
|
||||
- 본체 파일: `components/v2/V2Media.tsx` · `components/v2/config-panels/V2MediaConfigPanel.tsx` · `components/v2/config-panels/V2FileUploadConfigPanel.tsx` · `components/screen/widgets/types/ImageWidget.tsx`
|
||||
- file-upload 본체 3 파일: `FileUploadComponent.tsx` · `FileUploadRenderer.tsx` · `FileUploadConfigPanel.tsx` + `config.ts` + `README.md`
|
||||
|
||||
**보존 (shared file viewer 유틸)**:
|
||||
- `lib/registry/components/file-upload/FileViewerModal.tsx` — `GlobalFileViewer` / `FileAttachmentDetailModal` 의존
|
||||
- `lib/registry/components/file-upload/FileManagerModal.tsx` — FileViewerModal 사용
|
||||
- `lib/registry/components/file-upload/types.ts` — `FileInfo` / `FileUploadConfig` / `FileUploadResponse` 가 4 곳에서 사용
|
||||
|
||||
**정리 (잔여 참조)**:
|
||||
- `file-upload/index.ts` 재작성 — FileUploadComponent / FileUploadRenderer / FileUploadConfigPanel re-export 제거.
|
||||
`FileViewerModal` / `FileManagerModal` + 타입 3종 (`FileInfo` / `FileUploadConfig` / `FileUploadResponse`) 만 export 하는 shim
|
||||
- `components/screen/widgets/types/index.ts` — `ImageWidget` import / export / `getWidgetComponentByName` 의 `case "ImageWidget"` /
|
||||
`getWidgetComponentByWebType` 의 image/img/picture/photo 분기 / `WebTypeComponents` 의 `image` 매핑 모두 제거
|
||||
|
||||
**잔존 grep 매치 분류 (모두 운영 영향 없음)**:
|
||||
- 폐기 안내 주석 / 작업 노트
|
||||
- `WidgetRenderer.tsx:41` 의 `isImageWidget` 변수 — widgetType 문자열 (`image/img/picture/photo`) 매칭만. ImageWidget 본체 import 없이 wrapper `pointer-events-none` 처리, 실제 렌더는 `DynamicWebTypeRenderer` → canonical input (Phase D.4)
|
||||
- `pop-components/pop-text.tsx` 의 `ImageDisplay` — POP 컴포넌트 영역의 내부 helper 함수. 폐기된 `image-display/` 폴더와 무관
|
||||
|
||||
**검증**:
|
||||
- ✅ `git diff --check` — 0건
|
||||
- ✅ `rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer"` — 0건
|
||||
- ✅ `rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\""` — 0건
|
||||
- ✅ `rg "EntityPicker|entity-picker|EntitySearchModal" canonical input 경로` — 0건
|
||||
- ✅ `rg "FileUploadComponent|FileUploadRenderer|FileUploadConfigPanel|V2Media\b|V2MediaConfigPanel|V2FileUpload|ImageWidget|ImageDisplay"`:
|
||||
- 잔존은 모두 폐기 주석 / `isImageWidget` 변수 / `pop-text` 의 ImageDisplay 내부 helper. **외부 runtime / config / register 직접 import 0건**
|
||||
- ✅ `tsc --noEmit` — 삭제로 인한 `Cannot find module` 오류 0건. 잔존 3건은 모두 D.6 과 무관한 기존 module 오류 (`hierarchyColumn` / `auto-animate` / `lib/types/screen`)
|
||||
|
||||
**파일 통계**:
|
||||
- 삭제: 13 단일 파일 + 4 폴더 (총 ~30 파일)
|
||||
- 수정: 2 파일 (`file-upload/index.ts` shim 재작성, `widgets/types/index.ts` ImageWidget 정리)
|
||||
|
||||
### Phase A.8 — 채번 admin 페이지 + 시퀀스 관리 (★ 별도 트랙)
|
||||
|
||||
**배경**: VEX 는 채번을 캔버스 컴포넌트로 처리 (잘못된 구조). 팀장 요구 — 별도 admin 페이지에서 채번 규칙 + 시퀀스 일원 관리. INVYONE 에는 그 기능 없음 → 신규 작성.
|
||||
@@ -198,7 +547,7 @@
|
||||
- `rulesRefreshKey` state + numberingRules effect dep 추가
|
||||
- 생성 후 새 ruleId 자동 선택 + rules 목록 refresh
|
||||
- **canonical 위치 통일**: `autoGeneration.numberingRuleId` (옵션 밖) → `autoGeneration.options.numberingRuleId` (옵션 안)
|
||||
- V2InputConfigPanel 도 옵션 안에 저장. autoGeneration.ts.generateValue 도 옵션 안 사용.
|
||||
- 옛 입력 설정 패널도 옵션 안에 저장. autoGeneration.ts.generateValue 도 옵션 안 사용.
|
||||
- InputComponent 의 NumberingPicker `numberingRuleId` prop 도 옵션 안에서 읽음 → 일관 ★
|
||||
- 이전 옵션 밖 fallback 제거 (canonical 1안 원칙)
|
||||
- ✅ Codex 검증 — 2 issue fix
|
||||
@@ -210,7 +559,7 @@
|
||||
### Phase A.6 — numbering API hook (완료)
|
||||
|
||||
- ✅ `frontend/lib/registry/components/input/numbering-picker.tsx` 신규
|
||||
- V2Input.tsx:600~949, 1069~1144 의 채번 본체 추출 — useState/useRef + 3 useEffect (main / debounce / beforeFormSave) + 렌더 (readonly text vs prefix-input-suffix)
|
||||
- 옛 입력 컴포넌트의 채번 본체 추출 — useState/useRef + 3 useEffect (main / debounce / beforeFormSave) + 렌더 (readonly text vs prefix-input-suffix)
|
||||
- `previewNumberingCode(ruleId, formData, manualInputValue)` API 사용
|
||||
- ruleId 결정 흐름: `props.numberingRuleId` 우선 → 없으면 `by-column` API → fallback `getTableColumns.detailSettings.numberingRuleId`
|
||||
- `____` 템플릿: 첫 생성 시 templateRef set + 부모 value, 카테고리 변경 시 manualInputValue 유지 + 새 조합값 onChange
|
||||
@@ -243,7 +592,7 @@
|
||||
- ✅ Radio/Checkbox list 의 **외각 box 제거** — `mode=radio||check` 시 container border/bg 없음 (자체 visual element 가 표시)
|
||||
- ✅ **"복수 선택" CPSwitch 제거** (고급 설정) — brumb 의 `단일/다중` 이 진실의 원천. 단일/다중 = 저장 형태 차이 (값 cardinality), UX 토글 아님
|
||||
- ✅ "최대 개수" 노출 조건 — `multi prop` 으로 분기 (config.multiple 의존 X)
|
||||
- ✅ ConfigPanel "선택 방식" 옵션을 multi 따라 분기 — single: dropdown/combobox/radio/toggle, multi: dropdown/combobox/check/tag
|
||||
- ✅ ConfigPanel "선택 방식" 옵션을 multi 따라 분기 — single: dropdown/combobox/radio/toggle, multi: dropdown/combobox/check/swap/tag
|
||||
- ✅ ~~`displayMode` 신규 prop~~ 폐기 — 기존 `config.mode` 와 중복이라 정리. mode 만 사용
|
||||
- ✅ Radio/Checkbox list — flex-col → flex-wrap 으로 변경 (디자인/운영 모드 외형 일관, 박스 사이즈에 맞게 자동 wrap)
|
||||
- ✅ picker 4개 wrapper 의 `opacity-50` 제거 (시각 흐릿 해소)
|
||||
@@ -299,6 +648,115 @@ const runtimeConfig =
|
||||
- `templateAdapter.ts:76` 의 `[saveTemplate] payload` 일반 진단용 로그 — 유지 (low-noise)
|
||||
- 그 외 [Input debug] / [Save layout debug] / [loadTemplate] / [Input render path] 등 모두 제거 완료
|
||||
|
||||
### Phase B.5 — option loader (2026-05-12)
|
||||
|
||||
**배경**: InputComponent 의 select 분기가 `componentConfig.options` 정적 배열만 처리했음.
|
||||
공통코드 (`source=code`) / 사용자 카테고리 (`source=category`) / DB distinct (`source=distinct`)
|
||||
/ 외부 API (`source=api`) 케이스는 옛 선택 컴포넌트의 옵션 로딩 로직에 갇혀 있어서 input
|
||||
canonical 만으로는 옵션이 비어 보였음.
|
||||
|
||||
**변경**:
|
||||
- ✅ `frontend/lib/registry/components/input/use-option-loader.ts` 신규 hook
|
||||
- 입력 : `config / tableName / columnName / formData / isDesignMode`
|
||||
- 처리 source : `static / code / category / distinct (=select) / api / db`
|
||||
- 응답 정규화 : `Array<{value, label}>` — `value/code/id/valueCode` + `label/name/valueLabel`
|
||||
여러 응답 shape 흡수. category 트리는 `flattenCategoryTree` 로 평탄화 (`valueCode` 우선)
|
||||
- 디자인 모드 가드 : `isDesignMode === true` 면 fetch 자체 skip → static 만
|
||||
- 캐시 : module-scoped `Map<url, options>` 로 같은 url 재호출 차단
|
||||
- race 방지 : 요청 id (`reqIdRef`) + `cancelled` flag
|
||||
- 계층 (`hierarchical + parentField`) : `parentValue` 가 `formData[parentField]` 에서
|
||||
오면 `/common-codes/categories/{group}/hierarchy?parentCodeValue=...` 로 자식 코드 조회
|
||||
- entity 는 참조 테이블의 value/label 컬럼을 code-name 옵션으로 로드
|
||||
- 실패 시 `console.warn` + 빈 옵션 (컴포넌트가 죽지 않음)
|
||||
- ✅ `InputComponent.tsx` 본체 — `useOptionLoader` 호출 + select 분기에서 `loadedOptions`
|
||||
를 picker 들 (SingleSelectPicker / MultiSelectPicker / RadioPicker / CheckboxListPicker)
|
||||
에 직접 전달. 정적 정규화 코드 (rawOptions.map) 제거
|
||||
- ✅ FieldOption (string | object) 과 SelectOption (object) 의 union vs concrete 충돌
|
||||
해소를 위해 loader 가 자체 `LoadedOption` 타입 정의해 반환
|
||||
|
||||
**구현한 source**: static / code / category / distinct / select / api / db (V2 legacy)
|
||||
|
||||
**TODO 로 남은 source / 기능**:
|
||||
- 다단 cascade (계층 외에 sourceFiltering 으로 N→1 의존)
|
||||
- 옵션 검색 `filters` (`OptionFilter[]`) — runtime 치환 후 query string 전달.
|
||||
InvFieldConfigPanel 에 filter UI 가 아직 없어서 데이터 자체가 없음. config 가 들어오면
|
||||
쉽게 확장 가능하도록 hook 내부에 자리만 잡아둠 (현재는 미적용)
|
||||
- ✅ ~~swap 모드~~ (B.4.5 — 2026-05-12 완료)
|
||||
|
||||
**검증**:
|
||||
- ✅ `git diff --check` 통과 (whitespace 0)
|
||||
- ✅ `rg V2SelectRenderer | v2-input/V2InputRenderer | id: "v2-input" | id: "v2-select" |
|
||||
componentType: "v2-input/select" | type: "v2-input/select"` — 외부 import 0건
|
||||
(`v2-input` / `v2-select` 렌더러 폴더 자체 정의는 Phase D에서 삭제 완료)
|
||||
- ✅ `npx tsc --noEmit --pretty false` 변경 파일 (InputComponent / use-option-loader)
|
||||
타입 오류 0건. `DateInputComponent.tsx:214` 의 기존 옛 에러는 Phase E 폐기 예정
|
||||
|
||||
### Phase D.1 — v2-input/v2-select 렌더러 파일 삭제 (2026-05-12)
|
||||
|
||||
**배경**: Phase C.2/B.5 이후 `v2-input` / `v2-select` 는 더 이상 registry/import 경로에서 쓰이지 않음. 새 솔루션 개발 기준이므로 기존 저장 화면 호환 / DB layout 마이그레이션은 목표가 아님.
|
||||
|
||||
**변경**:
|
||||
- ✅ `frontend/lib/registry/components/v2-input/V2InputRenderer.tsx` 삭제
|
||||
- ✅ `frontend/lib/registry/components/v2-input/index.ts` 삭제
|
||||
- ✅ `frontend/lib/registry/components/v2-select/V2SelectRenderer.tsx` 삭제
|
||||
- ✅ `frontend/lib/registry/components/v2-select/index.ts` 삭제
|
||||
- ✅ 혼선 방지용 주석 정리 — 새 생성 경로는 `input` canonical 이며, legacy alias/fallback 은 Phase D.2 에서 제거 대상
|
||||
|
||||
**검증**:
|
||||
- ✅ `rg components/v2-input|components/v2-select|V2InputRenderer|V2SelectRenderer` — 실제 참조 0건
|
||||
- ✅ `rg id/componentType/type: "v2-input|v2-select"` — 신규 생성 literal 0건
|
||||
- ✅ `git diff --check` 통과
|
||||
|
||||
### Phase B.4.5 — SwapPicker (2026-05-12)
|
||||
|
||||
**배경**: InputComponent 의 select multi 분기가 `dropdown/multi/radio/check/tag` 까지 처리하지만
|
||||
`mode=swap` 은 미구현. 양쪽 리스트로 항목을 이동하는 UI 가 옛 다중 선택의 표준 패턴 중 하나라
|
||||
canonical input 에 흡수.
|
||||
|
||||
**변경**:
|
||||
- ✅ `frontend/lib/registry/components/input/select-pickers.tsx` — `SwapPicker` 신규 export
|
||||
- props: `value: string[] / onChange / options / maxSelect / disabled / readonly / className / availableLabel / selectedLabel`
|
||||
- UI: 왼쪽 (available, options 순서) ↔ 가운데 (`ChevronRight`/`ChevronLeft` 버튼) ↔ 오른쪽 (selected, value 순서)
|
||||
- 항목 클릭 → 같은 패널 내 highlight 토글 (다중 선택). 이동 후 highlight 자동 해제
|
||||
- 순서 정책: left→right 이동 시 selected 끝에 append, right→left 이동 시 그 항목만 제거
|
||||
- options 에 없는 value 가 들어와도 selected 에 표시 (label = value fallback)
|
||||
- opt.disabled / 패널 lockEdit 항목은 클릭 차단 + opacity 60%
|
||||
- ✅ `frontend/lib/registry/components/input/InputComponent.tsx` — select multi 분기 `mode === "swap"` 추가
|
||||
- 위치: tag → check → **swap** → dropdown/combobox (기본) 순. 기존 분기 보존
|
||||
- `loadedOptions` 그대로 전달, `maxSelect` / disabled / readonly 동일하게 전달
|
||||
- ✅ `frontend/components/v2/config-panels/InvFieldConfigPanel.tsx` — 고급 설정의 `선택 방식` 에
|
||||
`swap` 노출. `multi + list` 는 패널 설명처럼 기본 `mode=check` 로 정렬
|
||||
|
||||
**maxSelect / readonly / disabled 처리**:
|
||||
- `maxSelect`: left→right 이동 시 `selected.length + additions.length > maxSelect` 면 `slice(0, maxSelect)` 로 잘림.
|
||||
selected 가 이미 한도면 right 화살표 버튼 자체 비활성 (`atLimit`).
|
||||
- `readonly` / `disabled`: 단일 `lockEdit` 플래그로 통합. 항목 클릭, 화살표 버튼, 패널 hover 효과 모두 비활성.
|
||||
컨테이너에 `cursor-not-allowed` 부착.
|
||||
|
||||
**검증**:
|
||||
- ✅ `git diff --check` 통과 (whitespace 0)
|
||||
- ✅ `rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer"` — 0건 유지
|
||||
- ✅ `rg "V2Input|V2Select|V2InputConfigPanel|V2SelectConfigPanel"` — `V2SelectedItemsDetailInputConfigPanel`
|
||||
substring 매치만 잔존 (unrelated 컴포넌트)
|
||||
- ✅ `npx tsc --noEmit` — InputComponent / select-pickers / use-option-loader 신규 오류 0건
|
||||
|
||||
### Phase D.2 — v2-input/v2-select alias/fallback/schema 완전 제거 (2026-05-12)
|
||||
|
||||
**배경**: 목표는 InvFieldConfigPanel UI 호환이 아니라 FieldConfig / DataPort 계약 호환. V2 입력/선택 구현체를 runtime alias/fallback/schema 로 살리지 않고, 필요한 기능만 canonical `input` 에 흡수한다.
|
||||
|
||||
**변경**:
|
||||
- ✅ `DynamicComponentRenderer.tsx` — legacy alias / V2SelectRenderer 직접 require / 입력·선택 특수 처리 제거
|
||||
- ✅ `getComponentConfigPanel.tsx`, `V2PropertiesPanel.tsx` — V2 입력/선택 패널 매핑 제거
|
||||
- ✅ `componentConfig.ts` — V2 입력/선택 override schema / default config 제거
|
||||
- ✅ 화면/디자이너/aggregation 패널/CSS/templateMigrate 주석·분기 제거
|
||||
- ✅ `InputComponent.tsx` — 옛 `rawType` fallback 분기 제거
|
||||
|
||||
**검증**:
|
||||
- ✅ `git diff --check` 통과
|
||||
- ✅ `rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles` — 0건
|
||||
- ✅ `rg "components/v2-input|components/v2-select|v2-input/V2InputRenderer|v2-select/V2SelectRenderer" frontend` — 0건
|
||||
- ✅ FieldConfig / DataPort 계약 축소 없음. `types/invyone-component.ts` 변경은 entity FieldRef 확장(autoFill/filter/modalColumns)만.
|
||||
|
||||
---
|
||||
|
||||
## 3. 진행 중 / 남은 작업
|
||||
@@ -312,9 +770,10 @@ const runtimeConfig =
|
||||
- ✅ ~~**B.2** MultiSelectPicker — multi / maxSelect~~ (완료)
|
||||
- ✅ ~~**B.3** TagPicker — tags (tagbox)~~ (완료)
|
||||
- ✅ ~~**B.4** radio / checkbox / toggle~~ (완료)
|
||||
- ⏳ **B.4.5** SwapPicker — multi + mode=swap (양쪽 list 간 이동, 큰 작업)
|
||||
- ⏳ **B.5** option loader — api / code / category / distinct / 계층 (apiClient 의존)
|
||||
- ⏳ webTypeMapping 의 multi / checkbox / radio / boolean / code / category 매핑도 점진 input
|
||||
- ✅ ~~**B.4.5** SwapPicker — multi + mode=swap~~ (2026-05-12 완료 — select-pickers.tsx 에 신규)
|
||||
- ✅ ~~**B.5** option loader — api / code / category / distinct / 계층~~ (2026-05-12 완료 — `use-option-loader.ts` 신규)
|
||||
- ✅ webTypeMapping 의 checkbox / radio / boolean / code / category / entity 매핑 → input
|
||||
- ⏳ 실제 옵션 주입 검증 — 공통코드 / 카테고리 데이터 있는 화면에서 운영 동작 확인 필요
|
||||
|
||||
### 디버그 (해결)
|
||||
|
||||
@@ -322,18 +781,35 @@ const runtimeConfig =
|
||||
|
||||
### Phase C — entity
|
||||
|
||||
- ⏳ entity 검색팝업 + 다른 컬럼 auto-fill (V2Select.tsx:1007~)
|
||||
- ⏳ 현재 InputComponent entity 분기는 placeholder 버튼만
|
||||
- ✅ entity code-name 옵션 로딩 (`/entity/{table}/options?value=...&label=...`)
|
||||
- ✅ InputComponent entity 분기 → Single/Multi select picker
|
||||
- ✅ multi entity (`type="multi" + format="entity"`) 는 JSON 배열 저장 형태로 select 계열 picker 재사용
|
||||
|
||||
### Phase D — V2 폐기
|
||||
|
||||
- ⏳ webTypeMapping 의 select 계열 (multi/category/entity/code/checkbox/radio/boolean) → input (B 단계 후)
|
||||
- ✅ webTypeMapping 의 select 계열 (category/entity/code/checkbox/radio/boolean) → input
|
||||
- ⏳ webTypeMapping 의 file/image/img → input (file 통합 후)
|
||||
- ⏳ `ScreenSettingModal.tsx:2052-2066` 의 옛 컴포넌트 생성 경로 → input
|
||||
- ⏳ DB 마이그 — `screens` 테이블의 `layout` JSON 안 componentType 변경 (사용자 승인 필요)
|
||||
- ⏳ `V2Input.tsx` / `V2Select.tsx` 파일 삭제
|
||||
- ⏳ `registerV2Components.ts` 의 v2-input / v2-select 등록 제거
|
||||
- ⏳ `V2InputConfigPanel.tsx` (832줄) 삭제 — 이전 세션의 폐기 보류
|
||||
- ✅ `ScreenSettingModal.tsx:2052-2066` 의 옛 컴포넌트 생성 경로 → input
|
||||
- ✅ DB layout JSON 마이그레이션 안 함 — 새 솔루션 개발 기준, 기존 V2 저장 데이터 보존은 목표 아님
|
||||
- ✅ `frontend/lib/registry/components/v2-input/` 및 `v2-select/` 렌더러 파일 삭제
|
||||
- ✅ `registerV2Components.ts` 의 v2-input / v2-select 등록 제거
|
||||
- ✅ `components/index.ts` 의 v2-input / v2-select renderer auto-register 제거
|
||||
- ✅ v2-input / v2-select alias / fallback / schema 제거
|
||||
- ✅ `V2Input.tsx` / `V2Select.tsx` 본체 및 `V2InputConfigPanel.tsx` / `V2SelectConfigPanel.tsx` 삭제
|
||||
|
||||
### Phase D.3 — V2Input / V2Select 본체 및 직접 참조 삭제
|
||||
|
||||
- ✅ `frontend/components/v2/V2Input.tsx` 삭제
|
||||
- ✅ `frontend/components/v2/V2Select.tsx` 삭제
|
||||
- ✅ `frontend/components/v2/config-panels/V2InputConfigPanel.tsx` 삭제
|
||||
- ✅ `frontend/components/v2/config-panels/V2SelectConfigPanel.tsx` 삭제
|
||||
- ✅ `components/v2/index.ts`, `config-panels/index.ts`, `V2ComponentRenderer.tsx`, `V2ComponentsDemo.tsx`, `DynamicConfigPanel.tsx` 직접 참조 제거
|
||||
- ✅ `types/v2-components.ts` 의 옛 입력/선택 타입·type guard·legacy map 제거
|
||||
- ✅ `V2SelectFilter` 의존을 canonical `OptionFilter` 로 이전
|
||||
- ✅ `rg "V2Input|V2Select|V2InputConfigPanel|V2SelectConfigPanel|components/v2/V2Input|components/v2/V2Select" frontend/lib frontend/components frontend/app frontend/types`
|
||||
결과는 `V2SelectedItemsDetailInputConfigPanel` substring 매치만 잔존 (별개 컴포넌트)
|
||||
- ✅ `rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles` — 0건
|
||||
- ✅ FieldConfig / DataPort 계약 축소 없음. 이번 변경으로 `invyone-component.ts` / `dataPort/runtime.ts` 추가 변경 없음.
|
||||
|
||||
### Phase E — 옛 6개 폐기
|
||||
|
||||
@@ -345,14 +821,14 @@ const runtimeConfig =
|
||||
|
||||
## 4. 위험 영역 / 주의사항
|
||||
|
||||
1. **V2Input / V2Select 폐기 전 고유 기능 이식 검증 필수**
|
||||
- V2Input: numbering API · mask · password · slider · color picker
|
||||
- V2Select: radio/check/toggle/swap mode · entity FK 검색·auto-fill · option loader (api/code/category/distinct/계층)
|
||||
1. **옛 입력/선택 고유 기능 이식 검증**
|
||||
- 이식 완료: numbering API, password/email/tel/url, money/number, radio/check/toggle/swap, entity code-name option, option loader(api/code/category/distinct/계층)
|
||||
- 남은 항목: mask, slider, color picker, file/image/img 통합
|
||||
|
||||
2. **DB 마이그 (Phase D 4단계)**
|
||||
- 화면 데이터는 `screens` 테이블의 `layout` JSON 안에 통째 저장 (별도 component 테이블 없음 — `screen_components` 같은 이름 X)
|
||||
- JSON 안 `componentType` / `componentConfig` 변경 SQL 필요 (jsonb_set 또는 string replace)
|
||||
- 운영 단계 아니라 데이터 마이그 부담 작음 — 단 UPDATE 사용자 승인 필요 (메모리)
|
||||
2. **DB layout 마이그 금지**
|
||||
- 새 솔루션 개발 기준이므로 기존 저장 화면 보존은 목표가 아님.
|
||||
- `screens` / `templates` JSON 안 옛 componentType 을 변환하는 SQL 작성 금지.
|
||||
- 정리 대상은 코드의 생성/렌더/설정/schema 경로이며, FieldConfig / DataPort 계약 호환을 우선한다.
|
||||
|
||||
3. **dev reload 캐시**
|
||||
- webTypeMapping.ts 변경은 새로 끌어 놓는 컴포넌트만 반영
|
||||
@@ -379,12 +855,15 @@ frontend/lib/utils/getComponentConfigPanel.tsx ← componentId
|
||||
frontend/lib/registry/DynamicComponentRenderer.tsx ← 캔버스 렌더 dispatch (fieldType swap 제거됨)
|
||||
frontend/components/screen/panels/V2PropertiesPanel.tsx ← properties 패널 라우팅
|
||||
|
||||
[폐기 완료]
|
||||
frontend/components/v2/V2Input.tsx ← 삭제 완료
|
||||
frontend/components/v2/V2Select.tsx ← 삭제 완료
|
||||
frontend/components/v2/config-panels/V2InputConfigPanel.tsx ← 삭제 완료
|
||||
frontend/components/v2/config-panels/V2SelectConfigPanel.tsx ← 삭제 완료
|
||||
|
||||
[폐기 예정]
|
||||
frontend/components/v2/V2Input.tsx ← 1286줄
|
||||
frontend/components/v2/V2Select.tsx ← 1350줄
|
||||
frontend/lib/registry/components/{date,text,number}-input/ ← 자체 캔버스 컴포넌트 폐기
|
||||
frontend/lib/registry/components/{select,checkbox,textarea}-basic/
|
||||
frontend/components/v2/config-panels/V2InputConfigPanel.tsx ← 832줄 (이전 세션 폐기 보류)
|
||||
|
||||
[유틸 / API]
|
||||
frontend/lib/utils/autoGeneration.ts ← AutoGenerationUtils.generateValue (A.5 hook 연결됨)
|
||||
@@ -397,7 +876,7 @@ frontend/lib/api/numberingRule.ts ← previewNumberi
|
||||
|
||||
| 결정 | 이유 |
|
||||
|---|---|
|
||||
| Canonical = InvFieldConfigPanel + InputComponent | brumb (kind/type/format) 풍부, FieldConfig spec 정합 |
|
||||
| Canonical = FieldConfig/DataPort + InputComponent | FieldConfig 가 유일한 필드 규격, DataPort 가 컴포넌트 통신 계약 |
|
||||
| (가)/(다) 하이브리드 거부 → (나) 통합 추진 | canonical 1안 원칙 / 운영 단계 아님 |
|
||||
| webTypeMapping → input 점진 변경 | V2Select 고유 기능 이식 후 매핑 변경 (안전) |
|
||||
| native `<select>` → SingleSelectPicker | OS 기본 dropdown 통일 어려움 + V2Select 풍부 기능 흡수 |
|
||||
@@ -411,31 +890,18 @@ frontend/lib/api/numberingRule.ts ← previewNumberi
|
||||
|
||||
### 우선순위
|
||||
|
||||
1. **B.4.5 — SwapPicker** (큰)
|
||||
- multi + mode=swap
|
||||
- 양쪽 list (선택 가능 / 선택됨) + 이동 버튼
|
||||
- V2Select.tsx:530~ 참고
|
||||
1. **D 후속 — file/image/img → input 통합**
|
||||
- webTypeMapping 의 file/image/img 경로
|
||||
- 기존 file-upload / image-widget / v2-media 기능 중 필요한 것만 canonical input 으로 흡수
|
||||
|
||||
2. **B.5 — option loader** (중)
|
||||
- api / code / category / distinct / 계층
|
||||
- V2Select 의 option 로딩 로직 이식
|
||||
- apiClient 의존
|
||||
2. **C 후속 — entity filter runtime** (중)
|
||||
- `filters` 를 entity/category/code option query 에 runtime 적용
|
||||
- field/user/static 값 치환 후 API query 전달
|
||||
|
||||
3. **C — entity 검색팝업 + auto-fill** (큰)
|
||||
- V2Select.tsx:1007~ 의 entity FK 검색
|
||||
- 다른 컬럼 auto-fill (조인)
|
||||
- 현재 InputComponent entity 분기 = placeholder 버튼만
|
||||
3. **D — 남은 입력계 폐기**
|
||||
- mask / slider / color picker 흡수 여부 결정
|
||||
|
||||
4. **D — V2 폐기** (위 1~3 완료 후)
|
||||
- webTypeMapping 의 select 계열 (multi/category/entity/code/checkbox/radio/boolean) → input
|
||||
- webTypeMapping 의 file/image/img → input (file 통합 후)
|
||||
- `ScreenSettingModal.tsx:2052-2066` 의 옛 컴포넌트 생성 경로 → input
|
||||
- DB 마이그 — `templates.views` JSON 안 componentType / url 변경 (사용자 승인 필요)
|
||||
- `V2Input.tsx` / `V2Select.tsx` 파일 삭제
|
||||
- `registerV2Components.ts` 의 v2-input / v2-select 등록 제거
|
||||
- `V2InputConfigPanel.tsx` (832줄) 삭제
|
||||
|
||||
5. **E — 옛 6개 폐기**
|
||||
4. **E — 옛 6개 폐기**
|
||||
- date-input / text-input / number-input / select-basic / checkbox-basic / textarea-basic 의 캔버스 컴포넌트 (`DateInputComponent.tsx` 등) 폐기
|
||||
- 6 폴더 자체 삭제 (ScreenSettingModal 의 생성 경로 검증 후)
|
||||
|
||||
@@ -443,7 +909,7 @@ frontend/lib/api/numberingRule.ts ← previewNumberi
|
||||
|
||||
- ✅ defaultValue 동작 검증 완료 — form-popup 수정 모달에서 default 적용 됨
|
||||
- 이전에 한 변경들은 form-popup 의 BlockRenderer hijack 으로 동작 검증이 어려웠음. 이제 가능
|
||||
- ⏳ Phase B.4.5 / B.5 / C 중 어디부터 진행할지 결정 — 사용자 의도 (사진 확인 가능한 것 우선) 따라
|
||||
- ⏳ D 후속 / C 후속 / E 중 어디부터 진행할지 결정 — 사용자 의도 (사진 확인 가능한 것 우선) 따라
|
||||
|
||||
### 핵심 사실 (새 세션이 알아야 할 것)
|
||||
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
# Codex Handoff — Input Canonical Migration
|
||||
|
||||
날짜: 2026-05-12
|
||||
브랜치: `gbpark-node`
|
||||
주 작업 문서: `notes/gbpark/2026-05-08-input-canonical-migration.md`
|
||||
|
||||
이 문서는 다른 컴퓨터에서 Codex가 바로 이어받기 위한 요약이다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 목표
|
||||
|
||||
INVYONE Studio 입력 계열을 `FieldConfig / DataPort` 계약을 유지한 채 canonical `input`으로 통합한다.
|
||||
|
||||
핵심 원칙:
|
||||
- `FieldConfig`의 원천은 `frontend/types/invyone-component.ts`다. 설정 패널 UI가 원천이 아니다.
|
||||
- `DataPort / Connection` 계약은 축소하지 않는다.
|
||||
- `v2-input`, `v2-select`는 구현체, alias, fallback, schema, DB layout 마이그 대상이 아니다. 제거 대상이다.
|
||||
- 기존 DB layout JSON 마이그레이션은 하지 않는다. 새 솔루션 개발 기준이다.
|
||||
- `entity`는 검색 모달이 아니라 참조 테이블의 code-name 옵션 source다.
|
||||
- 검색 모달이 필요하면 별도 `entity-search-input` 계열에서 처리한다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 완료된 범위
|
||||
|
||||
### V2 input/select 제거
|
||||
|
||||
삭제 완료:
|
||||
- `frontend/lib/registry/components/v2-input/`
|
||||
- `frontend/lib/registry/components/v2-select/`
|
||||
- `frontend/components/v2/V2Input.tsx`
|
||||
- `frontend/components/v2/V2Select.tsx`
|
||||
- `frontend/components/v2/config-panels/V2InputConfigPanel.tsx`
|
||||
- `frontend/components/v2/config-panels/V2SelectConfigPanel.tsx`
|
||||
|
||||
정리 완료:
|
||||
- renderer alias / fallback 제거
|
||||
- config panel alias 제거
|
||||
- schema/default 제거
|
||||
- registerV2Components 등록 제거
|
||||
- V2 demo / V2 renderer 직접 참조 제거
|
||||
- `types/v2-components.ts`에서 V2Input/V2Select 타입 제거
|
||||
|
||||
검증 기준:
|
||||
```bash
|
||||
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles
|
||||
```
|
||||
결과는 0건이어야 한다.
|
||||
|
||||
### canonical select/entity
|
||||
|
||||
추가:
|
||||
- `frontend/lib/registry/components/input/use-option-loader.ts`
|
||||
- `frontend/lib/registry/components/input/select-pickers.tsx`의 `SwapPicker`
|
||||
|
||||
`useOptionLoader` source:
|
||||
- `static`
|
||||
- `code`
|
||||
- `category`
|
||||
- `entity`
|
||||
- `distinct` / `select`
|
||||
- `api`
|
||||
- `db`
|
||||
|
||||
entity 정책:
|
||||
- `/entity/{table}/options?value={valueColumn}&label={labelColumn}`
|
||||
- `config.entityTable/entityValueColumn/entityLabelColumn`
|
||||
- 또는 `config.ref.table/valueColumn/displayColumn`
|
||||
- entity modal 재유입 금지
|
||||
|
||||
filter runtime:
|
||||
- `OptionFilter[]`를 runtime에서 `formData` / `userContext`로 치환
|
||||
- `entity`, `distinct/select`, `db` URL에 `filters=` query append
|
||||
- `code`, `category`, `api`는 backend/external spec 미정으로 미적용
|
||||
|
||||
### canonical file/image/img
|
||||
|
||||
추가:
|
||||
- `frontend/lib/registry/components/input/file-picker.tsx`
|
||||
|
||||
변경:
|
||||
- `InputComponent`의 `case "file"`이 `FilePicker` 사용
|
||||
- `file/image/img/picture/photo`는 canonical input file로 라우팅
|
||||
- `webTypeMapping.ts`에서 `file/image/img` 모두 `componentType: "input"`
|
||||
- `DynamicWebTypeRenderer`의 old FileUpload/ImageWidget 직접 import 제거
|
||||
- `InteractiveScreenViewerDynamic` master save에서 canonical file 값 업로드 후 id/path로 치환
|
||||
|
||||
file 저장 정책:
|
||||
- `string/string[]`: 이미 저장된 값으로 보고 유지
|
||||
- `File/File[]`: `uploadFiles` 호출 후 `id ?? server_path ?? server_filename`로 치환
|
||||
- mixed `(File | string)[]`: string 유지 + File 업로드 결과 합침
|
||||
- 업로드 실패 시 `File` 객체가 `saveData`에 들어가지 않도록 string만 유지
|
||||
|
||||
old file/media 삭제 완료:
|
||||
- `frontend/lib/registry/components/v2-file-upload/`
|
||||
- `frontend/lib/registry/components/v2-media/`
|
||||
- `frontend/lib/registry/components/image-widget/`
|
||||
- `frontend/lib/registry/components/image-display/`
|
||||
- `frontend/components/v2/V2Media.tsx`
|
||||
- `frontend/components/v2/config-panels/V2MediaConfigPanel.tsx`
|
||||
- `frontend/components/v2/config-panels/V2FileUploadConfigPanel.tsx`
|
||||
- `frontend/components/screen/widgets/types/ImageWidget.tsx`
|
||||
- `frontend/lib/registry/components/file-upload/FileUploadComponent.tsx`
|
||||
- `frontend/lib/registry/components/file-upload/FileUploadRenderer.tsx`
|
||||
- `frontend/lib/registry/components/file-upload/FileUploadConfigPanel.tsx`
|
||||
- `frontend/lib/registry/components/file-upload/config.ts`
|
||||
- `frontend/lib/registry/components/file-upload/README.md`
|
||||
|
||||
보존:
|
||||
- `frontend/lib/registry/components/file-upload/FileViewerModal.tsx`
|
||||
- `frontend/lib/registry/components/file-upload/FileManagerModal.tsx`
|
||||
- `frontend/lib/registry/components/file-upload/types.ts`
|
||||
- `frontend/lib/registry/components/file-upload/index.ts`는 shared viewer/type export shim
|
||||
|
||||
검증 기준:
|
||||
```bash
|
||||
rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\"" frontend/lib frontend/components frontend/app frontend/types
|
||||
rg "FileUploadComponent|FileUploadRenderer|FileUploadConfigPanel|V2Media\\b|V2MediaConfigPanel|V2FileUpload|ImageWidget|ImageDisplay" frontend/lib frontend/components frontend/app frontend/types
|
||||
```
|
||||
첫 번째는 0건이어야 한다. 두 번째는 폐기 주석, `WidgetRenderer`의 `isImageWidget` 문자열, `pop-text` 내부 helper 정도만 남아야 한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 현재 known verification
|
||||
|
||||
통과:
|
||||
```bash
|
||||
git diff --check
|
||||
git diff --cached --check
|
||||
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles
|
||||
rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\"" frontend/lib frontend/components frontend/app frontend/types
|
||||
rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx
|
||||
```
|
||||
|
||||
전체 `tsc`는 아직 전역 기존 오류로 실패한다. D.6 삭제로 인한 old file/media `Cannot find module`은 0건이었다.
|
||||
|
||||
현재 확인된 기존 module 오류:
|
||||
```text
|
||||
@/lib/api/hierarchyColumn
|
||||
@formkit/auto-animate/react
|
||||
@/lib/types/screen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 다음 작업
|
||||
|
||||
### Phase D.7 — canonical input mask / slider / color 흡수
|
||||
|
||||
목표:
|
||||
- 남은 옛 입력 고유 기능 `mask`, `slider`, `color`를 canonical `input`에 흡수한다.
|
||||
- `v2-input/v2-select` 복구 금지.
|
||||
- old file/media 복구 금지.
|
||||
- FieldConfig / DataPort 변경 금지.
|
||||
|
||||
구현 방향:
|
||||
- `slider`
|
||||
- `type="number" + format="slider"` 또는 `inputType/webType === "slider"`
|
||||
- `min/max/step` 지원
|
||||
- `propagate` 흐름 유지
|
||||
- readonly/disabled 처리
|
||||
- `color`
|
||||
- `type="text" + format="color"` 또는 `inputType/webType === "color"`
|
||||
- native color input + hex text input
|
||||
- 값은 `#rrggbb` 문자열
|
||||
- `mask`
|
||||
- `InputConfig.mask?: string`
|
||||
- text onChange에서 간단 mask 적용
|
||||
- `#` 또는 `0` = digit, `A` = alphabet, `*` = any char, 나머지는 literal
|
||||
|
||||
수정 후보:
|
||||
- `frontend/lib/registry/components/input/InputComponent.tsx`
|
||||
- `frontend/lib/registry/components/input/types.ts`
|
||||
- `frontend/components/v2/config-panels/InvFieldConfigPanel.tsx`
|
||||
- `frontend/lib/utils/webTypeMapping.ts`
|
||||
- `frontend/components/screen/panels/ComponentsPanel.tsx`
|
||||
- `frontend/lib/registry/components/index.ts`
|
||||
|
||||
검증:
|
||||
```bash
|
||||
git diff --check
|
||||
git diff --cached --check
|
||||
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles
|
||||
rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\"" frontend/lib frontend/components frontend/app frontend/types
|
||||
rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx
|
||||
```
|
||||
|
||||
### Phase E — old 6 input components 삭제
|
||||
|
||||
D.7 이후 진행.
|
||||
|
||||
대상:
|
||||
- `frontend/lib/registry/components/date-input/`
|
||||
- `frontend/lib/registry/components/text-input/`
|
||||
- `frontend/lib/registry/components/number-input/`
|
||||
- `frontend/lib/registry/components/select-basic/`
|
||||
- `frontend/lib/registry/components/checkbox-basic/`
|
||||
- `frontend/lib/registry/components/textarea-basic/`
|
||||
|
||||
전제:
|
||||
- `webTypeMapping`, `ScreenSettingModal`, `ComponentsPanel`, `components/index.ts`, config panel alias가 모두 canonical `input`으로 정리되어야 한다.
|
||||
- `DateInputComponent.tsx` 기존 타입 오류는 삭제 시 자연 해소될 가능성이 높다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 금지 사항
|
||||
|
||||
- `v2-input`, `v2-select` 문자열 재생성 금지
|
||||
- `V2InputRenderer`, `V2SelectRenderer` 복구 금지
|
||||
- `V2Input.tsx`, `V2Select.tsx` 복구 금지
|
||||
- `EntityPicker` / `EntitySearchModal`을 canonical input에 넣지 말 것
|
||||
- old file/media 본체 복구 금지
|
||||
- DB layout JSON 변환 SQL 작성 금지
|
||||
- FieldConfig / DataPort 계약 축소 금지
|
||||
Reference in New Issue
Block a user