refactor(group): remove deprecated user group components
Remove unused user group management components as user groups have been deprecated in favor of node groups only.
This commit is contained in:
@@ -1,210 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@workspace/ui/components/dialog";
|
||||
import { Input } from "@workspace/ui/components/input";
|
||||
import { Label } from "@workspace/ui/components/label";
|
||||
import { Textarea } from "@workspace/ui/components/textarea";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@workspace/ui/components/select";
|
||||
import { Switch } from "@workspace/ui/components/switch";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { forwardRef, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface UserGroupFormProps {
|
||||
initialValues?: Partial<API.UserGroup>;
|
||||
loading?: boolean;
|
||||
nodeGroups?: API.NodeGroup[];
|
||||
onSubmit: (values: Record<string, unknown>) => Promise<boolean>;
|
||||
title: string;
|
||||
trigger: React.ReactNode;
|
||||
}
|
||||
|
||||
const UserGroupForm = forwardRef<
|
||||
HTMLButtonElement,
|
||||
UserGroupFormProps
|
||||
>(({ initialValues, loading, nodeGroups = [], onSubmit, title, trigger }, ref) => {
|
||||
const { t } = useTranslation("group");
|
||||
const [open, setOpen] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
const [values, setValues] = useState({
|
||||
name: "",
|
||||
description: "",
|
||||
sort: 0,
|
||||
node_group_id: null as number | null,
|
||||
for_calculation: true,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
if (initialValues) {
|
||||
setValues({
|
||||
name: initialValues.name || "",
|
||||
description: initialValues.description || "",
|
||||
sort: initialValues.sort ?? 0,
|
||||
node_group_id: initialValues.node_group_id || null,
|
||||
for_calculation: initialValues.for_calculation ?? true,
|
||||
});
|
||||
} else {
|
||||
setValues({
|
||||
name: "",
|
||||
description: "",
|
||||
sort: 0,
|
||||
node_group_id: null,
|
||||
for_calculation: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [initialValues, open]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSubmitting(true);
|
||||
const success = await onSubmit(values);
|
||||
setSubmitting(false);
|
||||
if (success) {
|
||||
setOpen(false);
|
||||
setValues({
|
||||
name: "",
|
||||
description: "",
|
||||
sort: 0,
|
||||
node_group_id: null,
|
||||
for_calculation: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild ref={ref}>
|
||||
{trigger}
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t("userGroupFormDescription", "Configure user group settings")}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name">
|
||||
{t("name", "Name")} *
|
||||
</Label>
|
||||
<Input
|
||||
id="name"
|
||||
value={values.name}
|
||||
onChange={(e) =>
|
||||
setValues({ ...values, name: e.target.value })
|
||||
}
|
||||
placeholder={t("namePlaceholder", "Enter name")}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
<Label htmlFor="for_calculation">{t("forCalculation", "For Calculation")}</Label>
|
||||
<Switch
|
||||
id="for_calculation"
|
||||
checked={values.for_calculation}
|
||||
onCheckedChange={(checked) =>
|
||||
setValues({ ...values, for_calculation: checked })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="description">
|
||||
{t("description", "Description")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
value={values.description}
|
||||
onChange={(e) =>
|
||||
setValues({ ...values, description: e.target.value })
|
||||
}
|
||||
placeholder={t("descriptionPlaceholder", "Enter description")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="node_group_id">{t("nodeGroup", "Node Group")}</Label>
|
||||
<Select
|
||||
value={values.node_group_id ? String(values.node_group_id) : "0"}
|
||||
onValueChange={(val) =>
|
||||
setValues({
|
||||
...values,
|
||||
node_group_id: val === "0" ? null : parseInt(val),
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger id="node_group_id" className="w-full">
|
||||
<SelectValue placeholder={t("selectNodeGroupPlaceholder", "Select a node group...")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="0">
|
||||
{t("unbound", "Unbound")}
|
||||
</SelectItem>
|
||||
{nodeGroups.map((nodeGroup) => (
|
||||
<SelectItem key={nodeGroup.id} value={String(nodeGroup.id)}>
|
||||
{nodeGroup.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="sort">{t("sort", "Sort Order")}</Label>
|
||||
<Input
|
||||
id="sort"
|
||||
type="number"
|
||||
value={values.sort}
|
||||
onChange={(e) =>
|
||||
setValues({ ...values, sort: parseInt(e.target.value) || 0 })
|
||||
}
|
||||
min={0}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen(false)}
|
||||
className="rounded-md border px-4 py-2 text-sm"
|
||||
disabled={submitting || loading}
|
||||
>
|
||||
{t("cancel", "Cancel")}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={submitting || loading}
|
||||
className="flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground disabled:opacity-50"
|
||||
>
|
||||
{submitting && <Loader2 className="h-4 w-4 animate-spin" />}
|
||||
{t("save", "Save")}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
});
|
||||
|
||||
UserGroupForm.displayName = "UserGroupForm";
|
||||
|
||||
export default UserGroupForm;
|
||||
@@ -1,200 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@workspace/ui/components/button";
|
||||
import { Badge } from "@workspace/ui/components/badge";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@workspace/ui/components/card";
|
||||
import { ConfirmButton } from "@workspace/ui/composed/confirm-button";
|
||||
import {
|
||||
ProTable,
|
||||
type ProTableActions,
|
||||
} from "@workspace/ui/composed/pro-table/pro-table";
|
||||
import {
|
||||
createUserGroup,
|
||||
deleteUserGroup,
|
||||
getUserGroupList,
|
||||
getNodeGroupList,
|
||||
updateUserGroup,
|
||||
} from "@workspace/ui/services/admin/group";
|
||||
import { useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import UserGroupForm from "./user-group-form";
|
||||
|
||||
export default function UserGroups() {
|
||||
const { t } = useTranslation("group");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const ref = useRef<ProTableActions>(null);
|
||||
|
||||
const { data: nodeGroupsData } = useQuery({
|
||||
queryKey: ["nodeGroups"],
|
||||
queryFn: async () => {
|
||||
const { data } = await getNodeGroupList({ page: 1, size: 1000 });
|
||||
return data.data?.list || [];
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("userGroups", "User Groups")}</CardTitle>
|
||||
<CardDescription>
|
||||
{t("userGroupsDescription", "Manage user groups for node access control")}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ProTable<API.UserGroup, API.GetUserGroupListRequest>
|
||||
action={ref}
|
||||
request={async (params) => {
|
||||
const { data } = await getUserGroupList({
|
||||
page: params.page || 1,
|
||||
size: params.size || 10,
|
||||
});
|
||||
return {
|
||||
list: data.data?.list || [],
|
||||
total: data.data?.total || 0,
|
||||
};
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
id: "id",
|
||||
accessorKey: "id",
|
||||
header: t("id", "ID"),
|
||||
cell: ({ row }: { row: any }) => <span className="text-muted-foreground">#{row.getValue("id")}</span>,
|
||||
},
|
||||
{
|
||||
id: "name",
|
||||
accessorKey: "name",
|
||||
header: t("name", "Name"),
|
||||
},
|
||||
{
|
||||
id: "for_calculation",
|
||||
accessorKey: "for_calculation",
|
||||
header: t("forCalculation", "For Calculation"),
|
||||
cell: ({ row }: { row: any }) => {
|
||||
const forCalculation = row.getValue("for_calculation");
|
||||
return forCalculation ? (
|
||||
<Badge variant="default">{t("yes", "Yes")}</Badge>
|
||||
) : (
|
||||
<Badge variant="secondary">{t("no", "No")}</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "description",
|
||||
accessorKey: "description",
|
||||
header: t("description", "Description"),
|
||||
cell: ({ row }: { row: any }) => row.getValue("description") || "--",
|
||||
},
|
||||
{
|
||||
id: "node_group_id",
|
||||
accessorKey: "node_group_id",
|
||||
header: t("nodeGroup", "Node Group"),
|
||||
cell: ({ row }: { row: any }) => {
|
||||
const nodeGroupId = row.getValue("node_group_id");
|
||||
const group = nodeGroupsData?.find((g) => g.id === nodeGroupId);
|
||||
return group?.name || "--";
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "sort",
|
||||
accessorKey: "sort",
|
||||
header: t("sort", "Sort"),
|
||||
},
|
||||
]}
|
||||
actions={{
|
||||
render: (row: any) => [
|
||||
<UserGroupForm
|
||||
key={`edit-${row.id}`}
|
||||
initialValues={row}
|
||||
loading={loading}
|
||||
nodeGroups={nodeGroupsData || []}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await updateUserGroup({
|
||||
id: row.id,
|
||||
...values,
|
||||
} as unknown as API.UpdateUserGroupRequest);
|
||||
toast.success(t("updated", "Updated successfully"));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch {
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
title={t("editUserGroup", "Edit User Group")}
|
||||
trigger={
|
||||
<Button variant="outline" size="sm">
|
||||
{t("edit", "Edit")}
|
||||
</Button>
|
||||
}
|
||||
/>,
|
||||
<ConfirmButton
|
||||
key="delete"
|
||||
cancelText={t("cancel", "Cancel")}
|
||||
confirmText={t("confirm", "Confirm")}
|
||||
description={t(
|
||||
"deleteUserGroupConfirm",
|
||||
"This will delete the user group. Users in this group will be reassigned to the default group."
|
||||
)}
|
||||
onConfirm={async () => {
|
||||
await deleteUserGroup({ id: row.id });
|
||||
toast.success(t("deleted", "Deleted successfully"));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
}}
|
||||
title={t("confirmDelete", "Confirm Delete")}
|
||||
trigger={
|
||||
<Button variant="destructive" size="sm">
|
||||
{t("delete", "Delete")}
|
||||
</Button>
|
||||
}
|
||||
/>,
|
||||
],
|
||||
}}
|
||||
header={{
|
||||
title: t("userGroups", "User Groups"),
|
||||
toolbar: (
|
||||
<UserGroupForm
|
||||
key="create"
|
||||
initialValues={undefined}
|
||||
loading={loading}
|
||||
nodeGroups={nodeGroupsData || []}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await createUserGroup(values as API.CreateUserGroupRequest);
|
||||
toast.success(t("created", "Created successfully"));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch {
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
title={t("createUserGroup", "Create User Group")}
|
||||
trigger={
|
||||
<Button>
|
||||
{t("create", "Create")}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user