배치 편집 conditional 매핑 평가 필드 UX 개선

- 평가 필드 미선택 시 select 에 빨간 테두리 + ring 강조 (한눈에 누락 식별)
- 라벨에 * 필수 마크 + placeholder 를 '조건을 평가할 API 필드 선택 (필수)' 로 변경
- 안내 텍스트 추가: 'status 컬럼에 enrlFg 의 J01→active 변환 시 평가 필드=enrlFg' 예시
- 저장된 apiField 가 fromApiFields 옵션에 없을 때 동적으로 (저장값) 라벨로 추가
  → 응답 미리보기 안 한 편집 모드에서도 기존 값 보존되어 그대로 저장 가능
- cn 유틸 import 추가 (조건부 클래스 적용 시 ReferenceError 방지)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chpark
2026-05-08 18:24:12 +09:00
parent 4007042311
commit 575098698c
@@ -13,6 +13,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
import { Trash2, Plus, ArrowLeft, Save, RefreshCw, Globe, Database, Eye, Link as LinkIcon } from "lucide-react";
import { toast } from "sonner";
import { showErrorToast } from "@/lib/utils/toastUtils";
import { cn } from "@/lib/utils";
import { BatchManagementAPI } from "@/lib/api/batchManagement";
import {
ExternalRestApiConnectionAPI,
@@ -2291,6 +2292,7 @@ function ConditionalEditor({
onConfigChange: (cfg: ConditionalConfig) => void;
}) {
const cfg = mapping.conditionalConfig || { rules: [{ when: "", then: "" }], default: "" };
const isApiFieldMissing = !mapping.apiField;
const updateRule = (idx: number, patch: Partial<ConditionalRule>) => {
const rules = cfg.rules.map((r, i) => (i === idx ? { ...r, ...patch } : r));
onConfigChange({ ...cfg, rules });
@@ -2300,19 +2302,31 @@ function ConditionalEditor({
onConfigChange({ ...cfg, rules: cfg.rules.filter((_, i) => i !== idx) });
return (
<div className="space-y-1.5 rounded border bg-muted/30 p-2">
<div className="flex items-center gap-1.5">
<span className="shrink-0 text-[10px] font-medium text-muted-foreground"> </span>
<Select value={mapping.apiField || "none"} onValueChange={(v) => onApiFieldChange(v === "none" ? "" : v)}>
<SelectTrigger className="h-7 text-xs">
<SelectValue placeholder="API 필드 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="none"> </SelectItem>
{fromApiFields.map((f) => (
<SelectItem key={f} value={f}>{f}</SelectItem>
))}
</SelectContent>
</Select>
<div className="space-y-0.5">
<div className="flex items-center gap-1.5">
<span className="shrink-0 text-[10px] font-medium text-muted-foreground"> <span className="text-destructive">*</span></span>
<Select value={mapping.apiField || "none"} onValueChange={(v) => onApiFieldChange(v === "none" ? "" : v)}>
<SelectTrigger className={cn(
"h-7 text-xs",
isApiFieldMissing && "border-destructive ring-1 ring-destructive/40",
)}>
<SelectValue placeholder="조건을 평가할 API 필드 선택 (필수)" />
</SelectTrigger>
<SelectContent>
<SelectItem value="none"> </SelectItem>
{/* 저장된 apiField 가 fromApiFields 옵션에 없을 때 동적 추가 (응답 미리보기 안 한 편집 모드 대응) */}
{mapping.apiField && !fromApiFields.includes(mapping.apiField) && (
<SelectItem value={mapping.apiField}>{mapping.apiField} ()</SelectItem>
)}
{fromApiFields.map((f) => (
<SelectItem key={f} value={f}>{f}</SelectItem>
))}
</SelectContent>
</Select>
</div>
<p className="pl-[60px] text-[10px] text-muted-foreground">
(: status <span className="font-mono">enrlFg</span> J01active = <span className="font-mono">enrlFg</span>)
</p>
</div>
<div className="space-y-1">
{cfg.rules.map((rule, idx) => (