release: 2026-04-01 (14건 커밋) #133
@ -10,6 +10,12 @@
|
||||
- 섹션 간 직접 이동
|
||||
- 메인화면 카드 높이 동기화 (CSS Grid)
|
||||
|
||||
### 수정
|
||||
- S&P Collector 다크모드 미적용 및 라벨 디자인 통일 (#122)
|
||||
- 실행이력상세/재수집이력상세 API 호출 로그 다크모드 적용
|
||||
- 개별 호출 로그 필터/테이블 다크모드 적용
|
||||
- 작업관리 스케줄 라벨 rounded-full 디자인 통일
|
||||
|
||||
## [2026-03-31]
|
||||
|
||||
### 추가
|
||||
|
||||
@ -71,11 +71,11 @@ export default function ApiLogSection({ stepExecutionId, summary }: ApiLogSectio
|
||||
className={`px-2.5 py-1 text-xs rounded-full font-medium transition-colors ${
|
||||
status === key
|
||||
? key === 'ERROR'
|
||||
? 'bg-red-100 text-red-700'
|
||||
? 'bg-red-500/15 text-red-500'
|
||||
: key === 'SUCCESS'
|
||||
? 'bg-emerald-100 text-emerald-700'
|
||||
: 'bg-blue-100 text-blue-700'
|
||||
: 'bg-gray-100 text-gray-500 hover:bg-gray-200'
|
||||
? 'bg-emerald-500/15 text-emerald-500'
|
||||
: 'bg-blue-500/15 text-blue-500'
|
||||
: 'bg-wing-card text-wing-muted hover:bg-wing-hover'
|
||||
}`}
|
||||
>
|
||||
{label} ({count.toLocaleString()})
|
||||
@ -92,7 +92,7 @@ export default function ApiLogSection({ stepExecutionId, summary }: ApiLogSectio
|
||||
<>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-xs text-left">
|
||||
<thead className="bg-blue-100 text-blue-700 sticky top-0">
|
||||
<thead className="bg-blue-500/15 text-blue-500 sticky top-0">
|
||||
<tr>
|
||||
<th className="px-2 py-1.5 font-medium">#</th>
|
||||
<th className="px-2 py-1.5 font-medium">URI</th>
|
||||
@ -104,24 +104,24 @@ export default function ApiLogSection({ stepExecutionId, summary }: ApiLogSectio
|
||||
<th className="px-2 py-1.5 font-medium">에러</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-blue-100">
|
||||
<tbody className="divide-y divide-blue-500/15">
|
||||
{logData.content.map((log, idx) => {
|
||||
const isError = (log.statusCode != null && log.statusCode >= 400) || log.errorMessage;
|
||||
return (
|
||||
<tr
|
||||
key={log.logId}
|
||||
className={isError ? 'bg-red-50' : 'bg-white hover:bg-blue-50'}
|
||||
className={isError ? 'bg-red-500/10' : 'bg-wing-surface hover:bg-blue-500/10'}
|
||||
>
|
||||
<td className="px-2 py-1.5 text-blue-500">{page * 10 + idx + 1}</td>
|
||||
<td className="px-2 py-1.5 max-w-[200px]">
|
||||
<div className="flex items-center gap-0.5">
|
||||
<span className="font-mono text-blue-900 truncate" title={log.requestUri}>
|
||||
<span className="font-mono text-wing-text truncate" title={log.requestUri}>
|
||||
{log.requestUri}
|
||||
</span>
|
||||
<CopyButton text={log.requestUri} />
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 py-1.5 font-semibold text-blue-900">{log.httpMethod}</td>
|
||||
<td className="px-2 py-1.5 font-semibold text-wing-text">{log.httpMethod}</td>
|
||||
<td className="px-2 py-1.5">
|
||||
<span className={`font-semibold ${
|
||||
log.statusCode == null ? 'text-gray-400'
|
||||
@ -132,10 +132,10 @@ export default function ApiLogSection({ stepExecutionId, summary }: ApiLogSectio
|
||||
{log.statusCode ?? '-'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-2 py-1.5 text-right text-blue-900">
|
||||
<td className="px-2 py-1.5 text-right text-wing-text">
|
||||
{log.responseTimeMs?.toLocaleString() ?? '-'}
|
||||
</td>
|
||||
<td className="px-2 py-1.5 text-right text-blue-900">
|
||||
<td className="px-2 py-1.5 text-right text-wing-text">
|
||||
{log.responseCount?.toLocaleString() ?? '-'}
|
||||
</td>
|
||||
<td className="px-2 py-1.5 text-blue-600 whitespace-nowrap">
|
||||
|
||||
@ -96,32 +96,32 @@ function StepCard({ step, jobName, jobExecutionId }: StepCardProps) {
|
||||
|
||||
{/* API 호출 정보: apiLogSummary가 있으면 개별 로그 리스트, 없으면 기존 apiCallInfo 요약 */}
|
||||
{step.apiLogSummary ? (
|
||||
<div className="mt-4 rounded-lg bg-blue-50 border border-blue-200 p-3">
|
||||
<div className="mt-4 rounded-lg bg-blue-500/10 border border-blue-500/20 p-3">
|
||||
<p className="text-xs font-medium text-blue-700 mb-2">API 호출 정보</p>
|
||||
<div className="grid grid-cols-3 sm:grid-cols-6 gap-2">
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-wing-text">{step.apiLogSummary.totalCalls.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">총 호출</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-emerald-600">{step.apiLogSummary.successCount.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">성공</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className={`text-sm font-bold ${step.apiLogSummary.errorCount > 0 ? 'text-red-500' : 'text-wing-text'}`}>
|
||||
{step.apiLogSummary.errorCount.toLocaleString()}
|
||||
</p>
|
||||
<p className="text-[10px] text-wing-muted">에러</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-blue-600">{Math.round(step.apiLogSummary.avgResponseMs).toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">평균(ms)</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-red-500">{step.apiLogSummary.maxResponseMs.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">최대(ms)</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-emerald-500">{step.apiLogSummary.minResponseMs.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">최소(ms)</p>
|
||||
</div>
|
||||
@ -132,7 +132,7 @@ function StepCard({ step, jobName, jobExecutionId }: StepCardProps) {
|
||||
)}
|
||||
</div>
|
||||
) : step.apiCallInfo && (
|
||||
<div className="mt-4 rounded-lg bg-blue-50 border border-blue-200 p-3">
|
||||
<div className="mt-4 rounded-lg bg-blue-500/10 border border-blue-500/20 p-3">
|
||||
<p className="text-xs font-medium text-blue-700 mb-2">API 호출 정보</p>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2 text-xs">
|
||||
<div>
|
||||
@ -163,7 +163,7 @@ function StepCard({ step, jobName, jobExecutionId }: StepCardProps) {
|
||||
)}
|
||||
|
||||
{step.exitMessage && (
|
||||
<div className="mt-4 rounded-lg bg-red-50 border border-red-200 p-3">
|
||||
<div className="mt-4 rounded-lg bg-red-500/10 border border-red-500/20 p-3">
|
||||
<p className="text-xs font-medium text-red-700 mb-1">Exit Message</p>
|
||||
<p className="text-xs text-red-600 whitespace-pre-wrap break-words">
|
||||
{step.exitMessage}
|
||||
@ -468,7 +468,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-4 rounded-lg bg-red-50 border border-red-200 p-3">
|
||||
<div className="mt-4 rounded-lg bg-red-500/10 border border-red-500/20 p-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<button
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
@ -522,7 +522,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<div className="mt-2">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-xs text-left">
|
||||
<thead className="bg-red-100 text-red-700">
|
||||
<thead className="bg-red-500/20 text-red-700">
|
||||
<tr>
|
||||
<th className="px-2 py-1.5 font-medium">Record Key</th>
|
||||
<th className="px-2 py-1.5 font-medium">에러 메시지</th>
|
||||
@ -531,11 +531,11 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<th className="px-2 py-1.5 font-medium">생성 시간</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-red-100">
|
||||
<tbody className="divide-y divide-red-500/20">
|
||||
{pagedRecords.map((record) => (
|
||||
<tr
|
||||
key={record.id}
|
||||
className="bg-white hover:bg-red-50"
|
||||
className="bg-wing-surface hover:bg-red-500/10"
|
||||
>
|
||||
<td className="px-2 py-1.5 font-mono text-red-900">
|
||||
{record.recordKey}
|
||||
@ -581,19 +581,19 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
{/* 재수집 확인 다이얼로그 */}
|
||||
{showConfirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<div className="bg-wing-surface rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<h3 className="text-lg font-semibold text-wing-text mb-2">
|
||||
실패 건 재수집 확인
|
||||
</h3>
|
||||
<p className="text-sm text-wing-muted mb-3">
|
||||
다음 {failedRecords.length}건의 IMO에 대해 재수집을 실행합니다.
|
||||
</p>
|
||||
<div className="bg-gray-50 rounded-lg p-3 mb-4 max-h-40 overflow-y-auto">
|
||||
<div className="bg-wing-card rounded-lg p-3 mb-4 max-h-40 overflow-y-auto">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{failedRecords.map((r) => (
|
||||
<span
|
||||
key={r.id}
|
||||
className="inline-flex px-2 py-0.5 text-xs font-mono bg-red-100 text-red-700 rounded"
|
||||
className="inline-flex px-2 py-0.5 text-xs font-mono bg-red-500/20 text-red-700 rounded"
|
||||
>
|
||||
{r.recordKey}
|
||||
</span>
|
||||
@ -604,7 +604,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<button
|
||||
onClick={() => setShowConfirm(false)}
|
||||
disabled={retrying}
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-wing-card hover:bg-wing-hover rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
@ -630,7 +630,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
{/* 일괄 RESOLVED 확인 다이얼로그 */}
|
||||
{showResolveConfirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<div className="bg-wing-surface rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<h3 className="text-lg font-semibold text-wing-text mb-2">
|
||||
일괄 RESOLVED 확인
|
||||
</h3>
|
||||
@ -642,7 +642,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<button
|
||||
onClick={() => setShowResolveConfirm(false)}
|
||||
disabled={resolving}
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-wing-card hover:bg-wing-hover rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
@ -668,7 +668,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
{/* 재시도 초기화 확인 다이얼로그 */}
|
||||
{showResetConfirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<div className="bg-wing-surface rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<h3 className="text-lg font-semibold text-wing-text mb-2">
|
||||
재시도 초기화 확인
|
||||
</h3>
|
||||
@ -680,7 +680,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<button
|
||||
onClick={() => setShowResetConfirm(false)}
|
||||
disabled={resetting}
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-wing-card hover:bg-wing-hover rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
|
||||
@ -376,11 +376,11 @@ export default function Jobs() {
|
||||
|
||||
<div className="flex items-center gap-2 pt-0.5">
|
||||
{job.scheduleCron ? (
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-emerald-100 text-emerald-700">
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold bg-emerald-500/15 text-emerald-500">
|
||||
자동
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-wing-card text-wing-muted">
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-wing-card text-wing-muted">
|
||||
수동
|
||||
</span>
|
||||
)}
|
||||
@ -478,11 +478,11 @@ export default function Jobs() {
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
{job.scheduleCron ? (
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-emerald-100 text-emerald-700">
|
||||
<span className="inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-semibold bg-emerald-100 text-emerald-700">
|
||||
자동
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-wing-card text-wing-muted">
|
||||
<span className="inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-semibold bg-wing-card text-wing-muted">
|
||||
수동
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -75,32 +75,32 @@ function StepCard({ step, jobName, jobExecutionId }: { step: StepExecutionDto; j
|
||||
|
||||
{/* API 호출 로그 요약 (batch_api_log 기반) */}
|
||||
{summary && (
|
||||
<div className="mt-4 rounded-lg bg-blue-50 border border-blue-200 p-3">
|
||||
<div className="mt-4 rounded-lg bg-blue-500/10 border border-blue-500/20 p-3">
|
||||
<p className="text-xs font-medium text-blue-700 mb-2">API 호출 정보</p>
|
||||
<div className="grid grid-cols-3 sm:grid-cols-6 gap-2">
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-wing-text">{summary.totalCalls.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">총 호출</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-emerald-600">{summary.successCount.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">성공</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className={`text-sm font-bold ${summary.errorCount > 0 ? 'text-red-500' : 'text-wing-text'}`}>
|
||||
{summary.errorCount.toLocaleString()}
|
||||
</p>
|
||||
<p className="text-[10px] text-wing-muted">에러</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-blue-600">{Math.round(summary.avgResponseMs).toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">평균(ms)</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-red-500">{summary.maxResponseMs.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">최대(ms)</p>
|
||||
</div>
|
||||
<div className="rounded bg-white px-2 py-1.5 text-center">
|
||||
<div className="rounded bg-wing-surface px-2 py-1.5 text-center">
|
||||
<p className="text-sm font-bold text-emerald-500">{summary.minResponseMs.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-wing-muted">최소(ms)</p>
|
||||
</div>
|
||||
@ -118,7 +118,7 @@ function StepCard({ step, jobName, jobExecutionId }: { step: StepExecutionDto; j
|
||||
)}
|
||||
|
||||
{step.exitMessage && (
|
||||
<div className="mt-4 rounded-lg bg-red-50 border border-red-200 p-3">
|
||||
<div className="mt-4 rounded-lg bg-red-500/10 border border-red-500/20 p-3">
|
||||
<p className="text-xs font-medium text-red-700 mb-1">Exit Message</p>
|
||||
<p className="text-xs text-red-600 whitespace-pre-wrap break-words">
|
||||
{step.exitMessage}
|
||||
@ -361,7 +361,7 @@ export default function RecollectDetail() {
|
||||
<h2 className="text-lg font-semibold text-red-600 mb-3">
|
||||
실패 사유
|
||||
</h2>
|
||||
<pre className="text-sm text-wing-text font-mono bg-red-50 border border-red-200 px-4 py-3 rounded-lg whitespace-pre-wrap break-words max-h-64 overflow-y-auto">
|
||||
<pre className="text-sm text-wing-text font-mono bg-red-500/10 border border-red-500/20 px-4 py-3 rounded-lg whitespace-pre-wrap break-words max-h-64 overflow-y-auto">
|
||||
{history.failureReason}
|
||||
</pre>
|
||||
</div>
|
||||
@ -536,7 +536,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-4 rounded-lg bg-red-50 border border-red-200 p-3">
|
||||
<div className="mt-4 rounded-lg bg-red-500/10 border border-red-500/20 p-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<button
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
@ -590,7 +590,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<div className="mt-2">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-xs text-left">
|
||||
<thead className="bg-red-100 text-red-700">
|
||||
<thead className="bg-red-500/20 text-red-700">
|
||||
<tr>
|
||||
<th className="px-2 py-1.5 font-medium">Record Key</th>
|
||||
<th className="px-2 py-1.5 font-medium">에러 메시지</th>
|
||||
@ -599,11 +599,11 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<th className="px-2 py-1.5 font-medium">생성 시간</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-red-100">
|
||||
<tbody className="divide-y divide-red-500/20">
|
||||
{pagedRecords.map((record) => (
|
||||
<tr
|
||||
key={record.id}
|
||||
className="bg-white hover:bg-red-50"
|
||||
className="bg-wing-surface hover:bg-red-500/10"
|
||||
>
|
||||
<td className="px-2 py-1.5 font-mono text-red-900">
|
||||
{record.recordKey}
|
||||
@ -649,19 +649,19 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
{/* 재수집 확인 다이얼로그 */}
|
||||
{showConfirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<div className="bg-wing-surface rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<h3 className="text-lg font-semibold text-wing-text mb-2">
|
||||
실패 건 재수집 확인
|
||||
</h3>
|
||||
<p className="text-sm text-wing-muted mb-3">
|
||||
다음 {failedRecords.length}건의 IMO에 대해 재수집을 실행합니다.
|
||||
</p>
|
||||
<div className="bg-gray-50 rounded-lg p-3 mb-4 max-h-40 overflow-y-auto">
|
||||
<div className="bg-wing-card rounded-lg p-3 mb-4 max-h-40 overflow-y-auto">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{failedRecords.map((r) => (
|
||||
<span
|
||||
key={r.id}
|
||||
className="inline-flex px-2 py-0.5 text-xs font-mono bg-red-100 text-red-700 rounded"
|
||||
className="inline-flex px-2 py-0.5 text-xs font-mono bg-red-500/20 text-red-700 rounded"
|
||||
>
|
||||
{r.recordKey}
|
||||
</span>
|
||||
@ -672,7 +672,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<button
|
||||
onClick={() => setShowConfirm(false)}
|
||||
disabled={retrying}
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-wing-card hover:bg-wing-hover rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
@ -698,7 +698,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
{/* 일괄 RESOLVED 확인 다이얼로그 */}
|
||||
{showResolveConfirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<div className="bg-wing-surface rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<h3 className="text-lg font-semibold text-wing-text mb-2">
|
||||
일괄 RESOLVED 확인
|
||||
</h3>
|
||||
@ -710,7 +710,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<button
|
||||
onClick={() => setShowResolveConfirm(false)}
|
||||
disabled={resolving}
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-wing-card hover:bg-wing-hover rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
@ -736,7 +736,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
{/* 재시도 초기화 확인 다이얼로그 */}
|
||||
{showResetConfirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<div className="bg-wing-surface rounded-xl shadow-2xl p-6 w-full max-w-md mx-4">
|
||||
<h3 className="text-lg font-semibold text-wing-text mb-2">
|
||||
재시도 초기화 확인
|
||||
</h3>
|
||||
@ -748,7 +748,7 @@ function FailedRecordsToggle({ records, jobName, jobExecutionId }: { records: Fa
|
||||
<button
|
||||
onClick={() => setShowResetConfirm(false)}
|
||||
disabled={resetting}
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 text-sm font-medium text-wing-muted bg-wing-card hover:bg-wing-hover rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user