Preview
Full width desktop view
Code
api_test-3.tsx
1"use client";
2
3import * as React from "react";
4import { cn } from "@/lib/utils";
5import { Button } from "@/components/ui/button";
6import { Input } from "@/components/ui/input";
7import { Label } from "@/components/ui/label";
8import { Card } from "@/components/ui/card";
9import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
10import { Textarea } from "@/components/ui/textarea";
11import { Server, Send, AlertCircle, CheckCircle, Loader2 } from "lucide-react";
12
13interface RconResponse {
14 success: boolean;
15 response?: string;
16 error?: string;
17}
18
19interface RconDashboardProps {
20 defaultAddress?: string;
21 defaultPassword?: string;
22 defaultCommand?: string;
23}
24
25const RconDashboard = React.forwardRef<HTMLDivElement, RconDashboardProps>(
26 (
27 {
28 defaultAddress = "localhost:25575",
29 defaultPassword = "",
30 defaultCommand = "list",
31 },
32 ref
33 ) => {
34 const [address, setAddress] = React.useState(defaultAddress);
35 const [password, setPassword] = React.useState(defaultPassword);
36 const [command, setCommand] = React.useState(defaultCommand);
37 const [response, setResponse] = React.useState<RconResponse | null>(null);
38 const [isLoading, setIsLoading] = React.useState(false);
39
40 const sendRconCommand = async () => {
41 if (!address || !password || !command) {
42 setResponse({
43 success: false,
44 error: "Please fill in all fields",
45 });
46 return;
47 }
48
49 setIsLoading(true);
50 setResponse(null);
51
52 try {
53 // Simulate RCON connection and command execution
54 await new Promise((resolve) => setTimeout(resolve, 1500));
55
56 // Mock response based on command
57 const mockResponses: Record<string, string> = {
58 list: "There are 3 of a max of 20 players online: Steve, Alex, Notch",
59 "time query daytime": "The time is 6000",
60 "weather query": "It is currently clear",
61 difficulty: "The difficulty is Easy",
62 seed: "Seed: [1234567890]",
63 version:
64 "This server is running CraftBukkit version git-Bukkit-1.20.1",
65 help: "Available commands: list, time, weather, difficulty, seed, version, say, give, tp, gamemode",
66 };
67
68 const mockResponse =
69 mockResponses[command.toLowerCase()] ||
70 `Command executed: ${command}`;
71
72 setResponse({
73 success: true,
74 response: mockResponse,
75 });
76 } catch (error) {
77 setResponse({
78 success: false,
79 error:
80 "Failed to connect to RCON server. Please check your connection details.",
81 });
82 } finally {
83 setIsLoading(false);
84 }
85 };
86
87 const handleKeyDown = (e: React.KeyboardEvent) => {
88 if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
89 e.preventDefault();
90 sendRconCommand();
91 }
92 };
93
94 return (
95 <div ref={ref} className="min-h-screen bg-background p-6">
96 <div className="mx-auto max-w-4xl space-y-6">
97 <div className="text-center space-y-2">
98 <div className="flex items-center justify-center gap-2">
99 <Server className="h-8 w-8 text-primary" />
100 <h1 className="text-3xl font-bold text-foreground">
101 RCON Admin Dashboard
102 </h1>
103 </div>
104 <p className="text-muted-foreground">
105 Test and execute RCON commands on your Minecraft server
106 </p>
107 </div>
108
109 <Card className="p-6 space-y-6">
110 <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
111 <div className="space-y-2">
112 <Label htmlFor="rcon-address" className="text-sm font-medium">
113 RCON Address
114 </Label>
115 <Input
116 id="rcon-address"
117 type="text"
118 placeholder="localhost:25575"
119 value={address}
120 onChange={(e) => setAddress(e.target.value)}
121 onKeyDown={handleKeyDown}
122 disabled={isLoading}
123 />
124 <p className="text-xs text-muted-foreground">
125 Format: hostname:port (e.g., localhost:25575)
126 </p>
127 </div>
128
129 <div className="space-y-2">
130 <Label htmlFor="rcon-password" className="text-sm font-medium">
131 RCON Password
132 </Label>
133 <Input
134 id="rcon-password"
135 type="password"
136 placeholder="Enter RCON password"
137 value={password}
138 onChange={(e) => setPassword(e.target.value)}
139 onKeyDown={handleKeyDown}
140 disabled={isLoading}
141 />
142 <p className="text-xs text-muted-foreground">
143 The password configured in server.properties
144 </p>
145 </div>
146 </div>
147
148 <div className="space-y-2">
149 <Label htmlFor="rcon-command" className="text-sm font-medium">
150 Command
151 </Label>
152 <div className="flex gap-2">
153 <Input
154 id="rcon-command"
155 type="text"
156 placeholder="list"
157 value={command}
158 onChange={(e) => setCommand(e.target.value)}
159 onKeyDown={handleKeyDown}
160 disabled={isLoading}
161 className="flex-1"
162 />
163 <Button
164 onClick={sendRconCommand}
165 disabled={isLoading || !address || !password || !command}
166 className="px-6"
167 >
168 {isLoading ? (
169 <Loader2 className="h-4 w-4 animate-spin" />
170 ) : (
171 <Send className="h-4 w-4" />
172 )}
173 {isLoading ? "Sending..." : "Send"}
174 </Button>
175 </div>
176 <p className="text-xs text-muted-foreground">
177 Press Ctrl+Enter to send command quickly
178 </p>
179 </div>
180
181 <div className="grid grid-cols-2 md:grid-cols-4 gap-2">
182 {[
183 "list",
184 "time query daytime",
185 "weather query",
186 "difficulty",
187 ].map((cmd) => (
188 <Button
189 key={cmd}
190 variant="outline"
191 size="sm"
192 onClick={() => setCommand(cmd)}
193 disabled={isLoading}
194 className="text-xs"
195 >
196 {cmd}
197 </Button>
198 ))}
199 </div>
200 </Card>
201
202 {response && (
203 <Alert
204 variant={response.success ? "default" : "destructive"}
205 // @ts-ignore
206 icon={
207 response.success ? (
208 <CheckCircle className="h-4 w-4" />
209 ) : (
210 <AlertCircle className="h-4 w-4" />
211 )
212 }
213 layout="complex"
214 >
215 <AlertTitle>
216 {response.success
217 ? "Command Executed Successfully"
218 : "Command Failed"}
219 </AlertTitle>
220 <AlertDescription>
221 <div className="mt-2">
222 {response.success ? (
223 <Textarea
224 value={response.response || ""}
225 readOnly
226 className="min-h-[100px] font-mono text-sm bg-muted/50"
227 />
228 ) : (
229 <p className="text-sm">{response.error}</p>
230 )}
231 </div>
232 </AlertDescription>
233 </Alert>
234 )}
235
236 <Card className="p-4">
237 <h3 className="text-sm font-medium mb-2">Common RCON Commands</h3>
238 <div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-xs text-muted-foreground">
239 <div>
240 <code className="bg-muted px-1 rounded">list</code> - Show
241 online players
242 </div>
243 <div>
244 <code className="bg-muted px-1 rounded">time set day</code> -
245 Set time to day
246 </div>
247 <div>
248 <code className="bg-muted px-1 rounded">weather clear</code> -
249 Clear weather
250 </div>
251 <div>
252 <code className="bg-muted px-1 rounded">
253 say <message>
254 </code>{" "}
255 - Broadcast message
256 </div>
257 <div>
258 <code className="bg-muted px-1 rounded">
259 tp <player> <target>
260 </code>{" "}
261 - Teleport player
262 </div>
263 <div>
264 <code className="bg-muted px-1 rounded">
265 gamemode <mode> <player>
266 </code>{" "}
267 - Change gamemode
268 </div>
269 </div>
270 </Card>
271 </div>
272 </div>
273 );
274 }
275);
276
277RconDashboard.displayName = "RconDashboard";
278
279export default function Component() {
280 return <RconDashboard />;
281}
Dependencies
External Libraries
lucide-reactreact
Shadcn/UI Components
alertbuttoncardinputlabeltextarea
Local Components
/lib/utils