diff --git a/src/lib/api.ts b/src/lib/api.ts index a700823..10fa540 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -30,23 +30,21 @@ const api = { headers: { ...headers, ...(options?.headers || {}) }, }); - if (!res.ok) { - const json = await res.json().catch(() => {}); - const message = json?.message || res.statusText; - throw new Error(message); - } - const isJson = res.headers .get("Content-Type") ?.includes("application/json"); + const data = isJson ? await res.json() : await res.text(); - if (isJson) { - const json = (await res.json()) as T; - return json; + if (!res.ok) { + const message = isJson + ? data?.message + : typeof data === "string" + ? data + : res.statusText; + throw new Error(message); } - const text = await res.text(); - return text as unknown as T; + return data as unknown as T; }, async get(url: string, options?: Partial) { diff --git a/src/pages/buckets/manage/browse/object-list.tsx b/src/pages/buckets/manage/browse/object-list.tsx index fbb270a..c27f575 100644 --- a/src/pages/buckets/manage/browse/object-list.tsx +++ b/src/pages/buckets/manage/browse/object-list.tsx @@ -1,10 +1,16 @@ -import { Table } from "react-daisyui"; +import { Alert, Loading, Table } from "react-daisyui"; import { useBrowseObjects } from "./hooks"; import { dayjs, readableBytes } from "@/lib/utils"; import mime from "mime/lite"; import { Object } from "./types"; import { API_URL } from "@/lib/api"; -import { FileArchive, FileIcon, FileType, Folder } from "lucide-react"; +import { + CircleXIcon, + FileArchive, + FileIcon, + FileType, + Folder, +} from "lucide-react"; import { useBucketContext } from "../context"; import ObjectActions from "./object-actions"; import GotoTopButton from "@/components/ui/goto-top-btn"; @@ -16,7 +22,10 @@ type Props = { const ObjectList = ({ prefix, onPrefixChange }: Props) => { const { bucketName } = useBucketContext(); - const { data } = useBrowseObjects(bucketName, { prefix, limit: 1000 }); + const { data, error, isLoading } = useBrowseObjects(bucketName, { + prefix, + limit: 1000, + }); const onObjectClick = (object: Object) => { window.open(API_URL + object.viewUrl, "_blank"); @@ -32,13 +41,29 @@ const ObjectList = ({ prefix, onPrefixChange }: Props) => { - {!data?.prefixes?.length && !data?.objects?.length && ( + {isLoading ? ( - + +
+ +
+ + + ) : error ? ( + + + }> + {error.message} + + + + ) : !data?.prefixes?.length && !data?.objects?.length ? ( + + No objects - )} + ) : null} {data?.prefixes.map((prefix) => ( { const { id } = useParams(); - const { data, refetch } = useBucket(id); + const { data, error, isLoading, refetch } = useBucket(id); const name = data?.globalAliases[0]; return ( -
+ <> : undefined} /> - {data && ( - - - + {isLoading && ( +
+ +
)} -
+ + {error != null && ( + }> + {error.message} + + )} + + {data && ( +
+ + + +
+ )} + ); };