91 lines
2.5 KiB
TypeScript
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>
|
|
);
|
|
}
|