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
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:
1 parent
b39e4dc28f
commit
5e2d1e902b
10 files changed
+205
-18
No files matched your search
@@ -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}>
|
||||
|
||||
Reference in new issue
Block a user