better alias handling

This commit is contained in:
Ignaz Kraft 2026-05-07 01:26:57 +02:00
parent ee420fbf29
commit cc5177edeb
No known key found for this signature in database
GPG Key ID: DAE265DB092113B7
10 changed files with 36 additions and 31 deletions

View File

@ -292,7 +292,7 @@ func getBucketCredentials(bucket string) (aws.CredentialsProvider, error) {
return cacheData.(aws.CredentialsProvider), nil return cacheData.(aws.CredentialsProvider), nil
} }
body, err := utils.Garage.Fetch("/v2/GetBucketInfo?globalAlias="+bucket, &utils.FetchOptions{}) body, err := utils.Garage.Fetch("/v2/GetBucketInfo?id="+bucket, &utils.FetchOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,13 +18,13 @@ type Props = {
}; };
const Actions = ({ prefix }: Props) => { const Actions = ({ prefix }: Props) => {
const { bucketName } = useBucketContext(); const { bucket } = useBucketContext();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const putObject = usePutObject(bucketName, { const putObject = usePutObject(bucket, {
onSuccess: () => { onSuccess: () => {
toast.success("File uploaded!"); toast.success("File uploaded!");
queryClient.invalidateQueries({ queryKey: ["browse", bucketName] }); queryClient.invalidateQueries({ queryKey: ["browse", bucket.id] });
}, },
onError: handleError, onError: handleError,
}); });
@ -76,7 +76,7 @@ type CreateFolderActionProps = {
const CreateFolderAction = ({ prefix }: CreateFolderActionProps) => { const CreateFolderAction = ({ prefix }: CreateFolderActionProps) => {
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const { bucketName } = useBucketContext(); const { bucket } = useBucketContext();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const form = useForm<CreateFolderSchema>({ const form = useForm<CreateFolderSchema>({
@ -88,10 +88,10 @@ const CreateFolderAction = ({ prefix }: CreateFolderActionProps) => {
if (isOpen) form.setFocus("name"); if (isOpen) form.setFocus("name");
}, [isOpen]); }, [isOpen]);
const createFolder = usePutObject(bucketName, { const createFolder = usePutObject(bucket, {
onSuccess: () => { onSuccess: () => {
toast.success("Folder created!"); toast.success("Folder created!");
queryClient.invalidateQueries({ queryKey: ["browse", bucketName] }); queryClient.invalidateQueries({ queryKey: ["browse", bucket.id] });
onClose(); onClose();
form.reset(); form.reset();
}, },

View File

@ -4,6 +4,7 @@ import {
UseMutationOptions, UseMutationOptions,
useQuery, useQuery,
} from "@tanstack/react-query"; } from "@tanstack/react-query";
import { Bucket } from "../../types";
import { import {
GetObjectsResult, GetObjectsResult,
PutObjectPayload, PutObjectPayload,
@ -11,18 +12,18 @@ import {
} from "./types"; } from "./types";
export const useBrowseObjects = ( export const useBrowseObjects = (
bucket: string, bucket: Bucket,
options?: UseBrowserObjectOptions options?: UseBrowserObjectOptions
) => { ) => {
return useQuery({ return useQuery({
queryKey: ["browse", bucket, options], queryKey: ["browse", bucket.id, options],
queryFn: () => queryFn: () =>
api.get<GetObjectsResult>(`/browse/${bucket}`, { params: options }), api.get<GetObjectsResult>(`/browse/${bucket.id}`, { params: options }),
}); });
}; };
export const usePutObject = ( export const usePutObject = (
bucket: string, bucket: Bucket,
options?: UseMutationOptions<any, Error, PutObjectPayload> options?: UseMutationOptions<any, Error, PutObjectPayload>
) => { ) => {
return useMutation({ return useMutation({
@ -32,19 +33,19 @@ export const usePutObject = (
formData.append("file", body.file); formData.append("file", body.file);
} }
return api.put(`/browse/${bucket}/${body.key}`, { body: formData }); return api.put(`/browse/${bucket.id}/${body.key}`, { body: formData });
}, },
...options, ...options,
}); });
}; };
export const useDeleteObject = ( export const useDeleteObject = (
bucket: string, bucket: Bucket,
options?: UseMutationOptions<any, Error, { key: string; recursive?: boolean }> options?: UseMutationOptions<any, Error, { key: string; recursive?: boolean }>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (data) => mutationFn: (data) =>
api.delete(`/browse/${bucket}/${data.key}`, { api.delete(`/browse/${bucket.id}/${data.key}`, {
params: { recursive: data.recursive }, params: { recursive: data.recursive },
}), }),
...options, ...options,

View File

@ -17,14 +17,14 @@ type Props = {
}; };
const ObjectActions = ({ prefix = "", object, end }: Props) => { const ObjectActions = ({ prefix = "", object, end }: Props) => {
const { bucketName } = useBucketContext(); const { bucket, bucketName } = useBucketContext();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const isDirectory = object.objectKey.endsWith("/"); const isDirectory = object.objectKey.endsWith("/");
const deleteObject = useDeleteObject(bucketName, { const deleteObject = useDeleteObject(bucket, {
onSuccess: () => { onSuccess: () => {
toast.success("Object deleted!"); toast.success("Object deleted!");
queryClient.invalidateQueries({ queryKey: ["browse", bucketName] }); queryClient.invalidateQueries({ queryKey: ["browse", bucket.id] });
}, },
onError: handleError, onError: handleError,
}); });
@ -61,6 +61,7 @@ const ObjectActions = ({ prefix = "", object, end }: Props) => {
</Dropdown.Toggle> </Dropdown.Toggle>
<Dropdown.Menu className="gap-y-1"> <Dropdown.Menu className="gap-y-1">
{bucketName && (
<Dropdown.Item <Dropdown.Item
onClick={() => onClick={() =>
shareDialog.open({ key: object.objectKey, prefix }) shareDialog.open({ key: object.objectKey, prefix })
@ -68,6 +69,7 @@ const ObjectActions = ({ prefix = "", object, end }: Props) => {
> >
<Share2 /> Share <Share2 /> Share
</Dropdown.Item> </Dropdown.Item>
)}
<Dropdown.Item <Dropdown.Item
className="text-error bg-error/10" className="text-error bg-error/10"
onClick={onDelete} onClick={onDelete}

View File

@ -21,8 +21,8 @@ type Props = {
}; };
const ObjectList = ({ prefix, onPrefixChange }: Props) => { const ObjectList = ({ prefix, onPrefixChange }: Props) => {
const { bucketName } = useBucketContext(); const { bucket } = useBucketContext();
const { data, error, isLoading } = useBrowseObjects(bucketName, { const { data, error, isLoading } = useBrowseObjects(bucket, {
prefix, prefix,
limit: 1000, limit: 1000,
}); });

View File

@ -18,7 +18,7 @@ const ShareDialog = () => {
const [domain, setDomain] = useState(bucketName); const [domain, setDomain] = useState(bucketName);
const websitePort = config?.s3_web?.bind_addr?.split(":").pop() || "80"; const websitePort = config?.s3_web?.bind_addr?.split(":").pop() || "80";
const rootDomain = config?.s3_web?.root_domain; const rootDomain = config?.s3_web?.root_domain || "";
const domains = useMemo( const domains = useMemo(
() => [ () => [

View File

@ -70,7 +70,7 @@ const WebsiteAccessSection = () => {
<ToggleField form={form} name="websiteAccess" label="Enabled" /> <ToggleField form={form} name="websiteAccess" label="Enabled" />
{isEnabled && ( {isEnabled && bucketName && (
<> <>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<InputField <InputField

View File

@ -40,7 +40,9 @@ const ManageBucketPage = () => {
const { id } = useParams(); const { id } = useParams();
const { data, error, isLoading, refetch } = useBucket(id); const { data, error, isLoading, refetch } = useBucket(id);
const name = data?.globalAliases[0]; const name =
data?.globalAliases?.at(0) ||
data?.keys?.at(0)?.bucketLocalAliases?.at(0);
return ( return (
<> <>

View File

@ -30,7 +30,7 @@ const BucketsPage = () => {
); );
} }
buckets = buckets.sort((a, b) => a.aliases[0].localeCompare(b.aliases[0])); buckets = buckets.sort((a, b) => (a.aliases.at(0) || "").localeCompare(b.aliases.at(0) || ""));
return buckets; return buckets;
}, [data, search]); }, [data, search]);

View File

@ -2,7 +2,7 @@
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "ES2020",
"useDefineForClassFields": true, "useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"], "lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,