fix: field_key 저장 및 표시 기능 완전 수정

- field_key 저장 시 백엔드 형식({ID}_{사용자입력})으로 전송
- API 요청 전 field_key 유효성 검증 추가
- 계층구조 탭 필드 추가/수정 시 field_key 반영
- 섹션 탭에서 field_key 표시 시 사용자입력 부분만 추출
- sectionsAsTemplates useMemo에서 linkedSections/unlinkedSections 모두 수정
- 마스터 필드, 템플릿 필드 다이얼로그에서 field_key 입력 지원
- ItemMasterContext에 field_key 상태 업데이트 로직 추가
- transformers에서 field_key 변환 처리

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2025-11-28 19:57:52 +09:00
parent 9d0cb073ba
commit 8fd9cf2d40
9 changed files with 133 additions and 34 deletions

View File

@@ -127,6 +127,9 @@ export function FieldDialog({
// 유효성 검사
const isNameEmpty = !newFieldName.trim();
const isKeyEmpty = !newFieldKey.trim();
// 2025-11-28: field_key validation - 영문 시작, 영문+숫자+언더스코어만 허용
const fieldKeyPattern = /^[a-zA-Z][a-zA-Z0-9_]*$/;
const isKeyInvalid = newFieldKey.trim() !== '' && !fieldKeyPattern.test(newFieldKey);
const handleClose = () => {
setIsSubmitted(false);
@@ -288,11 +291,14 @@ export function FieldDialog({
value={newFieldKey}
onChange={(e) => setNewFieldKey(e.target.value)}
placeholder="예: itemName"
className={isSubmitted && isKeyEmpty ? 'border-red-500 focus-visible:ring-red-500' : ''}
className={(isSubmitted && isKeyEmpty) || isKeyInvalid ? 'border-red-500 focus-visible:ring-red-500' : ''}
/>
{isSubmitted && isKeyEmpty && (
<p className="text-xs text-red-500 mt-1"> </p>
)}
{isKeyInvalid && (
<p className="text-xs text-red-500 mt-1"> , //(_) </p>
)}
</div>
</div>
@@ -420,7 +426,8 @@ export function FieldDialog({
<Button variant="outline" onClick={handleClose}></Button>
<Button onClick={async () => {
setIsSubmitted(true);
if ((fieldInputMode === 'custom' || editingFieldId) && (isNameEmpty || isKeyEmpty)) return;
// 2025-11-28: field_key validation 추가
if ((fieldInputMode === 'custom' || editingFieldId) && (isNameEmpty || isKeyEmpty || isKeyInvalid)) return;
await handleAddField();
setIsSubmitted(false);
}}></Button>

View File

@@ -85,6 +85,9 @@ export function MasterFieldDialog({
// 유효성 검사
const isNameEmpty = !newMasterFieldName.trim();
const isKeyEmpty = !newMasterFieldKey.trim();
// 2025-11-28: field_key validation - 영문 시작, 영문+숫자+언더스코어만 허용
const fieldKeyPattern = /^[a-zA-Z][a-zA-Z0-9_]*$/;
const isKeyInvalid = newMasterFieldKey.trim() !== '' && !fieldKeyPattern.test(newMasterFieldKey);
const handleClose = () => {
setIsMasterFieldDialogOpen(false);
@@ -105,7 +108,8 @@ export function MasterFieldDialog({
const handleSubmit = () => {
setIsSubmitted(true);
if (!isNameEmpty && !isKeyEmpty) {
// 2025-11-28: field_key validation 추가
if (!isNameEmpty && !isKeyEmpty && !isKeyInvalid) {
if (editingMasterFieldId) {
handleUpdateMasterField();
} else {
@@ -147,11 +151,14 @@ export function MasterFieldDialog({
value={newMasterFieldKey}
onChange={(e) => setNewMasterFieldKey(e.target.value)}
placeholder="예: itemName"
className={isSubmitted && isKeyEmpty ? 'border-red-500 focus-visible:ring-red-500' : ''}
className={(isSubmitted && isKeyEmpty) || isKeyInvalid ? 'border-red-500 focus-visible:ring-red-500' : ''}
/>
{isSubmitted && isKeyEmpty && (
<p className="text-xs text-red-500 mt-1"> </p>
)}
{isKeyInvalid && (
<p className="text-xs text-red-500 mt-1"> , //(_) </p>
)}
</div>
</div>