diff --git a/frontend/src/components/buckets/ObjectDetailsView.tsx b/frontend/src/components/buckets/ObjectDetailsView.tsx index cb73f98..ec30287 100644 --- a/frontend/src/components/buckets/ObjectDetailsView.tsx +++ b/frontend/src/components/buckets/ObjectDetailsView.tsx @@ -9,16 +9,7 @@ import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { ArrowLeft, ChevronRight, Copy, Download, File, Loader2, Trash2 } from 'lucide-react'; import { toast } from 'sonner'; import { formatBytes } from '@/lib/file-utils'; - -function formatDate(value: string) { - return new Date(value).toLocaleString(undefined, { - year: 'numeric', - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - }); -} +import { formatDate } from '@/lib/utils'; function CardSection({ title, children }: { title: string; children: React.ReactNode }) { return ( diff --git a/frontend/src/hooks/useBucketObjects.ts b/frontend/src/hooks/useBucketObjects.ts index 68ccfff..08e893a 100644 --- a/frontend/src/hooks/useBucketObjects.ts +++ b/frontend/src/hooks/useBucketObjects.ts @@ -90,10 +90,7 @@ export function useBucketObjects(bucketName: string | null, currentPath: string setUploadTasks(tasks); - let successCount = 0; - let errorCount = 0; - - for (const task of tasks) { + const results = await Promise.all(tasks.map(async (task) => { try { setUploadTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: 'uploading' as const } : t @@ -109,16 +106,19 @@ export function useBucketObjects(bucketName: string | null, currentPath: string setUploadTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: 'completed' as const, progress: 100 } : t )); - successCount++; + return true; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Upload failed'; setUploadTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: 'error' as const, error: errorMessage } : t )); - errorCount++; console.error(`Failed to upload ${task.key}:`, error); + return false; } - } + })); + + const successCount = results.filter(Boolean).length; + const errorCount = results.length - successCount; if (errorCount === 0) { if (hasRelativePaths && folders.size > 0) { diff --git a/frontend/src/pages/BucketSettings.tsx b/frontend/src/pages/BucketSettings.tsx index 781c8d2..f94177e 100644 --- a/frontend/src/pages/BucketSettings.tsx +++ b/frontend/src/pages/BucketSettings.tsx @@ -7,27 +7,11 @@ import { Badge } from '@/components/ui/badge'; import { EmptyState } from '@/components/ui/empty-state'; import { DangerousConfirmDialog } from '@/components/ui/dangerous-confirm-dialog'; import { toast } from 'sonner'; +import { formatBytes } from '@/lib/file-utils'; +import { formatDate as formatDateUtil } from '@/lib/utils'; -function formatBytes(n?: number) { - if (n == null) return '—'; - if (n < 1024) return `${n} B`; - const units = ['KB', 'MB', 'GB', 'TB']; - let v = n / 1024; - for (const u of units) { - if (v < 1024) return `${v.toFixed(v >= 10 ? 0 : 1)} ${u}`; - v /= 1024; - } - return `${v.toFixed(0)} PB`; -} - -function formatDate(iso?: string) { - if (!iso) return '—'; - try { - return new Date(iso).toLocaleString(); - } catch { - return iso; - } -} +const formatBytesOrDash = (n?: number) => (n == null ? '—' : formatBytes(n)); +const formatDateOrDash = (iso?: string) => (iso ? formatDateUtil(iso) : '—'); export function BucketSettings() { const { bucketName = '' } = useParams<{ bucketName: string }>(); @@ -78,9 +62,9 @@ export function BucketSettings() {
{bucket.name}} /> - + - + ()( isLoading: false, error: null }); - } catch (error: any) { - const errorMessage = error.response?.data?.error?.message || 'Login failed'; + } catch (error) { + const errorMessage = + (error as { response?: { data?: { error?: { message?: string } } } }) + .response?.data?.error?.message || + (error instanceof Error ? error.message : 'Login failed'); set({ error: errorMessage, isLoading: false,