mirror of
https://github.com/khairul169/garage-webui.git
synced 2026-09-15 00:43:21 +07:00
feat: add keys & bucket permissions management
This commit is contained in:
@@ -1,8 +1,23 @@
|
||||
import { Cylinder, HardDrive, LayoutDashboard } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
ArchiveIcon,
|
||||
HardDrive,
|
||||
KeySquare,
|
||||
LayoutDashboard,
|
||||
} from "lucide-react";
|
||||
import { Menu } from "react-daisyui";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
|
||||
const pages = [
|
||||
{ icon: LayoutDashboard, title: "Dashboard", path: "/", exact: true },
|
||||
{ icon: HardDrive, title: "Cluster", path: "/cluster" },
|
||||
{ icon: ArchiveIcon, title: "Buckets", path: "/buckets" },
|
||||
{ icon: KeySquare, title: "Keys", path: "/keys" },
|
||||
];
|
||||
|
||||
const Sidebar = () => {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
return (
|
||||
<aside className="bg-base-100 border-r border-base-300/30 w-[220px] overflow-y-auto">
|
||||
<div className="p-4">
|
||||
@@ -14,24 +29,26 @@ const Sidebar = () => {
|
||||
<p className="text-sm font-medium text-center">WebUI</p>
|
||||
</div>
|
||||
<Menu className="gap-y-1">
|
||||
<Menu.Item>
|
||||
<Link to="/">
|
||||
<LayoutDashboard />
|
||||
<p>Dashboard</p>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Link to="/cluster">
|
||||
<HardDrive />
|
||||
<p>Cluster</p>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Link to="/buckets">
|
||||
<Cylinder />
|
||||
<p>Buckets</p>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
{pages.map((page) => {
|
||||
const isActive = page.exact
|
||||
? pathname === page.path
|
||||
: pathname.startsWith(page.path);
|
||||
return (
|
||||
<Menu.Item key={page.path}>
|
||||
<Link
|
||||
to={page.path}
|
||||
className={cn(
|
||||
"h-12 flex items-center px-6",
|
||||
isActive &&
|
||||
"bg-primary text-primary-content hover:bg-primary/60 focus:bg-primary"
|
||||
)}
|
||||
>
|
||||
<page.icon size={18} />
|
||||
<p>{page.title}</p>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
</aside>
|
||||
);
|
||||
|
||||
@@ -40,7 +40,10 @@ const Header = () => {
|
||||
<ArrowLeft />
|
||||
</Button>
|
||||
) : null}
|
||||
<h1 className="text-xl">{page?.title || "Dashboard"}</h1>
|
||||
|
||||
<h1 className="text-xl flex-1 truncate">{page?.title || "Dashboard"}</h1>
|
||||
|
||||
{page?.actions}
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { LucideIcon } from "lucide-react";
|
||||
import { ComponentPropsWithoutRef, forwardRef } from "react";
|
||||
import { Button as BaseButton } from "react-daisyui";
|
||||
import { Link } from "react-router-dom";
|
||||
@@ -5,17 +6,22 @@ import { Link } from "react-router-dom";
|
||||
type ButtonProps = ComponentPropsWithoutRef<typeof BaseButton> & {
|
||||
href?: string;
|
||||
target?: "_blank" | "_self" | "_parent" | "_top";
|
||||
icon?: LucideIcon;
|
||||
};
|
||||
|
||||
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ href, ...props }, ref) => {
|
||||
({ href, children, icon: Icon, shape, ...props }, ref) => {
|
||||
return (
|
||||
<BaseButton
|
||||
ref={ref}
|
||||
tag={href ? Link : undefined}
|
||||
shape={Icon && !children ? "circle" : shape}
|
||||
{...props}
|
||||
{...(href ? { to: href } : {})}
|
||||
/>
|
||||
>
|
||||
{Icon ? <Icon size={18} className={children ? "-ml-1" : ""} /> : null}
|
||||
{children}
|
||||
</BaseButton>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Checkbox as BaseCheckbox } from "react-daisyui";
|
||||
import FormControl from "./form-control";
|
||||
import { FieldValues } from "react-hook-form";
|
||||
|
||||
type CheckboxProps = Omit<
|
||||
React.ComponentPropsWithoutRef<typeof BaseCheckbox>,
|
||||
"form"
|
||||
> & {
|
||||
label?: string;
|
||||
inputClassName?: string;
|
||||
};
|
||||
|
||||
const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
||||
({ label, className, inputClassName, ...props }, ref) => {
|
||||
return (
|
||||
<label
|
||||
className={cn(
|
||||
"label label-text inline-flex items-center justify-start gap-2 cursor-pointer",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<BaseCheckbox
|
||||
ref={ref}
|
||||
color="primary"
|
||||
size="sm"
|
||||
className={inputClassName}
|
||||
{...props}
|
||||
/>
|
||||
{label}
|
||||
</label>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
type CheckboxFieldProps<T extends FieldValues> = Omit<
|
||||
React.ComponentPropsWithoutRef<typeof FormControl<T>>,
|
||||
"render"
|
||||
> &
|
||||
CheckboxProps;
|
||||
|
||||
export const CheckboxField = <T extends FieldValues>({
|
||||
form,
|
||||
name,
|
||||
...props
|
||||
}: CheckboxFieldProps<T>) => {
|
||||
return (
|
||||
<FormControl
|
||||
form={form}
|
||||
name={name}
|
||||
render={(field) => (
|
||||
<Checkbox
|
||||
{...props}
|
||||
{...field}
|
||||
checked={field.value}
|
||||
onChange={(e) => field.onChange(e.target.checked)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Checkbox;
|
||||
@@ -0,0 +1,44 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import { Input as BaseInput } from "react-daisyui";
|
||||
import FormControl from "./form-control";
|
||||
import { FieldValues } from "react-hook-form";
|
||||
|
||||
type InputProps = Omit<
|
||||
React.ComponentPropsWithoutRef<typeof BaseInput>,
|
||||
"form"
|
||||
>;
|
||||
|
||||
const Input = forwardRef<HTMLInputElement, InputProps>(({ ...props }, ref) => {
|
||||
return <BaseInput ref={ref} {...props} />;
|
||||
});
|
||||
|
||||
type InputFieldProps<T extends FieldValues> = Omit<
|
||||
React.ComponentPropsWithoutRef<typeof FormControl<T>>,
|
||||
"render"
|
||||
> &
|
||||
InputProps & {
|
||||
inputClassName?: string;
|
||||
};
|
||||
|
||||
export const InputField = <T extends FieldValues>({
|
||||
form,
|
||||
name,
|
||||
title,
|
||||
className,
|
||||
inputClassName,
|
||||
...props
|
||||
}: InputFieldProps<T>) => {
|
||||
return (
|
||||
<FormControl
|
||||
form={form}
|
||||
name={name}
|
||||
title={title}
|
||||
className={className}
|
||||
render={(field) => (
|
||||
<Input {...props} {...field} className={inputClassName} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Input;
|
||||
Reference in New Issue
Block a user