Preview
Full width desktop view
Code
monitoring-6.tsx
1"use client";
2
3import React, { useState, useEffect } from "react";
4import {
5 Card,
6 CardContent,
7 CardDescription,
8 CardHeader,
9 CardTitle,
10} from "@/components/ui/card";
11import { Button } from "@/components/ui/button";
12import { Input } from "@/components/ui/input";
13import { Label } from "@/components/ui/label";
14import {
15 Select,
16 SelectContent,
17 SelectItem,
18 SelectTrigger,
19 SelectValue,
20} from "@/components/ui/select";
21import { Badge } from "@/components/ui/badge";
22import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
23import {
24 Dialog,
25 DialogContent,
26 DialogDescription,
27 DialogHeader,
28 DialogTitle,
29 DialogTrigger,
30} from "@/components/ui/dialog";
31import {
32 Table,
33 TableBody,
34 TableCell,
35 TableHead,
36 TableHeader,
37 TableRow,
38} from "@/components/ui/table";
39import { Progress } from "@/components/ui/progress";
40import { Switch } from "@/components/ui/switch";
41import { Separator } from "@/components/ui/separator";
42import {
43 Server,
44 Plus,
45 Settings,
46 Activity,
47 Cpu,
48 HardDrive,
49 MemoryStick,
50 Globe,
51 Users,
52 Power,
53 PowerOff,
54 Trash2,
55 Edit,
56 Eye,
57 AlertTriangle,
58 CheckCircle,
59 Clock,
60 Database,
61} from "lucide-react";
62
63interface VPSParent {
64 id: string;
65 name: string;
66 region: string;
67 cpu: number;
68 ram: number;
69 storage: number;
70 status: "online" | "offline" | "maintenance";
71 usedCpu: number;
72 usedRam: number;
73 usedStorage: number;
74 sharedVpsCount: number;
75 dedicatedVpsCount: number;
76 createdAt: string;
77}
78
79interface SharedVPS {
80 id: string;
81 name: string;
82 parentId: string;
83 parentName: string;
84 cpu: number;
85 ram: number;
86 storage: number;
87 status: "running" | "stopped" | "suspended";
88 customerEmail: string;
89 domain?: string;
90 createdAt: string;
91}
92
93interface DedicatedVPS {
94 id: string;
95 name: string;
96 region: string;
97 cpu: number;
98 ram: number;
99 storage: number;
100 status: "running" | "stopped" | "suspended";
101 customerEmail: string;
102 domain?: string;
103 createdAt: string;
104}
105
106const VPSAdminDashboard = () => {
107 const [vpsParents, setVpsParents] = useState<VPSParent[]>([
108 {
109 id: "1",
110 name: "US-East-Parent-01",
111 region: "us-east-1",
112 cpu: 32,
113 ram: 128,
114 storage: 2000,
115 status: "online",
116 usedCpu: 18,
117 usedRam: 76,
118 usedStorage: 1200,
119 sharedVpsCount: 8,
120 dedicatedVpsCount: 2,
121 createdAt: "2024-01-15",
122 },
123 {
124 id: "2",
125 name: "EU-West-Parent-01",
126 region: "eu-west-1",
127 cpu: 24,
128 ram: 96,
129 storage: 1500,
130 status: "online",
131 usedCpu: 12,
132 usedRam: 48,
133 usedStorage: 800,
134 sharedVpsCount: 6,
135 dedicatedVpsCount: 1,
136 createdAt: "2024-01-20",
137 },
138 ]);
139
140 const [sharedVps, setSharedVps] = useState<SharedVPS[]>([
141 {
142 id: "s1",
143 name: "Shared-Store-01",
144 parentId: "1",
145 parentName: "US-East-Parent-01",
146 cpu: 2,
147 ram: 8,
148 storage: 100,
149 status: "running",
150 customerEmail: "customer1@example.com",
151 domain: "store1.example.com",
152 createdAt: "2024-02-01",
153 },
154 {
155 id: "s2",
156 name: "Shared-Store-02",
157 parentId: "1",
158 parentName: "US-East-Parent-01",
159 cpu: 1,
160 ram: 4,
161 storage: 50,
162 status: "running",
163 customerEmail: "customer2@example.com",
164 domain: "store2.example.com",
165 createdAt: "2024-02-03",
166 },
167 ]);
168
169 const [dedicatedVps, setDedicatedVps] = useState<DedicatedVPS[]>([
170 {
171 id: "d1",
172 name: "Dedicated-Enterprise-01",
173 region: "us-east-1",
174 cpu: 8,
175 ram: 32,
176 storage: 500,
177 status: "running",
178 customerEmail: "enterprise@example.com",
179 domain: "enterprise.example.com",
180 createdAt: "2024-01-25",
181 },
182 ]);
183
184 const [activeTab, setActiveTab] = useState("overview");
185 const [isCreateParentOpen, setIsCreateParentOpen] = useState(false);
186 const [isCreateSharedOpen, setIsCreateSharedOpen] = useState(false);
187 const [isCreateDedicatedOpen, setIsCreateDedicatedOpen] = useState(false);
188
189 const [newParent, setNewParent] = useState({
190 name: "",
191 region: "",
192 cpu: 0,
193 ram: 0,
194 storage: 0,
195 });
196
197 const [newShared, setNewShared] = useState({
198 name: "",
199 parentId: "",
200 cpu: 0,
201 ram: 0,
202 storage: 0,
203 customerEmail: "",
204 domain: "",
205 });
206
207 const [newDedicated, setNewDedicated] = useState({
208 name: "",
209 region: "",
210 cpu: 0,
211 ram: 0,
212 storage: 0,
213 customerEmail: "",
214 domain: "",
215 });
216
217 const getStatusColor = (status: string) => {
218 switch (status) {
219 case "online":
220 case "running":
221 return "bg-green-500";
222 case "offline":
223 case "stopped":
224 return "bg-red-500";
225 case "maintenance":
226 case "suspended":
227 return "bg-yellow-500";
228 default:
229 return "bg-gray-500";
230 }
231 };
232
233 const getStatusIcon = (status: string) => {
234 switch (status) {
235 case "online":
236 case "running":
237 return <CheckCircle className="h-4 w-4" />;
238 case "offline":
239 case "stopped":
240 return <PowerOff className="h-4 w-4" />;
241 case "maintenance":
242 case "suspended":
243 return <AlertTriangle className="h-4 w-4" />;
244 default:
245 return <Clock className="h-4 w-4" />;
246 }
247 };
248
249 const createVPSParent = () => {
250 const parent: VPSParent = {
251 id: Date.now().toString(),
252 ...newParent,
253 status: "online",
254 usedCpu: 0,
255 usedRam: 0,
256 usedStorage: 0,
257 sharedVpsCount: 0,
258 dedicatedVpsCount: 0,
259 createdAt: new Date().toISOString().split("T")[0],
260 };
261 setVpsParents([...vpsParents, parent]);
262 setNewParent({ name: "", region: "", cpu: 0, ram: 0, storage: 0 });
263 setIsCreateParentOpen(false);
264 };
265
266 const createSharedVPS = () => {
267 const shared: SharedVPS = {
268 id: Date.now().toString(),
269 ...newShared,
270 parentName:
271 vpsParents.find((p) => p.id === newShared.parentId)?.name || "",
272 status: "running",
273 createdAt: new Date().toISOString().split("T")[0],
274 };
275 setSharedVps([...sharedVps, shared]);
276 setNewShared({
277 name: "",
278 parentId: "",
279 cpu: 0,
280 ram: 0,
281 storage: 0,
282 customerEmail: "",
283 domain: "",
284 });
285 setIsCreateSharedOpen(false);
286 };
287
288 const createDedicatedVPS = () => {
289 const dedicated: DedicatedVPS = {
290 id: Date.now().toString(),
291 ...newDedicated,
292 status: "running",
293 createdAt: new Date().toISOString().split("T")[0],
294 };
295 setDedicatedVps([...dedicatedVps, dedicated]);
296 setNewDedicated({
297 name: "",
298 region: "",
299 cpu: 0,
300 ram: 0,
301 storage: 0,
302 customerEmail: "",
303 domain: "",
304 });
305 setIsCreateDedicatedOpen(false);
306 };
307
308 const totalVpsParents = vpsParents.length;
309 const totalSharedVps = sharedVps.length;
310 const totalDedicatedVps = dedicatedVps.length;
311 const totalActiveInstances =
312 vpsParents.filter((p) => p.status === "online").length +
313 sharedVps.filter((s) => s.status === "running").length +
314 dedicatedVps.filter((d) => d.status === "running").length;
315
316 return (
317 <div className="min-h-screen bg-background p-6">
318 <div className="max-w-7xl mx-auto space-y-6">
319 {/* Header */}
320 <div className="flex items-center justify-between">
321 <div>
322 <h1 className="text-3xl font-bold text-foreground">
323 VPS Management Dashboard
324 </h1>
325 <p className="text-muted-foreground">
326 Manage and monitor your VPS infrastructure
327 </p>
328 </div>
329 <div className="flex items-center space-x-2">
330 <Badge variant="outline" className="text-green-600">
331 <Activity className="h-3 w-3 mr-1" />
332 {totalActiveInstances} Active
333 </Badge>
334 </div>
335 </div>
336
337 {/* Overview Cards */}
338 <div className="grid grid-cols-1 md:grid-cols-4 gap-6">
339 <Card>
340 <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
341 <CardTitle className="text-sm font-medium">VPS Parents</CardTitle>
342 <Server className="h-4 w-4 text-muted-foreground" />
343 </CardHeader>
344 <CardContent>
345 <div className="text-2xl font-bold">{totalVpsParents}</div>
346 <p className="text-xs text-muted-foreground">Physical servers</p>
347 </CardContent>
348 </Card>
349
350 <Card>
351 <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
352 <CardTitle className="text-sm font-medium">Shared VPS</CardTitle>
353 <Users className="h-4 w-4 text-muted-foreground" />
354 </CardHeader>
355 <CardContent>
356 <div className="text-2xl font-bold">{totalSharedVps}</div>
357 <p className="text-xs text-muted-foreground">Shared instances</p>
358 </CardContent>
359 </Card>
360
361 <Card>
362 <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
363 <CardTitle className="text-sm font-medium">
364 Dedicated VPS
365 </CardTitle>
366 <Database className="h-4 w-4 text-muted-foreground" />
367 </CardHeader>
368 <CardContent>
369 <div className="text-2xl font-bold">{totalDedicatedVps}</div>
370 <p className="text-xs text-muted-foreground">
371 Dedicated instances
372 </p>
373 </CardContent>
374 </Card>
375
376 <Card>
377 <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
378 <CardTitle className="text-sm font-medium">
379 Total Active
380 </CardTitle>
381 <Power className="h-4 w-4 text-muted-foreground" />
382 </CardHeader>
383 <CardContent>
384 <div className="text-2xl font-bold">{totalActiveInstances}</div>
385 <p className="text-xs text-muted-foreground">Running instances</p>
386 </CardContent>
387 </Card>
388 </div>
389
390 {/* Main Content */}
391 <Tabs
392 value={activeTab}
393 onValueChange={setActiveTab}
394 className="space-y-6"
395 >
396 <TabsList className="grid w-full grid-cols-4">
397 <TabsTrigger value="overview">Overview</TabsTrigger>
398 <TabsTrigger value="parents">VPS Parents</TabsTrigger>
399 <TabsTrigger value="shared">Shared VPS</TabsTrigger>
400 <TabsTrigger value="dedicated">Dedicated VPS</TabsTrigger>
401 </TabsList>
402
403 <TabsContent value="overview" className="space-y-6">
404 <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
405 {/* VPS Parents Overview */}
406 <Card>
407 <CardHeader>
408 <CardTitle className="flex items-center">
409 <Server className="h-5 w-5 mr-2" />
410 VPS Parents Status
411 </CardTitle>
412 </CardHeader>
413 <CardContent className="space-y-4">
414 {vpsParents.map((parent) => (
415 <div
416 key={parent.id}
417 className="flex items-center justify-between p-3 border rounded-lg"
418 >
419 <div className="flex items-center space-x-3">
420 <div
421 className={`w-3 h-3 rounded-full ${getStatusColor(
422 parent.status
423 )}`}
424 />
425 <div>
426 <p className="font-medium">{parent.name}</p>
427 <p className="text-sm text-muted-foreground">
428 {parent.region}
429 </p>
430 </div>
431 </div>
432 <div className="text-right">
433 <p className="text-sm font-medium">
434 {parent.sharedVpsCount + parent.dedicatedVpsCount}{" "}
435 instances
436 </p>
437 <p className="text-xs text-muted-foreground">
438 CPU: {Math.round((parent.usedCpu / parent.cpu) * 100)}
439 %
440 </p>
441 </div>
442 </div>
443 ))}
444 </CardContent>
445 </Card>
446
447 {/* Recent Activity */}
448 <Card>
449 <CardHeader>
450 <CardTitle className="flex items-center">
451 <Activity className="h-5 w-5 mr-2" />
452 Recent Activity
453 </CardTitle>
454 </CardHeader>
455 <CardContent className="space-y-4">
456 <div className="space-y-3">
457 <div className="flex items-center space-x-3 p-3 border rounded-lg">
458 <CheckCircle className="h-4 w-4 text-green-500" />
459 <div>
460 <p className="text-sm font-medium">
461 New shared VPS created
462 </p>
463 <p className="text-xs text-muted-foreground">
464 2 minutes ago
465 </p>
466 </div>
467 </div>
468 <div className="flex items-center space-x-3 p-3 border rounded-lg">
469 <Power className="h-4 w-4 text-blue-500" />
470 <div>
471 <p className="text-sm font-medium">
472 VPS Parent restarted
473 </p>
474 <p className="text-xs text-muted-foreground">
475 15 minutes ago
476 </p>
477 </div>
478 </div>
479 <div className="flex items-center space-x-3 p-3 border rounded-lg">
480 <Users className="h-4 w-4 text-purple-500" />
481 <div>
482 <p className="text-sm font-medium">
483 Customer deployed webstore
484 </p>
485 <p className="text-xs text-muted-foreground">
486 1 hour ago
487 </p>
488 </div>
489 </div>
490 </div>
491 </CardContent>
492 </Card>
493 </div>
494 </TabsContent>
495
496 <TabsContent value="parents" className="space-y-6">
497 <div className="flex items-center justify-between">
498 <h2 className="text-2xl font-bold">VPS Parents</h2>
499 <Dialog
500 open={isCreateParentOpen}
501 onOpenChange={setIsCreateParentOpen}
502 >
503 <DialogTrigger asChild>
504 <Button>
505 <Plus className="h-4 w-4 mr-2" />
506 Add VPS Parent
507 </Button>
508 </DialogTrigger>
509 <DialogContent>
510 <DialogHeader>
511 <DialogTitle>Create New VPS Parent</DialogTitle>
512 <DialogDescription>
513 Add a new physical server to host VPS instances
514 </DialogDescription>
515 </DialogHeader>
516 <div className="space-y-4">
517 <div>
518 <Label htmlFor="parent-name">Server Name</Label>
519 <Input
520 id="parent-name"
521 value={newParent.name}
522 onChange={(e) =>
523 setNewParent({ ...newParent, name: e.target.value })
524 }
525 placeholder="US-East-Parent-02"
526 />
527 </div>
528 <div>
529 <Label htmlFor="parent-region">Region</Label>
530 <Select
531 value={newParent.region}
532 onValueChange={(value) =>
533 setNewParent({ ...newParent, region: value })
534 }
535 >
536 <SelectTrigger>
537 <SelectValue placeholder="Select region" />
538 </SelectTrigger>
539 <SelectContent>
540 <SelectItem value="us-east-1">US East 1</SelectItem>
541 <SelectItem value="us-west-1">US West 1</SelectItem>
542 <SelectItem value="eu-west-1">EU West 1</SelectItem>
543 <SelectItem value="ap-southeast-1">
544 Asia Pacific Southeast 1
545 </SelectItem>
546 </SelectContent>
547 </Select>
548 </div>
549 <div className="grid grid-cols-3 gap-4">
550 <div>
551 <Label htmlFor="parent-cpu">CPU Cores</Label>
552 <Input
553 id="parent-cpu"
554 type="number"
555 value={newParent.cpu}
556 onChange={(e) =>
557 setNewParent({
558 ...newParent,
559 cpu: parseInt(e.target.value) || 0,
560 })
561 }
562 placeholder="32"
563 />
564 </div>
565 <div>
566 <Label htmlFor="parent-ram">RAM (GB)</Label>
567 <Input
568 id="parent-ram"
569 type="number"
570 value={newParent.ram}
571 onChange={(e) =>
572 setNewParent({
573 ...newParent,
574 ram: parseInt(e.target.value) || 0,
575 })
576 }
577 placeholder="128"
578 />
579 </div>
580 <div>
581 <Label htmlFor="parent-storage">Storage (GB)</Label>
582 <Input
583 id="parent-storage"
584 type="number"
585 value={newParent.storage}
586 onChange={(e) =>
587 setNewParent({
588 ...newParent,
589 storage: parseInt(e.target.value) || 0,
590 })
591 }
592 placeholder="2000"
593 />
594 </div>
595 </div>
596 <Button onClick={createVPSParent} className="w-full">
597 Create VPS Parent
598 </Button>
599 </div>
600 </DialogContent>
601 </Dialog>
602 </div>
603
604 <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
605 {vpsParents.map((parent) => (
606 <Card key={parent.id}>
607 <CardHeader>
608 <div className="flex items-center justify-between">
609 <CardTitle className="flex items-center">
610 {getStatusIcon(parent.status)}
611 <span className="ml-2">{parent.name}</span>
612 </CardTitle>
613 <Badge
614 variant={
615 parent.status === "online" ? "default" : "secondary"
616 }
617 >
618 {parent.status}
619 </Badge>
620 </div>
621 <CardDescription>
622 <Globe className="h-4 w-4 inline mr-1" />
623 {parent.region}
624 </CardDescription>
625 </CardHeader>
626 <CardContent className="space-y-4">
627 <div className="grid grid-cols-3 gap-4 text-center">
628 <div className="space-y-1">
629 <Cpu className="h-4 w-4 mx-auto text-muted-foreground" />
630 <p className="text-sm font-medium">
631 {parent.cpu} Cores
632 </p>
633 <p className="text-xs text-muted-foreground">
634 {parent.usedCpu} used
635 </p>
636 </div>
637 <div className="space-y-1">
638 <MemoryStick className="h-4 w-4 mx-auto text-muted-foreground" />
639 <p className="text-sm font-medium">{parent.ram} GB</p>
640 <p className="text-xs text-muted-foreground">
641 {parent.usedRam} GB used
642 </p>
643 </div>
644 <div className="space-y-1">
645 <HardDrive className="h-4 w-4 mx-auto text-muted-foreground" />
646 <p className="text-sm font-medium">
647 {parent.storage} GB
648 </p>
649 <p className="text-xs text-muted-foreground">
650 {parent.usedStorage} GB used
651 </p>
652 </div>
653 </div>
654
655 <Separator />
656
657 <div className="space-y-3">
658 <div>
659 <div className="flex justify-between text-sm mb-1">
660 <span>CPU Usage</span>
661 <span>
662 {Math.round((parent.usedCpu / parent.cpu) * 100)}%
663 </span>
664 </div>
665 <Progress value={(parent.usedCpu / parent.cpu) * 100} />
666 </div>
667 <div>
668 <div className="flex justify-between text-sm mb-1">
669 <span>RAM Usage</span>
670 <span>
671 {Math.round((parent.usedRam / parent.ram) * 100)}%
672 </span>
673 </div>
674 <Progress value={(parent.usedRam / parent.ram) * 100} />
675 </div>
676 <div>
677 <div className="flex justify-between text-sm mb-1">
678 <span>Storage Usage</span>
679 <span>
680 {Math.round(
681 (parent.usedStorage / parent.storage) * 100
682 )}
683 %
684 </span>
685 </div>
686 <Progress
687 value={(parent.usedStorage / parent.storage) * 100}
688 />
689 </div>
690 </div>
691
692 <Separator />
693
694 <div className="flex justify-between items-center">
695 <div className="text-sm">
696 <p>
697 <strong>{parent.sharedVpsCount}</strong> Shared VPS
698 </p>
699 <p>
700 <strong>{parent.dedicatedVpsCount}</strong> Dedicated
701 VPS
702 </p>
703 </div>
704 <div className="flex space-x-2">
705 <Button variant="outline" size="sm">
706 <Settings className="h-4 w-4" />
707 </Button>
708 <Button variant="outline" size="sm">
709 <Eye className="h-4 w-4" />
710 </Button>
711 </div>
712 </div>
713 </CardContent>
714 </Card>
715 ))}
716 </div>
717 </TabsContent>
718
719 <TabsContent value="shared" className="space-y-6">
720 <div className="flex items-center justify-between">
721 <h2 className="text-2xl font-bold">Shared VPS Instances</h2>
722 <Dialog
723 open={isCreateSharedOpen}
724 onOpenChange={setIsCreateSharedOpen}
725 >
726 <DialogTrigger asChild>
727 <Button>
728 <Plus className="h-4 w-4 mr-2" />
729 Create Shared VPS
730 </Button>
731 </DialogTrigger>
732 <DialogContent>
733 <DialogHeader>
734 <DialogTitle>Create New Shared VPS</DialogTitle>
735 <DialogDescription>
736 Create a shared VPS instance under a parent server
737 </DialogDescription>
738 </DialogHeader>
739 <div className="space-y-4">
740 <div>
741 <Label htmlFor="shared-name">Instance Name</Label>
742 <Input
743 id="shared-name"
744 value={newShared.name}
745 onChange={(e) =>
746 setNewShared({ ...newShared, name: e.target.value })
747 }
748 placeholder="Shared-Store-03"
749 />
750 </div>
751 <div>
752 <Label htmlFor="shared-parent">Parent Server</Label>
753 <Select
754 value={newShared.parentId}
755 onValueChange={(value) =>
756 setNewShared({ ...newShared, parentId: value })
757 }
758 >
759 <SelectTrigger>
760 <SelectValue placeholder="Select parent server" />
761 </SelectTrigger>
762 <SelectContent>
763 {vpsParents.map((parent) => (
764 <SelectItem key={parent.id} value={parent.id}>
765 {parent.name} ({parent.region})
766 </SelectItem>
767 ))}
768 </SelectContent>
769 </Select>
770 </div>
771 <div className="grid grid-cols-3 gap-4">
772 <div>
773 <Label htmlFor="shared-cpu">CPU Cores</Label>
774 <Input
775 id="shared-cpu"
776 type="number"
777 value={newShared.cpu}
778 onChange={(e) =>
779 setNewShared({
780 ...newShared,
781 cpu: parseInt(e.target.value) || 0,
782 })
783 }
784 placeholder="2"
785 />
786 </div>
787 <div>
788 <Label htmlFor="shared-ram">RAM (GB)</Label>
789 <Input
790 id="shared-ram"
791 type="number"
792 value={newShared.ram}
793 onChange={(e) =>
794 setNewShared({
795 ...newShared,
796 ram: parseInt(e.target.value) || 0,
797 })
798 }
799 placeholder="8"
800 />
801 </div>
802 <div>
803 <Label htmlFor="shared-storage">Storage (GB)</Label>
804 <Input
805 id="shared-storage"
806 type="number"
807 value={newShared.storage}
808 onChange={(e) =>
809 setNewShared({
810 ...newShared,
811 storage: parseInt(e.target.value) || 0,
812 })
813 }
814 placeholder="100"
815 />
816 </div>
817 </div>
818 <div>
819 <Label htmlFor="shared-customer">Customer Email</Label>
820 <Input
821 id="shared-customer"
822 type="email"
823 value={newShared.customerEmail}
824 onChange={(e) =>
825 setNewShared({
826 ...newShared,
827 customerEmail: e.target.value,
828 })
829 }
830 placeholder="customer@example.com"
831 />
832 </div>
833 <div>
834 <Label htmlFor="shared-domain">Domain (Optional)</Label>
835 <Input
836 id="shared-domain"
837 value={newShared.domain}
838 onChange={(e) =>
839 setNewShared({ ...newShared, domain: e.target.value })
840 }
841 placeholder="store.example.com"
842 />
843 </div>
844 <Button onClick={createSharedVPS} className="w-full">
845 Create Shared VPS
846 </Button>
847 </div>
848 </DialogContent>
849 </Dialog>
850 </div>
851
852 <Card>
853 <CardContent className="p-0">
854 <Table>
855 <TableHeader>
856 <TableRow>
857 <TableHead>Name</TableHead>
858 <TableHead>Parent Server</TableHead>
859 <TableHead>Resources</TableHead>
860 <TableHead>Customer</TableHead>
861 <TableHead>Domain</TableHead>
862 <TableHead>Status</TableHead>
863 <TableHead>Actions</TableHead>
864 </TableRow>
865 </TableHeader>
866 <TableBody>
867 {sharedVps.map((vps) => (
868 <TableRow key={vps.id}>
869 <TableCell className="font-medium">
870 {vps.name}
871 </TableCell>
872 <TableCell>{vps.parentName}</TableCell>
873 <TableCell>
874 <div className="text-sm">
875 <div>
876 {vps.cpu} CPU • {vps.ram} GB RAM
877 </div>
878 <div className="text-muted-foreground">
879 {vps.storage} GB Storage
880 </div>
881 </div>
882 </TableCell>
883 <TableCell>{vps.customerEmail}</TableCell>
884 <TableCell>{vps.domain || "-"}</TableCell>
885 <TableCell>
886 <Badge
887 variant={
888 vps.status === "running" ? "default" : "secondary"
889 }
890 >
891 {vps.status}
892 </Badge>
893 </TableCell>
894 <TableCell>
895 <div className="flex space-x-2">
896 <Button variant="outline" size="sm">
897 <Edit className="h-4 w-4" />
898 </Button>
899 <Button variant="outline" size="sm">
900 <Power className="h-4 w-4" />
901 </Button>
902 <Button variant="outline" size="sm">
903 <Trash2 className="h-4 w-4" />
904 </Button>
905 </div>
906 </TableCell>
907 </TableRow>
908 ))}
909 </TableBody>
910 </Table>
911 </CardContent>
912 </Card>
913 </TabsContent>
914
915 <TabsContent value="dedicated" className="space-y-6">
916 <div className="flex items-center justify-between">
917 <h2 className="text-2xl font-bold">Dedicated VPS Instances</h2>
918 <Dialog
919 open={isCreateDedicatedOpen}
920 onOpenChange={setIsCreateDedicatedOpen}
921 >
922 <DialogTrigger asChild>
923 <Button>
924 <Plus className="h-4 w-4 mr-2" />
925 Create Dedicated VPS
926 </Button>
927 </DialogTrigger>
928 <DialogContent>
929 <DialogHeader>
930 <DialogTitle>Create New Dedicated VPS</DialogTitle>
931 <DialogDescription>
932 Create a standalone dedicated VPS instance
933 </DialogDescription>
934 </DialogHeader>
935 <div className="space-y-4">
936 <div>
937 <Label htmlFor="dedicated-name">Instance Name</Label>
938 <Input
939 id="dedicated-name"
940 value={newDedicated.name}
941 onChange={(e) =>
942 setNewDedicated({
943 ...newDedicated,
944 name: e.target.value,
945 })
946 }
947 placeholder="Dedicated-Enterprise-02"
948 />
949 </div>
950 <div>
951 <Label htmlFor="dedicated-region">Region</Label>
952 <Select
953 value={newDedicated.region}
954 onValueChange={(value) =>
955 setNewDedicated({ ...newDedicated, region: value })
956 }
957 >
958 <SelectTrigger>
959 <SelectValue placeholder="Select region" />
960 </SelectTrigger>
961 <SelectContent>
962 <SelectItem value="us-east-1">US East 1</SelectItem>
963 <SelectItem value="us-west-1">US West 1</SelectItem>
964 <SelectItem value="eu-west-1">EU West 1</SelectItem>
965 <SelectItem value="ap-southeast-1">
966 Asia Pacific Southeast 1
967 </SelectItem>
968 </SelectContent>
969 </Select>
970 </div>
971 <div className="grid grid-cols-3 gap-4">
972 <div>
973 <Label htmlFor="dedicated-cpu">CPU Cores</Label>
974 <Input
975 id="dedicated-cpu"
976 type="number"
977 value={newDedicated.cpu}
978 onChange={(e) =>
979 setNewDedicated({
980 ...newDedicated,
981 cpu: parseInt(e.target.value) || 0,
982 })
983 }
984 placeholder="8"
985 />
986 </div>
987 <div>
988 <Label htmlFor="dedicated-ram">RAM (GB)</Label>
989 <Input
990 id="dedicated-ram"
991 type="number"
992 value={newDedicated.ram}
993 onChange={(e) =>
994 setNewDedicated({
995 ...newDedicated,
996 ram: parseInt(e.target.value) || 0,
997 })
998 }
999 placeholder="32"
1000 />
1001 </div>
1002 <div>
1003 <Label htmlFor="dedicated-storage">Storage (GB)</Label>
1004 <Input
1005 id="dedicated-storage"
1006 type="number"
1007 value={newDedicated.storage}
1008 onChange={(e) =>
1009 setNewDedicated({
1010 ...newDedicated,
1011 storage: parseInt(e.target.value) || 0,
1012 })
1013 }
1014 placeholder="500"
1015 />
1016 </div>
1017 </div>
1018 <div>
1019 <Label htmlFor="dedicated-customer">Customer Email</Label>
1020 <Input
1021 id="dedicated-customer"
1022 type="email"
1023 value={newDedicated.customerEmail}
1024 onChange={(e) =>
1025 setNewDedicated({
1026 ...newDedicated,
1027 customerEmail: e.target.value,
1028 })
1029 }
1030 placeholder="customer@example.com"
1031 />
1032 </div>
1033 <div>
1034 <Label htmlFor="dedicated-domain">
1035 Domain (Optional)
1036 </Label>
1037 <Input
1038 id="dedicated-domain"
1039 value={newDedicated.domain}
1040 onChange={(e) =>
1041 setNewDedicated({
1042 ...newDedicated,
1043 domain: e.target.value,
1044 })
1045 }
1046 placeholder="enterprise.example.com"
1047 />
1048 </div>
1049 <Button onClick={createDedicatedVPS} className="w-full">
1050 Create Dedicated VPS
1051 </Button>
1052 </div>
1053 </DialogContent>
1054 </Dialog>
1055 </div>
1056
1057 <Card>
1058 <CardContent className="p-0">
1059 <Table>
1060 <TableHeader>
1061 <TableRow>
1062 <TableHead>Name</TableHead>
1063 <TableHead>Region</TableHead>
1064 <TableHead>Resources</TableHead>
1065 <TableHead>Customer</TableHead>
1066 <TableHead>Domain</TableHead>
1067 <TableHead>Status</TableHead>
1068 <TableHead>Actions</TableHead>
1069 </TableRow>
1070 </TableHeader>
1071 <TableBody>
1072 {dedicatedVps.map((vps) => (
1073 <TableRow key={vps.id}>
1074 <TableCell className="font-medium">
1075 {vps.name}
1076 </TableCell>
1077 <TableCell>{vps.region}</TableCell>
1078 <TableCell>
1079 <div className="text-sm">
1080 <div>
1081 {vps.cpu} CPU • {vps.ram} GB RAM
1082 </div>
1083 <div className="text-muted-foreground">
1084 {vps.storage} GB Storage
1085 </div>
1086 </div>
1087 </TableCell>
1088 <TableCell>{vps.customerEmail}</TableCell>
1089 <TableCell>{vps.domain || "-"}</TableCell>
1090 <TableCell>
1091 <Badge
1092 variant={
1093 vps.status === "running" ? "default" : "secondary"
1094 }
1095 >
1096 {vps.status}
1097 </Badge>
1098 </TableCell>
1099 <TableCell>
1100 <div className="flex space-x-2">
1101 <Button variant="outline" size="sm">
1102 <Edit className="h-4 w-4" />
1103 </Button>
1104 <Button variant="outline" size="sm">
1105 <Power className="h-4 w-4" />
1106 </Button>
1107 <Button variant="outline" size="sm">
1108 <Trash2 className="h-4 w-4" />
1109 </Button>
1110 </div>
1111 </TableCell>
1112 </TableRow>
1113 ))}
1114 </TableBody>
1115 </Table>
1116 </CardContent>
1117 </Card>
1118 </TabsContent>
1119 </Tabs>
1120 </div>
1121 </div>
1122 );
1123};
1124
1125export default VPSAdminDashboard;
Dependencies
External Libraries
lucide-reactreact
Shadcn/UI Components
badgebuttoncarddialoginputlabelprogressselectseparatorswitchtabletabs