feat: 수집 실패건 로그 페이징 기능 상세화

This commit is contained in:
hyojin kim 2026-02-27 11:15:07 +09:00
부모 f559b3959b
커밋 1192a1117f
2개의 변경된 파일102개의 추가작업 그리고 74개의 파일을 삭제

파일 보기

@ -575,13 +575,18 @@ export default function ExecutionDetail() {
); );
} }
const FAILED_PAGE_SIZE = 10;
function FailedRecordsToggle({ records, jobName, stepExecutionId }: { records: FailedRecordDto[]; jobName: string; stepExecutionId: number }) { function FailedRecordsToggle({ records, jobName, stepExecutionId }: { records: FailedRecordDto[]; jobName: string; stepExecutionId: number }) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [showConfirm, setShowConfirm] = useState(false); const [showConfirm, setShowConfirm] = useState(false);
const [retrying, setRetrying] = useState(false); const [retrying, setRetrying] = useState(false);
const [page, setPage] = useState(0);
const navigate = useNavigate(); const navigate = useNavigate();
const failedRecords = records.filter((r) => r.status === 'FAILED'); const failedRecords = records.filter((r) => r.status === 'FAILED');
const totalPages = Math.ceil(records.length / FAILED_PAGE_SIZE);
const pagedRecords = records.slice(page * FAILED_PAGE_SIZE, (page + 1) * FAILED_PAGE_SIZE);
const statusColor = (status: string) => { const statusColor = (status: string) => {
switch (status) { switch (status) {
@ -637,44 +642,53 @@ function FailedRecordsToggle({ records, jobName, stepExecutionId }: { records: F
</div> </div>
{open && ( {open && (
<div className="mt-2 overflow-x-auto max-h-80 overflow-y-auto"> <div className="mt-2">
<table className="w-full text-xs text-left"> <div className="overflow-x-auto">
<thead className="bg-red-100 text-red-700 sticky top-0"> <table className="w-full text-xs text-left">
<tr> <thead className="bg-red-100 text-red-700">
<th className="px-2 py-1.5 font-medium">Record Key</th> <tr>
<th className="px-2 py-1.5 font-medium"> </th> <th className="px-2 py-1.5 font-medium">Record Key</th>
<th className="px-2 py-1.5 font-medium text-center"></th> <th className="px-2 py-1.5 font-medium"> </th>
<th className="px-2 py-1.5 font-medium text-center"></th> <th className="px-2 py-1.5 font-medium text-center"></th>
<th className="px-2 py-1.5 font-medium"> </th> <th className="px-2 py-1.5 font-medium text-center"></th>
</tr> <th className="px-2 py-1.5 font-medium"> </th>
</thead>
<tbody className="divide-y divide-red-100">
{records.map((record) => (
<tr
key={record.id}
className="bg-white hover:bg-red-50"
>
<td className="px-2 py-1.5 font-mono text-red-900">
{record.recordKey}
</td>
<td className="px-2 py-1.5 text-red-600 max-w-[200px] truncate" title={record.errorMessage || ''}>
{record.errorMessage || '-'}
</td>
<td className="px-2 py-1.5 text-center text-red-900">
{record.retryCount}
</td>
<td className="px-2 py-1.5 text-center">
<span className={`inline-flex px-1.5 py-0.5 text-[10px] font-medium rounded-full ${statusColor(record.status)}`}>
{record.status}
</span>
</td>
<td className="px-2 py-1.5 text-red-500 whitespace-nowrap">
{formatDateTime(record.createdAt)}
</td>
</tr> </tr>
))} </thead>
</tbody> <tbody className="divide-y divide-red-100">
</table> {pagedRecords.map((record) => (
<tr
key={record.id}
className="bg-white hover:bg-red-50"
>
<td className="px-2 py-1.5 font-mono text-red-900">
{record.recordKey}
</td>
<td className="px-2 py-1.5 text-red-600 max-w-[200px] truncate" title={record.errorMessage || ''}>
{record.errorMessage || '-'}
</td>
<td className="px-2 py-1.5 text-center text-red-900">
{record.retryCount}
</td>
<td className="px-2 py-1.5 text-center">
<span className={`inline-flex px-1.5 py-0.5 text-[10px] font-medium rounded-full ${statusColor(record.status)}`}>
{record.status}
</span>
</td>
<td className="px-2 py-1.5 text-red-500 whitespace-nowrap">
{formatDateTime(record.createdAt)}
</td>
</tr>
))}
</tbody>
</table>
</div>
<Pagination
page={page}
totalPages={totalPages}
totalElements={records.length}
pageSize={FAILED_PAGE_SIZE}
onPageChange={setPage}
/>
</div> </div>
)} )}

파일 보기

@ -626,13 +626,18 @@ export default function RecollectDetail() {
); );
} }
const FAILED_PAGE_SIZE = 10;
function FailedRecordsToggle({ records, jobName, stepExecutionId }: { records: FailedRecordDto[]; jobName: string; stepExecutionId: number }) { function FailedRecordsToggle({ records, jobName, stepExecutionId }: { records: FailedRecordDto[]; jobName: string; stepExecutionId: number }) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [showConfirm, setShowConfirm] = useState(false); const [showConfirm, setShowConfirm] = useState(false);
const [retrying, setRetrying] = useState(false); const [retrying, setRetrying] = useState(false);
const [page, setPage] = useState(0);
const navigate = useNavigate(); const navigate = useNavigate();
const failedRecords = records.filter((r) => r.status === 'FAILED'); const failedRecords = records.filter((r) => r.status === 'FAILED');
const totalPages = Math.ceil(records.length / FAILED_PAGE_SIZE);
const pagedRecords = records.slice(page * FAILED_PAGE_SIZE, (page + 1) * FAILED_PAGE_SIZE);
const statusColor = (status: string) => { const statusColor = (status: string) => {
switch (status) { switch (status) {
@ -688,44 +693,53 @@ function FailedRecordsToggle({ records, jobName, stepExecutionId }: { records: F
</div> </div>
{open && ( {open && (
<div className="mt-2 overflow-x-auto max-h-80 overflow-y-auto"> <div className="mt-2">
<table className="w-full text-xs text-left"> <div className="overflow-x-auto">
<thead className="bg-red-100 text-red-700 sticky top-0"> <table className="w-full text-xs text-left">
<tr> <thead className="bg-red-100 text-red-700">
<th className="px-2 py-1.5 font-medium">Record Key</th> <tr>
<th className="px-2 py-1.5 font-medium"> </th> <th className="px-2 py-1.5 font-medium">Record Key</th>
<th className="px-2 py-1.5 font-medium text-center"></th> <th className="px-2 py-1.5 font-medium"> </th>
<th className="px-2 py-1.5 font-medium text-center"></th> <th className="px-2 py-1.5 font-medium text-center"></th>
<th className="px-2 py-1.5 font-medium"> </th> <th className="px-2 py-1.5 font-medium text-center"></th>
</tr> <th className="px-2 py-1.5 font-medium"> </th>
</thead>
<tbody className="divide-y divide-red-100">
{records.map((record) => (
<tr
key={record.id}
className="bg-white hover:bg-red-50"
>
<td className="px-2 py-1.5 font-mono text-red-900">
{record.recordKey}
</td>
<td className="px-2 py-1.5 text-red-600 max-w-[200px] truncate" title={record.errorMessage || ''}>
{record.errorMessage || '-'}
</td>
<td className="px-2 py-1.5 text-center text-red-900">
{record.retryCount}
</td>
<td className="px-2 py-1.5 text-center">
<span className={`inline-flex px-1.5 py-0.5 text-[10px] font-medium rounded-full ${statusColor(record.status)}`}>
{record.status}
</span>
</td>
<td className="px-2 py-1.5 text-red-500 whitespace-nowrap">
{formatDateTime(record.createdAt)}
</td>
</tr> </tr>
))} </thead>
</tbody> <tbody className="divide-y divide-red-100">
</table> {pagedRecords.map((record) => (
<tr
key={record.id}
className="bg-white hover:bg-red-50"
>
<td className="px-2 py-1.5 font-mono text-red-900">
{record.recordKey}
</td>
<td className="px-2 py-1.5 text-red-600 max-w-[200px] truncate" title={record.errorMessage || ''}>
{record.errorMessage || '-'}
</td>
<td className="px-2 py-1.5 text-center text-red-900">
{record.retryCount}
</td>
<td className="px-2 py-1.5 text-center">
<span className={`inline-flex px-1.5 py-0.5 text-[10px] font-medium rounded-full ${statusColor(record.status)}`}>
{record.status}
</span>
</td>
<td className="px-2 py-1.5 text-red-500 whitespace-nowrap">
{formatDateTime(record.createdAt)}
</td>
</tr>
))}
</tbody>
</table>
</div>
<Pagination
page={page}
totalPages={totalPages}
totalElements={records.length}
pageSize={FAILED_PAGE_SIZE}
onPageChange={setPage}
/>
</div> </div>
)} )}