fix(uploads): retry failed files and report full storage
ci / db / db (push) Successful in 1m51s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m40s
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 33s
ci / ts / ts (packages + web) (push) Failing after 5m16s

This commit is contained in:
mrleo1nid committed 2026-10-29 00:39:03 +03:00
1 parent b39e4dc28f
commit 5e2d1e902b
10 files changed
+205 -18

No files matched your search

+15 -4
View File
@@ -129,7 +129,7 @@ export function SuggestPage() {
{st.items.length > 0 && (
<div className={u.files} aria-label={t('uploads.files')}>
{st.items.map((it) => (
<FileRow key={it.id} item={it} locked={st.busy || finished} onRemove={() => uploader.remove(it.id)} />
<FileRow key={it.id} item={it} locked={st.busy || finished} retryDisabled={!uploader.canRetryFailed} onRetry={() => void uploader.retryFailed(it.id)} onRemove={() => uploader.remove(it.id)} />
))}
</div>
)}
@@ -141,6 +141,7 @@ export function SuggestPage() {
<textarea
className={u.textarea}
value={comment}
disabled={st.busy}
maxLength={1000}
placeholder={t('uploads.comment_hint')}
onChange={(e) => setComment(e.target.value)}
@@ -188,7 +189,13 @@ export function SuggestPage() {
);
}
function FileRow({ item, locked, onRemove }: { item: UploadItem; locked: boolean; onRemove: () => void }) {
function FileRow({ item, locked, retryDisabled, onRetry, onRemove }: {
item: UploadItem;
locked: boolean;
retryDisabled: boolean;
onRetry: () => void;
onRemove: () => void;
}) {
const { t, i18n } = useTranslation(['admin', 'errors']);
const tr = t as unknown as (k: string) => string;
const showProgress = item.stage === 'hashing' || item.stage === 'uploading';
@@ -204,7 +211,7 @@ function FileRow({ item, locked, onRemove }: { item: UploadItem; locked: boolean
note = { text: tr(`errors:${item.code ?? 'uploads.duplicate'}`), cls: u.bad };
break;
case 'error':
note = { text: t('uploads.file_error', { message: item.message ?? '' }), cls: u.bad };
note = { text: item.code === 'uploads.storage_full' ? tr('errors:uploads.storage_full') : t('uploads.file_error', { message: item.message ?? '' }), cls: u.bad };
break;
case 'ready':
if (item.possibleDuplicate) note = { text: t('uploads.possible_dup'), cls: u.warn };
@@ -229,7 +236,11 @@ function FileRow({ item, locked, onRemove }: { item: UploadItem; locked: boolean
{note && <span className={note.cls}>{note.text}</span>}
</div>
<span className={u.size}>{formatBytes(item.size, i18n.language)}</span>
{locked ? (
{item.stage === 'error' && item.tusUrl && item.file ? (
<Button variant="secondary" disabled={retryDisabled} aria-label={t('uploads.retry_file', { name: item.relPath })} onClick={onRetry}>
{t('uploads.retry')}
</Button>
) : locked ? (
<span />
) : (
<Button variant="ghost" aria-label={t('uploads.remove', { name: item.relPath })} onClick={onRemove}>