Remove idle connection timeout handling
Remove error handling for closed connections Add progress watchdog to detect stalled accounts Improve error modal styling and pagination
This commit is contained in:
@@ -3,6 +3,7 @@ import { Modal } from './Modal'
|
||||
import { listAccountErrors, type AccountError } from '../api'
|
||||
|
||||
const fmt = (iso: string) => (iso ? new Date(iso).toLocaleString() : '—')
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
export function AccountErrorsModal({
|
||||
taskId,
|
||||
@@ -15,51 +16,76 @@ export function AccountErrorsModal({
|
||||
}) {
|
||||
const [errors, setErrors] = useState<AccountError[] | null>(null)
|
||||
const [failed, setFailed] = useState(false)
|
||||
const [page, setPage] = useState(0)
|
||||
const open = account !== null
|
||||
|
||||
useEffect(() => {
|
||||
if (!account) return
|
||||
setErrors(null)
|
||||
setFailed(false)
|
||||
setPage(0)
|
||||
listAccountErrors(taskId, account.id)
|
||||
.then((e) => setErrors(e ?? []))
|
||||
.catch(() => setFailed(true))
|
||||
}, [taskId, account])
|
||||
|
||||
const total = errors?.length ?? 0
|
||||
const pageCount = Math.max(1, Math.ceil(total / PAGE_SIZE))
|
||||
const current = Math.min(page, pageCount - 1)
|
||||
const slice = errors?.slice(current * PAGE_SIZE, current * PAGE_SIZE + PAGE_SIZE) ?? []
|
||||
|
||||
const title = account
|
||||
? `Errors — ${account.src_login}${total ? ` (${total})` : ''}`
|
||||
: 'Errors'
|
||||
|
||||
return (
|
||||
<Modal open={open} title={account ? `Errors — ${account.src_login}` : 'Errors'} onClose={onClose} size="lg">
|
||||
<div className="tbl-wrap">
|
||||
<table className="tbl">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Kind</th>
|
||||
<th>Folder</th>
|
||||
<th>Message</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{failed ? (
|
||||
<tr className="empty-row"><td colSpan={5}>failed to load errors</td></tr>
|
||||
) : errors === null ? (
|
||||
<tr className="empty-row"><td colSpan={5}>loading…</td></tr>
|
||||
) : errors.length === 0 ? (
|
||||
<tr className="empty-row"><td colSpan={5}>no errors recorded</td></tr>
|
||||
) : (
|
||||
errors.map((e) => (
|
||||
<tr key={e.id}>
|
||||
<td>{fmt(e.created_at)}</td>
|
||||
<td>{e.kind}</td>
|
||||
<td>{e.folder || '—'}</td>
|
||||
<td>{e.message_ref || '—'}</td>
|
||||
<td className="err-cell">{e.error}</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<Modal open={open} title={title} onClose={onClose} size="lg">
|
||||
{failed ? (
|
||||
<div className="err-empty">failed to load errors</div>
|
||||
) : errors === null ? (
|
||||
<div className="err-empty">loading…</div>
|
||||
) : total === 0 ? (
|
||||
<div className="err-empty">no errors recorded</div>
|
||||
) : (
|
||||
<>
|
||||
<ul className="err-list">
|
||||
{slice.map((e) => (
|
||||
<li key={e.id} className="err-item">
|
||||
<div className="err-item-head">
|
||||
<span className="err-kind">{e.kind}</span>
|
||||
{e.folder && <span className="err-folder">{e.folder}</span>}
|
||||
{e.message_ref && <span className="err-ref">{e.message_ref}</span>}
|
||||
<span className="err-time">{fmt(e.created_at)}</span>
|
||||
</div>
|
||||
<div className="err-text">{e.error}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{pageCount > 1 && (
|
||||
<div className="err-pager">
|
||||
<button
|
||||
type="button"
|
||||
className="btn"
|
||||
disabled={current === 0}
|
||||
onClick={() => setPage(current - 1)}
|
||||
>
|
||||
‹ prev
|
||||
</button>
|
||||
<span className="err-pageinfo">
|
||||
page {current + 1} / {pageCount}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="btn"
|
||||
disabled={current >= pageCount - 1}
|
||||
onClick={() => setPage(current + 1)}
|
||||
>
|
||||
next ›
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user