snp-batch-validation/frontend/src/components/bypass/BypassStepBasic.tsx
HYOJIN e6e58bfc25 feat: Bypass API 화면 개선 및 SPA 새로고침 오류 수정 (#63)
- WebClient Bean 드롭다운 표시 텍스트를 description만 표시
- bypass_api_param에 example 컬럼 추가 (Swagger placeholder 사용자 설정)
- 목록 기본 뷰를 리스트뷰(테이블)로 변경
- 도메인명 드롭다운 필터 추가
- WebViewController에 /bypass-config 경로 추가 (SPA 새로고침 404 해결)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:20:37 +09:00

143 lines
6.5 KiB
TypeScript

import type { WebClientBeanInfo } from '../../api/bypassApi';
interface BypassStepBasicProps {
domainName: string;
displayName: string;
webclientBean: string;
externalPath: string;
httpMethod: string;
description: string;
webclientBeans: WebClientBeanInfo[];
isEdit: boolean;
onChange: (field: string, value: string) => void;
}
export default function BypassStepBasic({
domainName,
displayName,
webclientBean,
externalPath,
httpMethod,
description,
webclientBeans,
isEdit,
onChange,
}: BypassStepBasicProps) {
return (
<div className="space-y-5">
<p className="text-sm text-wing-muted">
BYPASS API의 . .
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* 도메인명 */}
<div>
<label className="block text-sm font-medium text-wing-text mb-1">
<span className="text-red-500">*</span>
</label>
<input
type="text"
value={domainName}
onChange={(e) => onChange('domainName', e.target.value)}
disabled={isEdit}
placeholder="예: riskByImo"
pattern="[a-zA-Z][a-zA-Z0-9]*"
className={[
'w-full px-3 py-2 text-sm rounded-lg border',
'border-wing-border bg-wing-card text-wing-text',
'placeholder:text-wing-muted focus:outline-none focus:ring-2 focus:ring-wing-accent/50',
isEdit ? 'opacity-50 cursor-not-allowed' : '',
].join(' ')}
/>
<p className="mt-1 text-xs text-wing-muted"> / ( )</p>
</div>
{/* 표시명 */}
<div>
<label className="block text-sm font-medium text-wing-text mb-1">
<span className="text-red-500">*</span>
</label>
<input
type="text"
value={displayName}
onChange={(e) => onChange('displayName', e.target.value)}
placeholder="예: IMO 기반 리스크 조회"
className="w-full px-3 py-2 text-sm rounded-lg border border-wing-border bg-wing-card text-wing-text placeholder:text-wing-muted focus:outline-none focus:ring-2 focus:ring-wing-accent/50"
/>
</div>
{/* WebClient */}
<div>
<label className="block text-sm font-medium text-wing-text mb-1">
WebClient Bean <span className="text-red-500">*</span>
</label>
<select
value={webclientBean}
onChange={(e) => onChange('webclientBean', e.target.value)}
className="w-full px-3 py-2 text-sm rounded-lg border border-wing-border bg-wing-card text-wing-text focus:outline-none focus:ring-2 focus:ring-wing-accent/50"
>
<option value=""></option>
{webclientBeans.map((bean) => (
<option key={bean.name} value={bean.name}>
{bean.description || bean.name}
</option>
))}
</select>
</div>
{/* 외부 API 경로 */}
<div>
<label className="block text-sm font-medium text-wing-text mb-1">
API <span className="text-red-500">*</span>
</label>
<input
type="text"
value={externalPath}
onChange={(e) => onChange('externalPath', e.target.value)}
placeholder="/RiskAndCompliance/RisksByImos"
className="w-full px-3 py-2 text-sm rounded-lg border border-wing-border bg-wing-card text-wing-text placeholder:text-wing-muted focus:outline-none focus:ring-2 focus:ring-wing-accent/50"
/>
</div>
{/* HTTP 메서드 */}
<div>
<label className="block text-sm font-medium text-wing-text mb-1">
HTTP <span className="text-red-500">*</span>
</label>
<div className="flex gap-2">
{['GET', 'POST'].map((method) => (
<button
key={method}
type="button"
onClick={() => onChange('httpMethod', method)}
className={[
'flex-1 py-2 text-sm font-medium rounded-lg border transition-colors',
httpMethod === method
? 'bg-wing-accent text-white border-wing-accent'
: 'bg-wing-card text-wing-muted border-wing-border hover:bg-wing-hover',
].join(' ')}
>
{method}
</button>
))}
</div>
</div>
{/* 설명 */}
<div className="md:col-span-2">
<label className="block text-sm font-medium text-wing-text mb-1">
</label>
<textarea
value={description}
onChange={(e) => onChange('description', e.target.value)}
rows={3}
placeholder="이 API에 대한 설명을 입력하세요"
className="w-full px-3 py-2 text-sm rounded-lg border border-wing-border bg-wing-card text-wing-text placeholder:text-wing-muted focus:outline-none focus:ring-2 focus:ring-wing-accent/50 resize-none"
/>
</div>
</div>
</div>
);
}