style: run prettier to fix code formatting

This commit is contained in:
overtrue
2025-11-03 21:41:59 +08:00
parent d73ce8073b
commit bc96a40b98
6 changed files with 127 additions and 54 deletions
+6 -2
View File
@@ -61,8 +61,12 @@ const handleEscape = (event: Event) => {
<template>
<Dialog :open="modelValue" @update:open="handleUpdateOpen">
<DialogContent :class="cn(sizeClassMap[size], props.class, contentClass)" @pointerDownOutside="handlePointerOutside" @interactOutside="handlePointerOutside"
@escapeKeyDown="handleEscape">
<DialogContent
:class="cn(sizeClassMap[size], props.class, contentClass)"
@pointerDownOutside="handlePointerOutside"
@interactOutside="handlePointerOutside"
@escapeKeyDown="handleEscape"
>
<DialogHeader v-if="title || description || $slots.header" class="text-left">
<slot name="header">
<DialogTitle v-if="title">{{ title }}</DialogTitle>
+16 -6
View File
@@ -104,10 +104,14 @@
<FieldLabel>{{ t('Retention Mode') }}</FieldLabel>
<FieldContent>
<RadioGroup v-model="retentionMode" class="grid gap-2 sm:grid-cols-2">
<label v-for="option in [
{ label: t('COMPLIANCE'), value: 'COMPLIANCE' },
{ label: t('GOVERNANCE'), value: 'GOVERNANCE' },
]" :key="option.value" class="flex items-start gap-3 rounded-md border border-border/50 p-3">
<label
v-for="option in [
{ label: t('COMPLIANCE'), value: 'COMPLIANCE' },
{ label: t('GOVERNANCE'), value: 'GOVERNANCE' },
]"
:key="option.value"
class="flex items-start gap-3 rounded-md border border-border/50 p-3"
>
<RadioGroupItem :value="option.value" class="mt-0.5" />
<span class="text-sm font-medium">{{ option.label }}</span>
</label>
@@ -130,8 +134,14 @@
</Modal>
<object-preview-modal v-model:show="showPreview" :object="previewObject ?? object" />
<ObjectVersions :bucket-name="bucketName" :object-key="object?.Key || ''" :visible="showVersions" @close="handleVersionsClose" @preview="handlePreviewVersion"
@refresh-parent="handleVersionsRefresh" />
<ObjectVersions
:bucket-name="bucketName"
:object-key="object?.Key || ''"
:visible="showVersions"
@close="handleVersionsClose"
@preview="handlePreviewVersion"
@refresh-parent="handleVersionsRefresh"
/>
</Drawer>
</template>
+44 -22
View File
@@ -13,7 +13,13 @@
<Icon name="ri:file-add-line" class="size-4" />
<span>{{ t('Upload File') }}/{{ t('Folder') }}</span>
</Button>
<Button variant="outline" class="text-destructive border-destructive" :disabled="!checkedKeys.length" v-show="checkedKeys.length" @click="handleBatchDelete">
<Button
variant="outline"
class="text-destructive border-destructive"
:disabled="!checkedKeys.length"
v-show="checkedKeys.length"
@click="handleBatchDelete"
>
<Icon name="ri:delete-bin-5-line" class="size-4" />
<span>{{ t('Delete Selected') }}</span>
</Button>
@@ -28,7 +34,12 @@
</template>
</page-header>
<DataTable :table="table" :is-loading="loading" :empty-title="t('No Objects')" :empty-description="t('Upload files or create folders to populate this bucket.')" />
<DataTable
:table="table"
:is-loading="loading"
:empty-title="t('No Objects')"
:empty-description="t('Upload files or create folders to populate this bucket.')"
/>
<div class="flex justify-end gap-2">
<Button variant="outline" :disabled="!continuationToken" @click="goToPreviousPage">
@@ -42,18 +53,29 @@
</div>
</div>
<object-upload-picker :show="uploadPickerVisible" :bucketName="bucketName" :prefix="prefix" @update:show="
val => {
uploadPickerVisible = val
refresh()
}
" />
<object-new-form :show="newObjectFormVisible" :bucketName="bucketName" :prefix="prefix" :asPrefix="newObjectAsPrefix" @update:show="
val => {
newObjectFormVisible = val
refresh()
}
" />
<object-upload-picker
:show="uploadPickerVisible"
:bucketName="bucketName"
:prefix="prefix"
@update:show="
val => {
uploadPickerVisible = val
refresh()
}
"
/>
<object-new-form
:show="newObjectFormVisible"
:bucketName="bucketName"
:prefix="prefix"
:asPrefix="newObjectAsPrefix"
@update:show="
val => {
newObjectFormVisible = val
refresh()
}
"
/>
<object-info ref="infoRef" :bucket-name="bucketName" @refresh-parent="handleObjectDeleted" />
</template>
@@ -263,14 +285,14 @@ const columns = computed<ColumnDef<ObjectRow, any>[]>(() => {
h('div', { class: 'flex items-center gap-2' }, [
row.original.type === 'object'
? h(
Button,
{
variant: 'outline',
size: 'sm',
onClick: () => downloadFile(row.original.Key),
},
() => [h(Icon, { name: 'ri:download-cloud-2-line', class: 'size-4' }), h('span', t('Download'))]
)
Button,
{
variant: 'outline',
size: 'sm',
onClick: () => downloadFile(row.original.Key),
},
() => [h(Icon, { name: 'ri:download-cloud-2-line', class: 'size-4' }), h('span', t('Download'))]
)
: null,
h(
Button,
+36 -9
View File
@@ -7,7 +7,9 @@
<div class="flex flex-wrap items-center justify-between gap-3">
<div class="space-y-1">
<p class="text-sm font-medium text-muted-foreground">{{ t('Target Bucket') }}: {{ bucketName }}</p>
<p class="text-xs text-muted-foreground">{{ t('Current Prefix') }}: <span class="text-blue-500">{{ prefix || '/' }}</span></p>
<p class="text-xs text-muted-foreground">
{{ t('Current Prefix') }}: <span class="text-blue-500">{{ prefix || '/' }}</span>
</p>
</div>
<ActionBar>
@@ -28,7 +30,10 @@
</AlertDescription>
</Alert>
<Alert v-if="isMemoryWarning" class="border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-100">
<Alert
v-if="isMemoryWarning"
class="border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-100"
>
<AlertDescription>
{{ t('Large File Count Warning', { count: totalFileCount.toLocaleString(), max: MAX_FILES_LIMIT }) }}
</AlertDescription>
@@ -41,16 +46,30 @@
<p v-if="totalFileCount > 0">{{ t('Total Files') }}: {{ totalFileCount.toLocaleString() }}</p>
<p v-if="totalFileCount > 0">{{ t('Memory Usage') }}: {{ getMemoryUsageLevel() }}</p>
</div>
<Button variant="outline" size="sm" :disabled="!hasFiles || isFolderLoading || isAdding" @click="clearAllFiles">
<Button
variant="outline"
size="sm"
:disabled="!hasFiles || isFolderLoading || isAdding"
@click="clearAllFiles"
>
<Icon name="ri:delete-bin-line" class="size-4" />
{{ t('Clear All') }}
</Button>
</div>
<!-- objects list / drag area -->
<div class="rounded-md border-t transition" :class="isDragOver ? 'border-primary bg-primary/5' : ''" @dragenter.prevent="handleDragEnter" @dragover.prevent="handleDragOver"
@dragleave.prevent="handleDragLeave" @drop.prevent="handleDrop">
<div v-if="!selectedItems.length" class="flex h-[40vh] flex-col items-center justify-center gap-4 p-6 text-center">
<div
class="rounded-md border-t transition"
:class="isDragOver ? 'border-primary bg-primary/5' : ''"
@dragenter.prevent="handleDragEnter"
@dragover.prevent="handleDragOver"
@dragleave.prevent="handleDragLeave"
@drop.prevent="handleDrop"
>
<div
v-if="!selectedItems.length"
class="flex h-[40vh] flex-col items-center justify-center gap-4 p-6 text-center"
>
<Icon name="ri:cloud-upload-line" class="size-10 text-muted-foreground" />
<p class="text-base font-medium text-muted-foreground">{{ t('No Selection') }}</p>
<p class="max-w-[320px] text-sm text-muted-foreground">
@@ -77,7 +96,10 @@
<tr v-for="(item, index) in selectedItems" :key="item.uid" class="border-b last:border-b-0">
<td class="px-3 py-2">
<div class="flex items-start gap-2">
<Icon :name="item.type === 'folder' ? 'ri:folder-3-line' : 'ri:file-line'" class="mt-0.5 size-4 text-muted-foreground" />
<Icon
:name="item.type === 'folder' ? 'ri:folder-3-line' : 'ri:file-line'"
class="mt-0.5 size-4 text-muted-foreground"
/>
<div>
<div class="font-medium text-foreground truncate max-w-md">
{{ item.name }}<span v-if="item.type === 'folder'">/</span>
@@ -124,7 +146,12 @@
<Button variant="outline" :disabled="!hasFiles || isAdding || isFolderLoading">
{{ t('Configure') }}
</Button>
<Button variant="default" :disabled="!hasFiles || isAdding || isFolderLoading" :loading="isAdding" @click="handleUpload">
<Button
variant="default"
:disabled="!hasFiles || isAdding || isFolderLoading"
:loading="isAdding"
@click="handleUpload"
>
{{ t('Start Upload') }}
</Button>
</div>
@@ -213,7 +240,7 @@ const clearAllFiles = () => {
if (typeof window !== 'undefined' && 'gc' in window && typeof (window as any).gc === 'function') {
try {
; (window as any).gc()
;(window as any).gc()
} catch {
// ignore
}
+2 -2
View File
@@ -118,8 +118,8 @@ watch(
const fetchVersions = async () => {
loading.value = true
try {
const response = await objectApi.getObjectVersions(props.objectKey)
versions.value = response.Versions ?? []
const response = await objectApi.listObjectVersions(props.objectKey)
versions.value = response.Versions
} catch (error) {
message.error(t('Failed to fetch versions'))
versions.value = []
+23 -13
View File
@@ -1,18 +1,18 @@
import {
DeleteObjectCommand,
DeleteObjectTaggingCommand,
GetObjectCommand,
GetObjectLegalHoldCommand,
GetObjectRetentionCommand,
GetObjectTaggingCommand,
HeadObjectCommand,
ListObjectsV2Command,
PutObjectCommand,
GetObjectTaggingCommand,
PutObjectTaggingCommand,
DeleteObjectTaggingCommand,
GetObjectRetentionCommand,
PutObjectRetentionCommand,
GetObjectLegalHoldCommand,
PutObjectLegalHoldCommand,
ListObjectVersionsCommand,
ObjectLockRetentionMode,
PutObjectCommand,
PutObjectLegalHoldCommand,
PutObjectRetentionCommand,
PutObjectTaggingCommand,
} from '@aws-sdk/client-s3'
import { getSignedUrl as _getSignedUrl } from '@aws-sdk/s3-request-presigner'
@@ -211,19 +211,29 @@ export function useObject({ bucket, region }: { bucket: string; region?: string
return await $client.send(new PutObjectLegalHoldCommand(params))
}
async function getObjectVersions(key: string) {
async function listObjectVersions(key: string) {
const params = {
Bucket: bucket,
Prefix: key,
Prefix: key, // match "abc" and "abcd"
Delimiter: '/', // has no effect on "abcd", can keep or remove
}
return await $client.send(new ListObjectVersionsCommand(params))
const res = await $client.send(new ListObjectVersionsCommand(params))
const Versions = (res.Versions ?? []).filter(v => v.Key === key)
const DeleteMarkers = (res.DeleteMarkers ?? []).filter(m => m.Key === key)
// Sort by LastModified desc
Versions.sort((a, b) => +new Date(b.LastModified!) - +new Date(a.LastModified!))
DeleteMarkers.sort((a, b) => +new Date(b.LastModified!) - +new Date(a.LastModified!))
return { ...res, Versions, DeleteMarkers }
}
async function deleteAllVersions(key: string) {
try {
// Get all versions of the object
const versions = await getObjectVersions(key)
const versions = await listObjectVersions(key)
const versionsToDelete = versions.Versions || []
const deleteMarkers = versions.DeleteMarkers || []
@@ -258,7 +268,7 @@ export function useObject({ bucket, region }: { bucket: string; region?: string
getObjectLegalHold,
putObjectLegalHold,
setLegalHold: (key: string, enabled: boolean) => putObjectLegalHold(key, { Status: enabled ? 'ON' : 'OFF' }),
getObjectVersions,
listObjectVersions,
deleteAllVersions,
}
}