Files
garage-webui/src/pages/buckets/manage/permissions/allow-key-dialog.tsx
T

179 lines
5.6 KiB
TypeScript

import Button from "@/components/ui/button";
import { useKeys } from "@/pages/keys/hooks";
import { zodResolver } from "@hookform/resolvers/zod";
import { Plus } from "lucide-react";
import { useEffect } from "react";
import { Checkbox, Modal, Table } from "react-daisyui";
import { useFieldArray, useForm } from "react-hook-form";
import { AllowKeysSchema, allowKeysSchema } from "../schema";
import { useDisclosure } from "@/hooks/useDisclosure";
import { CheckboxField } from "@/components/ui/checkbox";
import { useAllowKey } from "../hooks";
import { toast } from "sonner";
import { handleError } from "@/lib/utils";
import { useQueryClient } from "@tanstack/react-query";
import { useBucketContext } from "../context";
type Props = {
currentKeys?: string[];
};
const AllowKeyDialog = ({ currentKeys }: Props) => {
const { bucket } = useBucketContext();
const { dialogRef, isOpen, onOpen, onClose } = useDisclosure();
const { data: keys } = useKeys();
const form = useForm<AllowKeysSchema>({
resolver: zodResolver(allowKeysSchema),
});
const { fields: keyFields } = useFieldArray({
control: form.control,
name: "keys",
});
const queryClient = useQueryClient();
const allowKey = useAllowKey(bucket.id, {
onSuccess: () => {
form.reset();
onClose();
toast.success("Key allowed!");
queryClient.invalidateQueries({ queryKey: ["bucket", bucket.id] });
},
onError: handleError,
});
useEffect(() => {
const _keys = keys
?.filter((key) => !currentKeys?.includes(key.id))
?.map((key) => ({
checked: false,
keyId: key.id,
name: key.name,
read: false,
write: false,
owner: false,
}));
form.setValue("keys", _keys || []);
}, [keys, currentKeys]);
const onToggleAll = (
e: React.ChangeEvent<HTMLInputElement>,
field: keyof AllowKeysSchema["keys"][number]
) => {
const curValues = form.getValues("keys");
const newValues = curValues.map((item) => ({
...item,
[field]: e.target.checked,
}));
form.setValue("keys", newValues);
};
const onSubmit = form.handleSubmit((values) => {
const data = values.keys
.filter((key) => key.checked)
.map((key) => ({
keyId: key.keyId,
permissions: { read: key.read, write: key.write, owner: key.owner },
}));
allowKey.mutate(data);
});
return (
<>
<Button icon={Plus} color="primary" onClick={onOpen}>
Allow Key
</Button>
<Modal ref={dialogRef} backdrop open={isOpen} className="max-w-2xl">
<Modal.Header className="mb-1">Allow Key</Modal.Header>
<Modal.Body>
<p>Enter the key you want to allow access to.</p>
<div className="overflow-x-auto mt-4">
<Table>
<Table.Head>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
color="primary"
size="sm"
onChange={(e) => onToggleAll(e, "checked")}
/>
Key
</label>
<label>Local Aliases</label>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
color="primary"
size="sm"
onChange={(e) => onToggleAll(e, "read")}
/>
Read
</label>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
color="primary"
size="sm"
onChange={(e) => onToggleAll(e, "write")}
/>
Write
</label>
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
color="primary"
size="sm"
onChange={(e) => onToggleAll(e, "owner")}
/>
Owner
</label>
</Table.Head>
<Table.Body>
{!keyFields.length ? (
<tr>
<td colSpan={5} className="text-center">
No keys found
</td>
</tr>
) : null}
{keyFields.map((field, index) => {
const curKey = bucket.keys.find(
(key) => key.accessKeyId === field.keyId
);
return (
<Table.Row key={field.id}>
<CheckboxField
form={form}
name={`keys.${index}.checked`}
label={field.name || field.keyId?.substring(0, 8)}
/>
<span>
{curKey?.bucketLocalAliases?.join(", ") || "-"}
</span>
<CheckboxField form={form} name={`keys.${index}.read`} />
<CheckboxField form={form} name={`keys.${index}.write`} />
<CheckboxField form={form} name={`keys.${index}.owner`} />
</Table.Row>
);
})}
</Table.Body>
</Table>
</div>
</Modal.Body>
<Modal.Actions>
<Button onClick={onClose}>Cancel</Button>
<Button
color="primary"
disabled={allowKey.isPending}
onClick={onSubmit}
>
Submit
</Button>
</Modal.Actions>
</Modal>
</>
);
};
export default AllowKeyDialog;