TTMT.ManageWebGUI/src/components/command-form.tsx
2025-09-24 16:13:57 +07:00

91 lines
2.5 KiB
TypeScript

"use client";
import { useState } from "react";
import { useForm } from "@tanstack/react-form";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Loader2, Terminal, AlertTriangle, CheckCircle } from "lucide-react";
interface ShellCommandFormProps {
onExecute: (command: string) => Promise<{ success: boolean; output: string }>;
}
export function ShellCommandForm({ onExecute }: ShellCommandFormProps) {
const [isLoading, setIsLoading] = useState(false);
// init form
const form = useForm({
defaultValues: {
command: "",
},
onSubmit: async ({ value }) => {
setIsLoading(true);
try {
const res = await onExecute(value.command);
if (res.success) {
form.reset();
}
} finally {
setIsLoading(false);
}
},
});
return (
<div className="space-y-6">
{/* Form */}
<form
onSubmit={(e) => {
e.preventDefault();
form.handleSubmit();
}}
className="space-y-5"
>
{/* Field: command */}
<form.Field
name="command"
validators={{
onChange: z
.string()
.min(1, "Nhập command để thực thi")
.max(500, "Command quá dài"),
}}
children={(field) => (
<div className="w-full px-0">
<Textarea
className="w-full h-[25vh]"
placeholder="Nhập lệnh..."
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
disabled={isLoading}
/>
{field.state.meta.errors?.length > 0 && (
<p className="text-sm text-red-500">
{field.state.meta.errors.join(", ")}
</p>
)}
</div>
)}
/>
<Button type="submit" disabled={isLoading}>
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Yêu cầu thiết bị thực thi
</Button>
</form>
</div>
);
}