Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 6 additions & 157 deletions components/object/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ import { downloadUrl } from "@/lib/export-file"
import { getAttachmentContentDisposition } from "@/lib/content-disposition"
import { formatBytes, formatDateTime } from "@/lib/functions"
import { cn } from "@/lib/utils"
import { PrefixSummaryLimitError } from "@/lib/prefix-summary"
import { normalizeDateToIso } from "@/lib/safe-date"
import { buildBucketPath } from "@/lib/bucket-path"
import {
Expand Down Expand Up @@ -116,7 +115,6 @@ interface ObjectRow {
type: "prefix" | "object"
Size: number
LastModified: string
summary?: { size: number; lastModified?: Date }
deleted: boolean
}

Expand Down Expand Up @@ -170,7 +168,7 @@ export function ObjectList({
const { t } = useTranslation()
const message = useMessage()
const api = useApi()
const { listObject, calculatePrefixSummary, getSignedUrl, renameObject } = useObject(bucket)
const { listObject, getSignedUrl, renameObject } = useObject(bucket)
const { getBucketVersioning } = useBucket()
const { canCapability } = usePermissions()
const addDeleteKeys = useAddDeleteKeys()
Expand All @@ -187,14 +185,6 @@ export function ObjectList({
OBJECT_LIST_DEFAULT_PAGE_SIZE,
)
const deletedView = resolveObjectListDeletedView(storedDeletedView)
const [prefixSummaries, setPrefixSummaries] = React.useState<Record<string, { size: number; lastModified?: Date }>>(
{},
)
const [prefixScan, setPrefixScan] = React.useState<{
key: string
state: "loading" | "failed" | "cancelled" | "limit" | "success"
} | null>(null)
const prefixScanRef = React.useRef<AbortController | null>(null)
const [loading, setLoading] = React.useState(false)
const [listError, setListError] = React.useState<ObjectListError | null>(null)
const [loadMoreError, setLoadMoreError] = React.useState(false)
Expand Down Expand Up @@ -384,53 +374,7 @@ export function ObjectList({
[bucket, prefix, resolvedPageSize, includeDeleted, listObject, message, t],
)

const scanPrefix = React.useCallback(
async (key: string) => {
if (prefixScanRef.current) return
const controller = new AbortController()
prefixScanRef.current = controller
setPrefixSummaries((current) => {
const next = { ...current }
delete next[key]
return next
})
setPrefixScan({ key, state: "loading" })
try {
const summary = await calculatePrefixSummary(key, controller.signal)
if (prefixScanRef.current !== controller) return
controller.signal.throwIfAborted()
setPrefixSummaries((current) => ({ ...current, [key]: summary }))
setPrefixScan({ key, state: "success" })
} catch (error) {
if (prefixScanRef.current !== controller) return
setPrefixScan({
key,
state: controller.signal.aborted
? "cancelled"
: error instanceof PrefixSummaryLimitError
? "limit"
: "failed",
})
} finally {
if (prefixScanRef.current === controller) prefixScanRef.current = null
}
},
[calculatePrefixSummary],
)

React.useEffect(
() => () => {
prefixScanRef.current?.abort()
prefixScanRef.current = null
},
[listScope],
)

const resetAndFetchObjects = React.useCallback(() => {
prefixScanRef.current?.abort()
prefixScanRef.current = null
setPrefixScan(null)
setPrefixSummaries({})
setNextToken(undefined)
setData([])
void fetchObjects({ resetPagination: true })
Expand Down Expand Up @@ -639,29 +583,8 @@ export function ObjectList({
{
id: "size",
header: () => t("Size"),
accessorFn: (row) => (row.type === "object" ? row.Size : (row.summary?.size ?? -1)),
cell: ({ row }) => {
if (row.original.type === "object") return formatBytes(row.original.Size)
const key = row.original.Key
const summary = row.original.summary
const state = prefixScan?.key === key ? prefixScan.state : null
return (
<div className="flex flex-col items-start gap-1">
{summary ? <span>{formatBytes(summary.size)}</span> : <span>-</span>}
{state !== "loading" ? (
<Button
variant="outline"
size="sm"
aria-label={t("Calculate statistics for {prefix}", { prefix: key })}
disabled={prefixScan?.state === "loading"}
onClick={() => void scanPrefix(key)}
>
{t("Calculate folder statistics")}
</Button>
) : null}
</div>
)
},
accessorFn: (row) => (row.type === "object" ? row.Size : -1),
cell: ({ row }) => (row.original.type === "object" ? formatBytes(row.original.Size) : "-"),
},
{
id: "lastModified",
Expand All @@ -673,14 +596,8 @@ export function ObjectList({
) : null}
</span>
),
accessorFn: (row) => {
const date = row.type === "prefix" ? row.summary?.lastModified : row.LastModified
return date ? new Date(date).getTime() : -1
},
cell: ({ row }) => {
const date = row.original.type === "prefix" ? row.original.summary?.lastModified : row.original.LastModified
return date ? formatDateTime(date) : "-"
},
accessorFn: (row) => (row.type === "prefix" || !row.LastModified ? "" : new Date(row.LastModified).getTime()),
cell: ({ row }) => (row.original.LastModified ? formatDateTime(row.original.LastModified) : "-"),
},
{
id: "actions",
Expand Down Expand Up @@ -811,20 +728,11 @@ export function ObjectList({
nextToken,
setRowActionTrigger,
getRowActionTrigger,
prefixScan,
scanPrefix,
],
)

const tableRows = React.useMemo(() => {
if (Object.keys(prefixSummaries).length === 0) return filteredData
return filteredData.map((row) => {
const summary = row.type === "prefix" ? prefixSummaries[row.Key] : undefined
return summary ? { ...row, summary } : row
})
}, [filteredData, prefixSummaries])
const { table, selectedRowIds } = useDataTable<ObjectRow>({
data: tableRows,
data: filteredData,
columns,
getRowId: (row) => row.Key,
enableRowSelection: true,
Expand Down Expand Up @@ -1057,65 +965,6 @@ export function ObjectList({
{heading ?? <h1>{bucket}</h1>}
</PageHeader>

{data.some((row) => row.type === "prefix") ? (
<p className="text-sm text-muted-foreground">
{t(
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.",
)}
</p>
) : null}
{prefixScan ? (
<div className="sticky top-16 z-10 flex items-center gap-2 rounded-md border bg-background p-3">
<div
role={prefixScan.state === "failed" || prefixScan.state === "limit" ? "alert" : "status"}
className="min-w-0 flex-1"
title={prefixScan.key}
>
<div className="flex min-w-0 gap-1">
<span className="shrink-0">
{prefixScan.state === "loading"
? t("Calculating folder statistics...")
: prefixScan.state === "cancelled"
? t("Calculation cancelled.")
: prefixScan.state === "limit"
? t("Folder exceeds the scan limit.")
: prefixScan.state === "success"
? t("Complete")
: t("Could not calculate folder statistics.")}
</span>
<bdi className="truncate">{prefixScan.key}</bdi>
</div>
{prefixScan.state === "success" && prefixSummaries[prefixScan.key] ? (
<div className="flex flex-wrap gap-x-3 text-xs text-muted-foreground">
<span>
{t("Size")}: {formatBytes(prefixSummaries[prefixScan.key].size)}
</span>
<span>
{t("Last Modified")}:{" "}
{prefixSummaries[prefixScan.key].lastModified
? formatDateTime(prefixSummaries[prefixScan.key].lastModified)
: "-"}
</span>
</div>
) : null}
</div>
{prefixScan.state === "loading" ? (
<Button
variant="outline"
size="sm"
aria-label={t("Cancel statistics for {prefix}", { prefix: prefixScan.key })}
className="shrink-0"
onClick={() => prefixScanRef.current?.abort()}
>
{t("Cancel")}
</Button>
) : (
<Button variant="outline" size="sm" className="shrink-0" onClick={() => setPrefixScan(null)}>
{t("Close")}
</Button>
)}
</div>
) : null}
<DataTable
caption={t("Objects")}
toolbar={
Expand Down
7 changes: 0 additions & 7 deletions hooks/use-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
} from "@aws-sdk/client-s3"
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
import { useS3 } from "@/contexts/s3-context"
import { fetchPrefixSummary } from "@/lib/prefix-summary-request"
import { encodeObjectCopySource } from "@/lib/object-rename"
import { decodeS3UrlEncodedObjectList, decodeS3UrlEncodedObjectVersions } from "@/lib/s3-object-encoding"

Expand Down Expand Up @@ -156,11 +155,6 @@ export function useObject(bucket: string) {
[client],
)

const calculatePrefixSummary = useCallback(
(prefix: string, signal: AbortSignal) => fetchPrefixSummary(client, bucket, prefix, signal),
[client, bucket],
)

const mapAllFiles = useCallback(
async (bucketName: string, prefix: string, callback: (fileKey: string) => void) => {
let isTruncated = true
Expand Down Expand Up @@ -346,7 +340,6 @@ export function useObject(bucket: string) {
restoreObjectVersion,
getSignedUrl: getSignedUrlFn,
listObject,
calculatePrefixSummary,
mapAllFiles,
getObjectInfo,
getObjectTags,
Expand Down
8 changes: 0 additions & 8 deletions i18n/locales/ar-MA.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,6 @@
"Cache clear completed with warnings": "اكتمل مسح التخزين المؤقت مع تحذيرات",
"Cache cleared successfully": "تم مسح التخزين المؤقت بنجاح",
"Cache time-to-live in seconds, default: 600": "مدة صلاحية التخزين المؤقت بالثواني، الافتراضي: 600",
"Calculate folder statistics": "حساب إحصاءات المجلد",
"Calculate statistics for {prefix}": "حساب إحصاءات {prefix}",
"Cancel statistics for {prefix}": "إلغاء إحصاءات {prefix}",
"Calculating folder statistics...": "جارٍ حساب إحصاءات المجلد...",
"Could not calculate folder statistics.": "تعذر حساب إحصاءات المجلد.",
"Calculation cancelled.": "تم إلغاء الحساب.",
"Folder exceeds the scan limit.": "يتجاوز المجلد حد الفحص.",
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.": "تفحص إحصاءات المجلد حتى 100 صفحة أو 100,000 كائن حالي، أيهما يتحقق أولاً. يعتمد آخر تعديل على هذه الكائنات؛ قد تتغير النتائج أثناء الفحص.",
"Cancel": "إلغاء",
"Cancel Deletion": "إلغاء الحذف",
"Cancel Key Deletion": "إلغاء حذف المفتاح",
Expand Down
8 changes: 0 additions & 8 deletions i18n/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,6 @@
"Cache clear completed with warnings": "Cache-Löschung mit Warnungen abgeschlossen",
"Cache cleared successfully": "Cache erfolgreich gelöscht",
"Cache time-to-live in seconds, default: 600": "Cache-Lebensdauer in Sekunden, Standard: 600",
"Calculate folder statistics": "Ordnerstatistik berechnen",
"Calculate statistics for {prefix}": "Statistik für {prefix} berechnen",
"Cancel statistics for {prefix}": "Statistik für {prefix} abbrechen",
"Calculating folder statistics...": "Ordnerstatistik wird berechnet...",
"Could not calculate folder statistics.": "Ordnerstatistik konnte nicht berechnet werden.",
"Calculation cancelled.": "Berechnung abgebrochen.",
"Folder exceeds the scan limit.": "Ordner überschreitet das Scanlimit.",
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.": "Die Ordnerstatistik durchsucht höchstens 100 Seiten oder 100.000 aktuelle Objekte, je nachdem, welches Limit zuerst erreicht wird. Die letzte Änderung basiert auf diesen Objekten; Ergebnisse können sich während des Scans ändern.",
"Cancel": "Abbrechen",
"Cancel Deletion": "Löschung abbrechen",
"Cancel Key Deletion": "Schlüssellöschung abbrechen",
Expand Down
8 changes: 0 additions & 8 deletions i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,6 @@
"Cache clear completed with warnings": "Cache clear completed with warnings",
"Cache cleared successfully": "Cache cleared successfully",
"Cache time-to-live in seconds, default: 600": "Cache time-to-live in seconds, default: 600",
"Calculate folder statistics": "Calculate folder statistics",
"Calculate statistics for {prefix}": "Calculate statistics for {prefix}",
"Cancel statistics for {prefix}": "Cancel statistics for {prefix}",
"Calculating folder statistics...": "Calculating folder statistics...",
"Could not calculate folder statistics.": "Could not calculate folder statistics.",
"Calculation cancelled.": "Calculation cancelled.",
"Folder exceeds the scan limit.": "Folder exceeds the scan limit.",
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.": "Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.",
"Cancel": "Cancel",
"Cancel Deletion": "Cancel Deletion",
"Cancel Key Deletion": "Cancel Key Deletion",
Expand Down
8 changes: 0 additions & 8 deletions i18n/locales/es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,6 @@
"Cache clear completed with warnings": "Limpieza de caché completada con advertencias",
"Cache cleared successfully": "Caché limpiada exitosamente",
"Cache time-to-live in seconds, default: 600": "Tiempo de vida de la caché en segundos, predeterminado: 600",
"Calculate folder statistics": "Calcular estadísticas de carpeta",
"Calculate statistics for {prefix}": "Calcular estadísticas de {prefix}",
"Cancel statistics for {prefix}": "Cancelar estadísticas de {prefix}",
"Calculating folder statistics...": "Calculando estadísticas de carpeta...",
"Could not calculate folder statistics.": "No se pudieron calcular las estadísticas.",
"Calculation cancelled.": "Cálculo cancelado.",
"Folder exceeds the scan limit.": "La carpeta supera el límite de exploración.",
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.": "Las estadísticas exploran hasta 100 páginas o 100.000 objetos actuales, lo que ocurra primero. La última modificación se basa en estos objetos; los resultados pueden cambiar durante la exploración.",
"Cancel": "Cancelar",
"Cancel Deletion": "Cancelar eliminación",
"Cancel Key Deletion": "Cancelar eliminación de clave",
Expand Down
8 changes: 0 additions & 8 deletions i18n/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,6 @@
"Cache clear completed with warnings": "Effacement du cache terminé avec des avertissements",
"Cache cleared successfully": "Cache effacé avec succès",
"Cache time-to-live in seconds, default: 600": "Durée de vie du cache en secondes, par défaut : 600",
"Calculate folder statistics": "Calculer les statistiques du dossier",
"Calculate statistics for {prefix}": "Calculer les statistiques de {prefix}",
"Cancel statistics for {prefix}": "Annuler les statistiques de {prefix}",
"Calculating folder statistics...": "Calcul des statistiques du dossier...",
"Could not calculate folder statistics.": "Impossible de calculer les statistiques.",
"Calculation cancelled.": "Calcul annulé.",
"Folder exceeds the scan limit.": "Le dossier dépasse la limite d’analyse.",
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.": "Les statistiques analysent au maximum 100 pages ou 100 000 objets actuels, selon la première limite atteinte. La dernière modification concerne ces objets ; les résultats peuvent changer pendant l’analyse.",
"Cancel": "Annuler",
"Cancel Deletion": "Annuler la suppression",
"Cancel Key Deletion": "Annuler la suppression de la clé",
Expand Down
8 changes: 0 additions & 8 deletions i18n/locales/id-ID.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,6 @@
"Cache clear completed with warnings": "Pembersihan cache selesai dengan peringatan",
"Cache cleared successfully": "Cache berhasil dibersihkan",
"Cache time-to-live in seconds, default: 600": "Time-to-live cache dalam detik, default: 600",
"Calculate folder statistics": "Hitung statistik folder",
"Calculate statistics for {prefix}": "Hitung statistik untuk {prefix}",
"Cancel statistics for {prefix}": "Batalkan statistik untuk {prefix}",
"Calculating folder statistics...": "Menghitung statistik folder...",
"Could not calculate folder statistics.": "Statistik folder tidak dapat dihitung.",
"Calculation cancelled.": "Penghitungan dibatalkan.",
"Folder exceeds the scan limit.": "Folder melampaui batas pemindaian.",
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.": "Statistik folder memindai hingga 100 halaman atau 100.000 objek saat ini, mana pun yang tercapai lebih dahulu. Modifikasi terakhir berdasarkan objek tersebut; hasil dapat berubah selama pemindaian.",
"Cancel": "Batal",
"Cancel Deletion": "Batalkan Penghapusan",
"Cancel Key Deletion": "Batalkan Penghapusan Kunci",
Expand Down
8 changes: 0 additions & 8 deletions i18n/locales/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,6 @@
"Cache clear completed with warnings": "Pulizia cache completata con avvisi",
"Cache cleared successfully": "Cache pulita con successo",
"Cache time-to-live in seconds, default: 600": "Tempo di vita cache in secondi, predefinito: 600",
"Calculate folder statistics": "Calcola statistiche cartella",
"Calculate statistics for {prefix}": "Calcola statistiche per {prefix}",
"Cancel statistics for {prefix}": "Annulla statistiche per {prefix}",
"Calculating folder statistics...": "Calcolo statistiche cartella...",
"Could not calculate folder statistics.": "Impossibile calcolare le statistiche.",
"Calculation cancelled.": "Calcolo annullato.",
"Folder exceeds the scan limit.": "La cartella supera il limite di scansione.",
"Folder statistics scan up to 100 pages or 100,000 current objects, whichever comes first. Latest modification is based on these objects; results may change during the scan.": "Le statistiche analizzano fino a 100 pagine o 100.000 oggetti correnti, a seconda del limite raggiunto per primo. L’ultima modifica si basa su questi oggetti; i risultati possono cambiare durante la scansione.",
"Cancel": "Annulla",
"Cancel Deletion": "Annulla eliminazione",
"Cancel Key Deletion": "Annulla eliminazione chiave",
Expand Down
Loading