fix: bucket access/delete error handling and policy private support (#75)

This commit is contained in:
GatewayJ
2026-03-10 15:00:41 +08:00
committed by GitHub
parent 4b40353d93
commit 82f00c7ea1
5 changed files with 42 additions and 17 deletions
+1
View File
@@ -20,6 +20,7 @@
/.nuxt/
/.output/
/.vscode/
.cursor/
# production
/build
+16 -3
View File
@@ -51,10 +51,23 @@ export function BrowserContent({ bucketName, keyPath = "", preview = false, prev
if (!bucketName) return
headBucket(bucketName)
.then(() => {})
.catch(() => {
message.error(t("Bucket not found"))
.catch((error: unknown) => {
const err = error as { $metadata?: { httpStatusCode?: number }; Code?: string; message?: string }
const status = err?.$metadata?.httpStatusCode
const code = (err?.Code ?? (error as Error)?.message ?? "").toLowerCase()
const isAccessDenied =
status === 403 ||
code === "accessdenied" ||
code === "forbidden" ||
(typeof code === "string" && (code.includes("access denied") || code.includes("forbidden")))
message.error(isAccessDenied ? t("Access Denied") : t("Bucket not found"))
const params = new URLSearchParams(searchParams.toString())
router.push(`/browser?${params.toString()}`)
params.delete("bucket")
params.delete("prefix")
params.delete("preview")
params.delete("previewKey")
const query = params.toString()
router.push(query ? `/browser?${query}` : "/browser")
})
}, [bucketName, headBucket, message, router, t, searchParams])
+13 -13
View File
@@ -237,24 +237,24 @@ function BrowserBucketsPage() {
}
const deleteItem = async (row: BucketRow) => {
const files = await objectApi.listObject(row.Name, undefined, 1)
const hasObjects =
Boolean((files as { Contents?: Array<{ Key?: string }> })?.Contents?.some((item) => Boolean(item?.Key))) ||
Boolean((files as { CommonPrefixes?: unknown[] })?.CommonPrefixes?.length)
if (hasObjects) {
message.error(t("Bucket is not empty"))
return
}
try {
const files = await objectApi.listObject(row.Name, undefined, 1)
const hasObjects =
Boolean((files as { Contents?: Array<{ Key?: string }> })?.Contents?.some((item) => Boolean(item?.Key))) ||
Boolean((files as { CommonPrefixes?: unknown[] })?.CommonPrefixes?.length)
if (hasObjects) {
message.error(t("Bucket is not empty"))
return
}
await deleteBucket(row.Name)
message.success(t("Delete Success"))
await fetchBuckets({ force: true })
} catch (error: unknown) {
message.error(
(error as { response?: { data?: { message?: string } } })?.response?.data?.message || t("Delete Failed"),
)
const err = error as { response?: { data?: { message?: string } }; message?: string }
const msg = err?.response?.data?.message ?? (error as Error)?.message ?? t("Delete Failed")
message.error(msg)
}
}
+3 -1
View File
@@ -188,7 +188,9 @@ export function BucketInfo({ bucketName }: BucketInfoProps) {
const submitPolicy = async () => {
try {
if (policyFormPolicy === "custom") {
if (policyFormPolicy === "private") {
await bucketApi.deleteBucketPolicy(bucketName)
} else if (policyFormPolicy === "custom") {
JSON.parse(policyFormContent)
await bucketApi.putBucketPolicy(bucketName, policyFormContent)
} else {
+9
View File
@@ -27,6 +27,7 @@ import {
DeleteBucketTaggingCommand,
DeleteBucketEncryptionCommand,
DeleteBucketLifecycleCommand,
DeleteBucketPolicyCommand,
DeleteBucketReplicationCommand,
PutBucketNotificationConfigurationCommand,
GetBucketNotificationConfigurationCommand,
@@ -185,6 +186,13 @@ export function useBucket() {
[client],
)
const deleteBucketPolicy = useCallback(
async (bucket: string) => {
return client.send(new DeleteBucketPolicyCommand({ Bucket: bucket }))
},
[client],
)
const getObjectLockConfiguration = useCallback(
async (bucket: string) => {
return client.send(new GetObjectLockConfigurationCommand({ Bucket: bucket }))
@@ -357,6 +365,7 @@ export function useBucket() {
getBucketPolicyStatus,
getBucketPolicy,
putBucketPolicy,
deleteBucketPolicy,
getObjectLockConfiguration,
putObjectLockConfiguration,
getBucketLifecycleConfiguration,