ShadCN Vaults

Back to Blocks

Modern VPS Admin Console

System Monitoring Block

System MonitoringComponent

Modern VPS Admin Console

Modern VPS admin console with sidebar navigation, responsive layout, and advanced filtering for managing VPS parents, shared, and dedicated servers.

Preview

Full width desktop view

Code

monitoring-8.tsx
1"use client";
2
3import React, { useState, useEffect } from "react";
4import {
5  Server,
6  Plus,
7  Settings,
8  Monitor,
9  Database,
10  Globe,
11  Cpu,
12  HardDrive,
13  MemoryStick,
14  Activity,
15  Users,
16  ChevronRight,
17  ChevronDown,
18  Edit,
19  Trash2,
20  Play,
21  Square,
22  RotateCcw,
23  AlertCircle,
24  CheckCircle,
25  Clock,
26  Search,
27  Filter,
28  MoreVertical,
29  MapPin,
30  Zap,
31  Shield,
32  Menu,
33  X,
34  ChevronLeft,
35  Home,
36  BarChart3,
37} from "lucide-react";
38import { motion, AnimatePresence } from "framer-motion";
39import {
40  Card,
41  CardContent,
42  CardDescription,
43  CardHeader,
44  CardTitle,
45} from "@/components/ui/card";
46import { Button } from "@/components/ui/button";
47import { Input } from "@/components/ui/input";
48import { Label } from "@/components/ui/label";
49import {
50  Select,
51  SelectContent,
52  SelectItem,
53  SelectTrigger,
54  SelectValue,
55} from "@/components/ui/select";
56import { Badge } from "@/components/ui/badge";
57import {
58  Dialog,
59  DialogContent,
60  DialogDescription,
61  DialogHeader,
62  DialogTitle,
63  DialogTrigger,
64} from "@/components/ui/dialog";
65import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
66import { Progress } from "@/components/ui/progress";
67import { Separator } from "@/components/ui/separator";
68import { Switch } from "@/components/ui/switch";
69import { Textarea } from "@/components/ui/textarea";
70
71interface VPSParent {
72  id: string;
73  name: string;
74  region: string;
75  cpu: number;
76  ram: number;
77  storage: number;
78  status: "online" | "offline" | "maintenance";
79  ipAddress: string;
80  createdAt: string;
81  sharedVPS: SharedVPS[];
82  dedicatedVPS: DedicatedVPS[];
83  totalSharedInstances: number;
84  usedResources: {
85    cpu: number;
86    ram: number;
87    storage: number;
88  };
89}
90
91interface SharedVPS {
92  id: string;
93  name: string;
94  parentId: string;
95  customerId: string;
96  customerName: string;
97  allocatedCpu: number;
98  allocatedRam: number;
99  allocatedStorage: number;
100  status: "running" | "stopped" | "suspended";
101  domain?: string;
102  createdAt: string;
103}
104
105interface DedicatedVPS {
106  id: string;
107  name: string;
108  parentId: string;
109  customerId: string;
110  customerName: string;
111  cpu: number;
112  ram: number;
113  storage: number;
114  status: "running" | "stopped" | "suspended";
115  ipAddress: string;
116  domain?: string;
117  createdAt: string;
118}
119
120const VPSAdminDashboard = () => {
121  const [sidebarOpen, setSidebarOpen] = useState(false);
122  const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
123  const [activeTab, setActiveTab] = useState("overview");
124  const [searchTerm, setSearchTerm] = useState("");
125  const [selectedRegion, setSelectedRegion] = useState("all");
126  const [expandedParents, setExpandedParents] = useState<Set<string>>(
127    new Set()
128  );
129
130  // Sample data
131  const [vpsParents, setVpsParents] = useState<VPSParent[]>([
132    {
133      id: "parent-1",
134      name: "US-East-Primary",
135      region: "us-east-1",
136      cpu: 32,
137      ram: 128,
138      storage: 2000,
139      status: "online",
140      ipAddress: "192.168.1.100",
141      createdAt: "2024-01-15",
142      totalSharedInstances: 8,
143      usedResources: { cpu: 24, ram: 96, storage: 1200 },
144      sharedVPS: [
145        {
146          id: "shared-1",
147          name: "Store-Alpha",
148          parentId: "parent-1",
149          customerId: "cust-1",
150          customerName: "John Doe",
151          allocatedCpu: 4,
152          allocatedRam: 8,
153          allocatedStorage: 100,
154          status: "running",
155          domain: "store-alpha.com",
156          createdAt: "2024-01-20",
157        },
158        {
159          id: "shared-2",
160          name: "Store-Beta",
161          parentId: "parent-1",
162          customerId: "cust-2",
163          customerName: "Jane Smith",
164          allocatedCpu: 2,
165          allocatedRam: 4,
166          allocatedStorage: 50,
167          status: "running",
168          domain: "store-beta.com",
169          createdAt: "2024-01-22",
170        },
171      ],
172      dedicatedVPS: [
173        {
174          id: "dedicated-1",
175          name: "Enterprise-Store",
176          parentId: "parent-1",
177          customerId: "cust-3",
178          customerName: "Acme Corp",
179          cpu: 16,
180          ram: 64,
181          storage: 500,
182          status: "running",
183          ipAddress: "192.168.1.101",
184          domain: "enterprise-store.com",
185          createdAt: "2024-01-18",
186        },
187      ],
188    },
189    {
190      id: "parent-2",
191      name: "EU-West-Primary",
192      region: "eu-west-1",
193      cpu: 24,
194      ram: 96,
195      storage: 1500,
196      status: "online",
197      ipAddress: "192.168.2.100",
198      createdAt: "2024-01-10",
199      totalSharedInstances: 6,
200      usedResources: { cpu: 18, ram: 72, storage: 900 },
201      sharedVPS: [],
202      dedicatedVPS: [],
203    },
204  ]);
205
206  const [newVPSParent, setNewVPSParent] = useState({
207    name: "",
208    region: "",
209    cpu: 0,
210    ram: 0,
211    storage: 0,
212    ipAddress: "",
213  });
214
215  const [newSharedVPS, setNewSharedVPS] = useState({
216    name: "",
217    parentId: "",
218    customerId: "",
219    customerName: "",
220    allocatedCpu: 0,
221    allocatedRam: 0,
222    allocatedStorage: 0,
223    domain: "",
224  });
225
226  const [newDedicatedVPS, setNewDedicatedVPS] = useState({
227    name: "",
228    parentId: "",
229    customerId: "",
230    customerName: "",
231    cpu: 0,
232    ram: 0,
233    storage: 0,
234    ipAddress: "",
235    domain: "",
236  });
237
238  const menuItems = [
239    { name: "Overview", icon: Home, key: "overview" },
240    { name: "VPS Parents", icon: Server, key: "parents" },
241    { name: "Shared VPS", icon: Users, key: "shared" },
242    { name: "Dedicated VPS", icon: Database, key: "dedicated" },
243    { name: "Monitoring", icon: Activity, key: "monitoring" },
244    { name: "Settings", icon: Settings, key: "settings" },
245  ];
246
247  const regions = [
248    { value: "us-east-1", label: "US East (N. Virginia)" },
249    { value: "us-west-2", label: "US West (Oregon)" },
250    { value: "eu-west-1", label: "EU West (Ireland)" },
251    { value: "ap-southeast-1", label: "Asia Pacific (Singapore)" },
252  ];
253
254  const getStatusColor = (status: string) => {
255    switch (status) {
256      case "online":
257      case "running":
258        return "bg-green-500";
259      case "offline":
260      case "stopped":
261        return "bg-red-500";
262      case "maintenance":
263      case "suspended":
264        return "bg-yellow-500";
265      default:
266        return "bg-gray-500";
267    }
268  };
269
270  const getStatusIcon = (status: string) => {
271    switch (status) {
272      case "online":
273      case "running":
274        return <CheckCircle className="h-4 w-4 text-green-500" />;
275      case "offline":
276      case "stopped":
277        return <AlertCircle className="h-4 w-4 text-red-500" />;
278      case "maintenance":
279      case "suspended":
280        return <Clock className="h-4 w-4 text-yellow-500" />;
281      default:
282        return <AlertCircle className="h-4 w-4 text-gray-500" />;
283    }
284  };
285
286  const toggleParentExpansion = (parentId: string) => {
287    setExpandedParents((prev) => {
288      const newSet = new Set(prev);
289      if (newSet.has(parentId)) {
290        newSet.delete(parentId);
291      } else {
292        newSet.add(parentId);
293      }
294      return newSet;
295    });
296  };
297
298  const createVPSParent = () => {
299    const newParent: VPSParent = {
300      id: `parent-${Date.now()}`,
301      ...newVPSParent,
302      status: "online",
303      createdAt: new Date().toISOString().split("T")[0],
304      sharedVPS: [],
305      dedicatedVPS: [],
306      totalSharedInstances: 0,
307      usedResources: { cpu: 0, ram: 0, storage: 0 },
308    };
309    setVpsParents([...vpsParents, newParent]);
310    setNewVPSParent({
311      name: "",
312      region: "",
313      cpu: 0,
314      ram: 0,
315      storage: 0,
316      ipAddress: "",
317    });
318  };
319
320  const createSharedVPS = () => {
321    const parentIndex = vpsParents.findIndex(
322      (p) => p.id === newSharedVPS.parentId
323    );
324    if (parentIndex !== -1) {
325      const newShared: SharedVPS = {
326        id: `shared-${Date.now()}`,
327        ...newSharedVPS,
328        status: "running",
329        createdAt: new Date().toISOString().split("T")[0],
330      };
331
332      const updatedParents = [...vpsParents];
333      updatedParents[parentIndex].sharedVPS.push(newShared);
334      updatedParents[parentIndex].totalSharedInstances += 1;
335      updatedParents[parentIndex].usedResources.cpu +=
336        newSharedVPS.allocatedCpu;
337      updatedParents[parentIndex].usedResources.ram +=
338        newSharedVPS.allocatedRam;
339      updatedParents[parentIndex].usedResources.storage +=
340        newSharedVPS.allocatedStorage;
341
342      setVpsParents(updatedParents);
343      setNewSharedVPS({
344        name: "",
345        parentId: "",
346        customerId: "",
347        customerName: "",
348        allocatedCpu: 0,
349        allocatedRam: 0,
350        allocatedStorage: 0,
351        domain: "",
352      });
353    }
354  };
355
356  const createDedicatedVPS = () => {
357    const parentIndex = vpsParents.findIndex(
358      (p) => p.id === newDedicatedVPS.parentId
359    );
360    if (parentIndex !== -1) {
361      const newDedicated: DedicatedVPS = {
362        id: `dedicated-${Date.now()}`,
363        ...newDedicatedVPS,
364        status: "running",
365        createdAt: new Date().toISOString().split("T")[0],
366      };
367
368      const updatedParents = [...vpsParents];
369      updatedParents[parentIndex].dedicatedVPS.push(newDedicated);
370
371      setVpsParents(updatedParents);
372      setNewDedicatedVPS({
373        name: "",
374        parentId: "",
375        customerId: "",
376        customerName: "",
377        cpu: 0,
378        ram: 0,
379        storage: 0,
380        ipAddress: "",
381        domain: "",
382      });
383    }
384  };
385
386  const filteredParents = vpsParents.filter((parent) => {
387    const matchesSearch = parent.name
388      .toLowerCase()
389      .includes(searchTerm.toLowerCase());
390    const matchesRegion =
391      selectedRegion === "all" || parent.region === selectedRegion;
392    return matchesSearch && matchesRegion;
393  });
394
395  const totalStats = {
396    totalParents: vpsParents.length,
397    totalShared: vpsParents.reduce(
398      (sum, parent) => sum + parent.sharedVPS.length,
399      0
400    ),
401    totalDedicated: vpsParents.reduce(
402      (sum, parent) => sum + parent.dedicatedVPS.length,
403      0
404    ),
405    onlineParents: vpsParents.filter((p) => p.status === "online").length,
406  };
407
408  useEffect(() => {
409    const handleResize = () => {
410      if (window.innerWidth >= 768) {
411        setSidebarOpen(true);
412      } else {
413        setSidebarOpen(false);
414      }
415    };
416
417    handleResize();
418    window.addEventListener("resize", handleResize);
419    return () => window.removeEventListener("resize", handleResize);
420  }, []);
421
422  return (
423    <div className="flex h-screen bg-background">
424      {/* Mobile hamburger button */}
425      <button
426        onClick={() => setSidebarOpen(!sidebarOpen)}
427        className="fixed top-6 left-6 z-50 p-3 rounded-lg bg-white shadow-md border border-border md:hidden hover:bg-accent transition-all duration-200"
428      >
429        {sidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
430      </button>
431
432      {/* Mobile overlay */}
433      {sidebarOpen && (
434        <div
435          className="fixed inset-0 bg-black/40 backdrop-blur-sm z-30 md:hidden transition-opacity duration-300"
436          onClick={() => setSidebarOpen(false)}
437        />
438      )}
439
440      {/* Sidebar */}
441      <div
442        className={`
443          fixed top-0 left-0 h-full bg-card border-r border-border z-40 transition-all duration-300 ease-in-out flex flex-col
444          ${sidebarOpen ? "translate-x-0" : "-translate-x-full"}
445          ${sidebarCollapsed ? "w-20" : "w-72"}
446          md:translate-x-0 md:static md:z-auto
447        `}
448      >
449        {/* Header */}
450        <div className="flex items-center justify-between p-5 border-b border-border">
451          {!sidebarCollapsed && (
452            <div className="flex items-center space-x-3">
453              <div className="w-10 h-10 bg-primary rounded-lg flex items-center justify-center">
454                <Server className="h-6 w-6 text-primary-foreground" />
455              </div>
456              <div>
457                <h1 className="text-lg font-bold text-foreground">VPS Admin</h1>
458                <p className="text-xs text-muted-foreground">
459                  Management Console
460                </p>
461              </div>
462            </div>
463          )}
464
465          <button
466            onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
467            className="hidden md:flex p-1.5 rounded-md hover:bg-accent transition-all duration-200"
468          >
469            {sidebarCollapsed ? (
470              <ChevronRight className="h-4 w-4 text-muted-foreground" />
471            ) : (
472              <ChevronLeft className="h-4 w-4 text-muted-foreground" />
473            )}
474          </button>
475        </div>
476
477        {/* Navigation */}
478        <nav className="flex-1 p-4 space-y-2">
479          {menuItems.map((item) => {
480            const Icon = item.icon;
481            const isActive = activeTab === item.key;
482
483            return (
484              <button
485                key={item.key}
486                onClick={() => {
487                  setActiveTab(item.key);
488                  if (window.innerWidth < 768) setSidebarOpen(false);
489                }}
490                className={`
491                  w-full flex items-center space-x-3 px-3 py-2.5 rounded-lg transition-all duration-200 group
492                  ${
493                    isActive
494                      ? "bg-primary text-primary-foreground"
495                      : "text-muted-foreground hover:bg-accent hover:text-foreground"
496                  }
497                  ${sidebarCollapsed ? "justify-center px-2" : ""}
498                `}
499                title={sidebarCollapsed ? item.name : undefined}
500              >
501                <Icon className="h-5 w-5 flex-shrink-0" />
502                {!sidebarCollapsed && (
503                  <span className="font-medium">{item.name}</span>
504                )}
505              </button>
506            );
507          })}
508        </nav>
509      </div>
510
511      {/* Main Content */}
512      <div
513        className={`flex-1 flex flex-col transition-all duration-300 ${
514          sidebarCollapsed ? "md:ml-20" : "md:ml-72"
515        }`}
516      >
517        {/* Header */}
518        <header className="bg-card border-b border-border p-6 ml-16 md:ml-0">
519          <div className="flex items-center justify-between">
520            <div>
521              <h1 className="text-2xl font-bold text-foreground">
522                VPS Management Dashboard
523              </h1>
524              <p className="text-muted-foreground">
525                Manage and monitor your VPS infrastructure
526              </p>
527            </div>
528            <div className="flex items-center space-x-4">
529              <div className="relative">
530                <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
531                <Input
532                  placeholder="Search VPS..."
533                  value={searchTerm}
534                  onChange={(e) => setSearchTerm(e.target.value)}
535                  className="pl-10 w-64"
536                />
537              </div>
538              <Select value={selectedRegion} onValueChange={setSelectedRegion}>
539                <SelectTrigger className="w-48">
540                  <SelectValue placeholder="Filter by region" />
541                </SelectTrigger>
542                <SelectContent>
543                  <SelectItem value="all">All Regions</SelectItem>
544                  {regions.map((region) => (
545                    <SelectItem key={region.value} value={region.value}>
546                      {region.label}
547                    </SelectItem>
548                  ))}
549                </SelectContent>
550              </Select>
551            </div>
552          </div>
553        </header>
554
555        {/* Content */}
556        <main className="flex-1 p-6 ml-16 md:ml-0 overflow-auto">
557          <Tabs value={activeTab} onValueChange={setActiveTab}>
558            {/* Overview Tab */}
559            <TabsContent value="overview" className="space-y-6">
560              <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
561                <Card>
562                  <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
563                    <CardTitle className="text-sm font-medium">
564                      VPS Parents
565                    </CardTitle>
566                    <Server className="h-4 w-4 text-muted-foreground" />
567                  </CardHeader>
568                  <CardContent>
569                    <div className="text-2xl font-bold">
570                      {totalStats.totalParents}
571                    </div>
572                    <p className="text-xs text-muted-foreground">
573                      {totalStats.onlineParents} online
574                    </p>
575                  </CardContent>
576                </Card>
577
578                <Card>
579                  <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
580                    <CardTitle className="text-sm font-medium">
581                      Shared VPS
582                    </CardTitle>
583                    <Users className="h-4 w-4 text-muted-foreground" />
584                  </CardHeader>
585                  <CardContent>
586                    <div className="text-2xl font-bold">
587                      {totalStats.totalShared}
588                    </div>
589                    <p className="text-xs text-muted-foreground">
590                      Active instances
591                    </p>
592                  </CardContent>
593                </Card>
594
595                <Card>
596                  <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
597                    <CardTitle className="text-sm font-medium">
598                      Dedicated VPS
599                    </CardTitle>
600                    <Database className="h-4 w-4 text-muted-foreground" />
601                  </CardHeader>
602                  <CardContent>
603                    <div className="text-2xl font-bold">
604                      {totalStats.totalDedicated}
605                    </div>
606                    <p className="text-xs text-muted-foreground">
607                      Standalone instances
608                    </p>
609                  </CardContent>
610                </Card>
611
612                <Card>
613                  <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
614                    <CardTitle className="text-sm font-medium">
615                      Total Customers
616                    </CardTitle>
617                    <Globe className="h-4 w-4 text-muted-foreground" />
618                  </CardHeader>
619                  <CardContent>
620                    <div className="text-2xl font-bold">
621                      {
622                        new Set([
623                          ...vpsParents.flatMap((p) =>
624                            p.sharedVPS.map((s) => s.customerId)
625                          ),
626                          ...vpsParents.flatMap((p) =>
627                            p.dedicatedVPS.map((d) => d.customerId)
628                          ),
629                        ]).size
630                      }
631                    </div>
632                    <p className="text-xs text-muted-foreground">
633                      Unique customers
634                    </p>
635                  </CardContent>
636                </Card>
637              </div>
638
639              {/* Recent Activity */}
640              <Card>
641                <CardHeader>
642                  <CardTitle>Recent Activity</CardTitle>
643                  <CardDescription>
644                    Latest VPS management activities
645                  </CardDescription>
646                </CardHeader>
647                <CardContent>
648                  <div className="space-y-4">
649                    {[
650                      {
651                        action: "Created new VPS Parent",
652                        target: "US-East-Primary",
653                        time: "2 hours ago",
654                        type: "create",
655                      },
656                      {
657                        action: "Deployed Shared VPS",
658                        target: "Store-Alpha",
659                        time: "4 hours ago",
660                        type: "deploy",
661                      },
662                      {
663                        action: "Updated Dedicated VPS",
664                        target: "Enterprise-Store",
665                        time: "6 hours ago",
666                        type: "update",
667                      },
668                      {
669                        action: "Maintenance completed",
670                        target: "EU-West-Primary",
671                        time: "1 day ago",
672                        type: "maintenance",
673                      },
674                    ].map((activity, index) => (
675                      <div key={index} className="flex items-center space-x-4">
676                        <div
677                          className={`w-2 h-2 rounded-full ${
678                            activity.type === "create"
679                              ? "bg-green-500"
680                              : activity.type === "deploy"
681                              ? "bg-blue-500"
682                              : activity.type === "update"
683                              ? "bg-yellow-500"
684                              : "bg-purple-500"
685                          }`}
686                        />
687                        <div className="flex-1">
688                          <p className="text-sm font-medium">
689                            {activity.action}
690                          </p>
691                          <p className="text-xs text-muted-foreground">
692                            {activity.target}
693                          </p>
694                        </div>
695                        <p className="text-xs text-muted-foreground">
696                          {activity.time}
697                        </p>
698                      </div>
699                    ))}
700                  </div>
701                </CardContent>
702              </Card>
703            </TabsContent>
704
705            {/* VPS Parents Tab */}
706            <TabsContent value="parents" className="space-y-6">
707              <div className="flex justify-between items-center">
708                <h2 className="text-xl font-semibold">VPS Parents</h2>
709                <Dialog>
710                  <DialogTrigger asChild>
711                    <Button>
712                      <Plus className="h-4 w-4 mr-2" />
713                      Add VPS Parent
714                    </Button>
715                  </DialogTrigger>
716                  <DialogContent className="sm:max-w-md">
717                    <DialogHeader>
718                      <DialogTitle>Create New VPS Parent</DialogTitle>
719                      <DialogDescription>
720                        Set up a new VPS parent server with specified resources.
721                      </DialogDescription>
722                    </DialogHeader>
723                    <div className="space-y-4">
724                      <div>
725                        <Label htmlFor="parent-name">Server Name</Label>
726                        <Input
727                          id="parent-name"
728                          value={newVPSParent.name}
729                          onChange={(e) =>
730                            setNewVPSParent({
731                              ...newVPSParent,
732                              name: e.target.value,
733                            })
734                          }
735                          placeholder="e.g., US-East-Primary"
736                        />
737                      </div>
738                      <div>
739                        <Label htmlFor="parent-region">Region</Label>
740                        <Select
741                          value={newVPSParent.region}
742                          onValueChange={(value) =>
743                            setNewVPSParent({ ...newVPSParent, region: value })
744                          }
745                        >
746                          <SelectTrigger>
747                            <SelectValue placeholder="Select region" />
748                          </SelectTrigger>
749                          <SelectContent>
750                            {regions.map((region) => (
751                              <SelectItem
752                                key={region.value}
753                                value={region.value}
754                              >
755                                {region.label}
756                              </SelectItem>
757                            ))}
758                          </SelectContent>
759                        </Select>
760                      </div>
761                      <div className="grid grid-cols-3 gap-4">
762                        <div>
763                          <Label htmlFor="parent-cpu">CPU Cores</Label>
764                          <Input
765                            id="parent-cpu"
766                            type="number"
767                            value={newVPSParent.cpu}
768                            onChange={(e) =>
769                              setNewVPSParent({
770                                ...newVPSParent,
771                                cpu: parseInt(e.target.value) || 0,
772                              })
773                            }
774                            placeholder="32"
775                          />
776                        </div>
777                        <div>
778                          <Label htmlFor="parent-ram">RAM (GB)</Label>
779                          <Input
780                            id="parent-ram"
781                            type="number"
782                            value={newVPSParent.ram}
783                            onChange={(e) =>
784                              setNewVPSParent({
785                                ...newVPSParent,
786                                ram: parseInt(e.target.value) || 0,
787                              })
788                            }
789                            placeholder="128"
790                          />
791                        </div>
792                        <div>
793                          <Label htmlFor="parent-storage">Storage (GB)</Label>
794                          <Input
795                            id="parent-storage"
796                            type="number"
797                            value={newVPSParent.storage}
798                            onChange={(e) =>
799                              setNewVPSParent({
800                                ...newVPSParent,
801                                storage: parseInt(e.target.value) || 0,
802                              })
803                            }
804                            placeholder="2000"
805                          />
806                        </div>
807                      </div>
808                      <div>
809                        <Label htmlFor="parent-ip">IP Address</Label>
810                        <Input
811                          id="parent-ip"
812                          value={newVPSParent.ipAddress}
813                          onChange={(e) =>
814                            setNewVPSParent({
815                              ...newVPSParent,
816                              ipAddress: e.target.value,
817                            })
818                          }
819                          placeholder="192.168.1.100"
820                        />
821                      </div>
822                      <Button onClick={createVPSParent} className="w-full">
823                        Create VPS Parent
824                      </Button>
825                    </div>
826                  </DialogContent>
827                </Dialog>
828              </div>
829
830              <div className="space-y-4">
831                {filteredParents.map((parent) => (
832                  <Card key={parent.id}>
833                    <CardHeader>
834                      <div className="flex items-center justify-between">
835                        <div className="flex items-center space-x-3">
836                          <button
837                            onClick={() => toggleParentExpansion(parent.id)}
838                            className="p-1 hover:bg-accent rounded"
839                          >
840                            {expandedParents.has(parent.id) ? (
841                              <ChevronDown className="h-4 w-4" />
842                            ) : (
843                              <ChevronRight className="h-4 w-4" />
844                            )}
845                          </button>
846                          <div>
847                            <CardTitle className="flex items-center space-x-2">
848                              <span>{parent.name}</span>
849                              <Badge
850                                variant={
851                                  parent.status === "online"
852                                    ? "default"
853                                    : "destructive"
854                                }
855                              >
856                                {parent.status}
857                              </Badge>
858                            </CardTitle>
859                            <CardDescription className="flex items-center space-x-4">
860                              <span className="flex items-center space-x-1">
861                                <MapPin className="h-3 w-3" />
862                                <span>
863                                  {
864                                    regions.find(
865                                      (r) => r.value === parent.region
866                                    )?.label
867                                  }
868                                </span>
869                              </span>
870                              <span>{parent.ipAddress}</span>
871                            </CardDescription>
872                          </div>
873                        </div>
874                        <div className="flex items-center space-x-2">
875                          <Button variant="outline" size="sm">
876                            <Settings className="h-4 w-4" />
877                          </Button>
878                          <Button variant="outline" size="sm">
879                            <MoreVertical className="h-4 w-4" />
880                          </Button>
881                        </div>
882                      </div>
883                    </CardHeader>
884                    <CardContent>
885                      <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
886                        <div className="space-y-2">
887                          <div className="flex items-center justify-between">
888                            <span className="text-sm text-muted-foreground">
889                              CPU Usage
890                            </span>
891                            <span className="text-sm font-medium">
892                              {parent.usedResources.cpu}/{parent.cpu} cores
893                            </span>
894                          </div>
895                          <Progress
896                            value={
897                              (parent.usedResources.cpu / parent.cpu) * 100
898                            }
899                          />
900                        </div>
901                        <div className="space-y-2">
902                          <div className="flex items-center justify-between">
903                            <span className="text-sm text-muted-foreground">
904                              RAM Usage
905                            </span>
906                            <span className="text-sm font-medium">
907                              {parent.usedResources.ram}/{parent.ram} GB
908                            </span>
909                          </div>
910                          <Progress
911                            value={
912                              (parent.usedResources.ram / parent.ram) * 100
913                            }
914                          />
915                        </div>
916                        <div className="space-y-2">
917                          <div className="flex items-center justify-between">
918                            <span className="text-sm text-muted-foreground">
919                              Storage Usage
920                            </span>
921                            <span className="text-sm font-medium">
922                              {parent.usedResources.storage}/{parent.storage} GB
923                            </span>
924                          </div>
925                          <Progress
926                            value={
927                              (parent.usedResources.storage / parent.storage) *
928                              100
929                            }
930                          />
931                        </div>
932                      </div>
933
934                      <AnimatePresence>
935                        {expandedParents.has(parent.id) && (
936                          <motion.div
937                            initial={{ height: 0, opacity: 0 }}
938                            animate={{ height: "auto", opacity: 1 }}
939                            exit={{ height: 0, opacity: 0 }}
940                            transition={{ duration: 0.3 }}
941                            className="overflow-hidden"
942                          >
943                            <Separator className="my-4" />
944                            <div className="space-y-4">
945                              <div className="flex items-center justify-between">
946                                <h4 className="font-medium">
947                                  Shared VPS Instances (
948                                  {parent.sharedVPS.length})
949                                </h4>
950                                <Dialog>
951                                  <DialogTrigger asChild>
952                                    <Button variant="outline" size="sm">
953                                      <Plus className="h-4 w-4 mr-1" />
954                                      Add Shared VPS
955                                    </Button>
956                                  </DialogTrigger>
957                                  <DialogContent>
958                                    <DialogHeader>
959                                      <DialogTitle>
960                                        Create Shared VPS
961                                      </DialogTitle>
962                                      <DialogDescription>
963                                        Create a new shared VPS instance under{" "}
964                                        {parent.name}
965                                      </DialogDescription>
966                                    </DialogHeader>
967                                    <div className="space-y-4">
968                                      <div>
969                                        <Label>VPS Name</Label>
970                                        <Input
971                                          value={newSharedVPS.name}
972                                          onChange={(e) =>
973                                            setNewSharedVPS({
974                                              ...newSharedVPS,
975                                              name: e.target.value,
976                                              parentId: parent.id,
977                                            })
978                                          }
979                                          placeholder="Store-Gamma"
980                                        />
981                                      </div>
982                                      <div className="grid grid-cols-2 gap-4">
983                                        <div>
984                                          <Label>Customer ID</Label>
985                                          <Input
986                                            value={newSharedVPS.customerId}
987                                            onChange={(e) =>
988                                              setNewSharedVPS({
989                                                ...newSharedVPS,
990                                                customerId: e.target.value,
991                                              })
992                                            }
993                                            placeholder="cust-123"
994                                          />
995                                        </div>
996                                        <div>
997                                          <Label>Customer Name</Label>
998                                          <Input
999                                            value={newSharedVPS.customerName}
1000                                            onChange={(e) =>
1001                                              setNewSharedVPS({
1002                                                ...newSharedVPS,
1003                                                customerName: e.target.value,
1004                                              })
1005                                            }
1006                                            placeholder="John Doe"
1007                                          />
1008                                        </div>
1009                                      </div>
1010                                      <div className="grid grid-cols-3 gap-4">
1011                                        <div>
1012                                          <Label>CPU Cores</Label>
1013                                          <Input
1014                                            type="number"
1015                                            value={newSharedVPS.allocatedCpu}
1016                                            onChange={(e) =>
1017                                              setNewSharedVPS({
1018                                                ...newSharedVPS,
1019                                                allocatedCpu:
1020                                                  parseInt(e.target.value) || 0,
1021                                              })
1022                                            }
1023                                            placeholder="2"
1024                                          />
1025                                        </div>
1026                                        <div>
1027                                          <Label>RAM (GB)</Label>
1028                                          <Input
1029                                            type="number"
1030                                            value={newSharedVPS.allocatedRam}
1031                                            onChange={(e) =>
1032                                              setNewSharedVPS({
1033                                                ...newSharedVPS,
1034                                                allocatedRam:
1035                                                  parseInt(e.target.value) || 0,
1036                                              })
1037                                            }
1038                                            placeholder="4"
1039                                          />
1040                                        </div>
1041                                        <div>
1042                                          <Label>Storage (GB)</Label>
1043                                          <Input
1044                                            type="number"
1045                                            value={
1046                                              newSharedVPS.allocatedStorage
1047                                            }
1048                                            onChange={(e) =>
1049                                              setNewSharedVPS({
1050                                                ...newSharedVPS,
1051                                                allocatedStorage:
1052                                                  parseInt(e.target.value) || 0,
1053                                              })
1054                                            }
1055                                            placeholder="50"
1056                                          />
1057                                        </div>
1058                                      </div>
1059                                      <div>
1060                                        <Label>Domain (Optional)</Label>
1061                                        <Input
1062                                          value={newSharedVPS.domain}
1063                                          onChange={(e) =>
1064                                            setNewSharedVPS({
1065                                              ...newSharedVPS,
1066                                              domain: e.target.value,
1067                                            })
1068                                          }
1069                                          placeholder="store-gamma.com"
1070                                        />
1071                                      </div>
1072                                      <Button
1073                                        onClick={createSharedVPS}
1074                                        className="w-full"
1075                                      >
1076                                        Create Shared VPS
1077                                      </Button>
1078                                    </div>
1079                                  </DialogContent>
1080                                </Dialog>
1081                              </div>
1082
1083                              {parent.sharedVPS.length > 0 ? (
1084                                <div className="grid gap-2">
1085                                  {parent.sharedVPS.map((shared) => (
1086                                    <div
1087                                      key={shared.id}
1088                                      className="flex items-center justify-between p-3 bg-accent/50 rounded-lg"
1089                                    >
1090                                      <div className="flex items-center space-x-3">
1091                                        <div
1092                                          className={`w-2 h-2 rounded-full ${getStatusColor(
1093                                            shared.status
1094                                          )}`}
1095                                        />
1096                                        <div>
1097                                          <p className="font-medium">
1098                                            {shared.name}
1099                                          </p>
1100                                          <p className="text-xs text-muted-foreground">
1101                                            {shared.customerName}{" "}
1102                                            {shared.allocatedCpu}C/
1103                                            {shared.allocatedRam}GB/
1104                                            {shared.allocatedStorage}GB
1105                                          </p>
1106                                        </div>
1107                                      </div>
1108                                      <div className="flex items-center space-x-2">
1109                                        <Badge variant="outline">
1110                                          {shared.status}
1111                                        </Badge>
1112                                        <Button variant="ghost" size="sm">
1113                                          <Settings className="h-3 w-3" />
1114                                        </Button>
1115                                      </div>
1116                                    </div>
1117                                  ))}
1118                                </div>
1119                              ) : (
1120                                <p className="text-sm text-muted-foreground text-center py-4">
1121                                  No shared VPS instances
1122                                </p>
1123                              )}
1124
1125                              <div className="flex items-center justify-between">
1126                                <h4 className="font-medium">
1127                                  Dedicated VPS Instances (
1128                                  {parent.dedicatedVPS.length})
1129                                </h4>
1130                                <Dialog>
1131                                  <DialogTrigger asChild>
1132                                    <Button variant="outline" size="sm">
1133                                      <Plus className="h-4 w-4 mr-1" />
1134                                      Add Dedicated VPS
1135                                    </Button>
1136                                  </DialogTrigger>
1137                                  <DialogContent>
1138                                    <DialogHeader>
1139                                      <DialogTitle>
1140                                        Create Dedicated VPS
1141                                      </DialogTitle>
1142                                      <DialogDescription>
1143                                        Create a new dedicated VPS instance
1144                                        under {parent.name}
1145                                      </DialogDescription>
1146                                    </DialogHeader>
1147                                    <div className="space-y-4">
1148                                      <div>
1149                                        <Label>VPS Name</Label>
1150                                        <Input
1151                                          value={newDedicatedVPS.name}
1152                                          onChange={(e) =>
1153                                            setNewDedicatedVPS({
1154                                              ...newDedicatedVPS,
1155                                              name: e.target.value,
1156                                              parentId: parent.id,
1157                                            })
1158                                          }
1159                                          placeholder="Enterprise-Store-2"
1160                                        />
1161                                      </div>
1162                                      <div className="grid grid-cols-2 gap-4">
1163                                        <div>
1164                                          <Label>Customer ID</Label>
1165                                          <Input
1166                                            value={newDedicatedVPS.customerId}
1167                                            onChange={(e) =>
1168                                              setNewDedicatedVPS({
1169                                                ...newDedicatedVPS,
1170                                                customerId: e.target.value,
1171                                              })
1172                                            }
1173                                            placeholder="cust-456"
1174                                          />
1175                                        </div>
1176                                        <div>
1177                                          <Label>Customer Name</Label>
1178                                          <Input
1179                                            value={newDedicatedVPS.customerName}
1180                                            onChange={(e) =>
1181                                              setNewDedicatedVPS({
1182                                                ...newDedicatedVPS,
1183                                                customerName: e.target.value,
1184                                              })
1185                                            }
1186                                            placeholder="Acme Corp"
1187                                          />
1188                                        </div>
1189                                      </div>
1190                                      <div className="grid grid-cols-3 gap-4">
1191                                        <div>
1192                                          <Label>CPU Cores</Label>
1193                                          <Input
1194                                            type="number"
1195                                            value={newDedicatedVPS.cpu}
1196                                            onChange={(e) =>
1197                                              setNewDedicatedVPS({
1198                                                ...newDedicatedVPS,
1199                                                cpu:
1200                                                  parseInt(e.target.value) || 0,
1201                                              })
1202                                            }
1203                                            placeholder="8"
1204                                          />
1205                                        </div>
1206                                        <div>
1207                                          <Label>RAM (GB)</Label>
1208                                          <Input
1209                                            type="number"
1210                                            value={newDedicatedVPS.ram}
1211                                            onChange={(e) =>
1212                                              setNewDedicatedVPS({
1213                                                ...newDedicatedVPS,
1214                                                ram:
1215                                                  parseInt(e.target.value) || 0,
1216                                              })
1217                                            }
1218                                            placeholder="32"
1219                                          />
1220                                        </div>
1221                                        <div>
1222                                          <Label>Storage (GB)</Label>
1223                                          <Input
1224                                            type="number"
1225                                            value={newDedicatedVPS.storage}
1226                                            onChange={(e) =>
1227                                              setNewDedicatedVPS({
1228                                                ...newDedicatedVPS,
1229                                                storage:
1230                                                  parseInt(e.target.value) || 0,
1231                                              })
1232                                            }
1233                                            placeholder="500"
1234                                          />
1235                                        </div>
1236                                      </div>
1237                                      <div className="grid grid-cols-2 gap-4">
1238                                        <div>
1239                                          <Label>IP Address</Label>
1240                                          <Input
1241                                            value={newDedicatedVPS.ipAddress}
1242                                            onChange={(e) =>
1243                                              setNewDedicatedVPS({
1244                                                ...newDedicatedVPS,
1245                                                ipAddress: e.target.value,
1246                                              })
1247                                            }
1248                                            placeholder="192.168.1.102"
1249                                          />
1250                                        </div>
1251                                        <div>
1252                                          <Label>Domain (Optional)</Label>
1253                                          <Input
1254                                            value={newDedicatedVPS.domain}
1255                                            onChange={(e) =>
1256                                              setNewDedicatedVPS({
1257                                                ...newDedicatedVPS,
1258                                                domain: e.target.value,
1259                                              })
1260                                            }
1261                                            placeholder="enterprise-2.com"
1262                                          />
1263                                        </div>
1264                                      </div>
1265                                      <Button
1266                                        onClick={createDedicatedVPS}
1267                                        className="w-full"
1268                                      >
1269                                        Create Dedicated VPS
1270                                      </Button>
1271                                    </div>
1272                                  </DialogContent>
1273                                </Dialog>
1274                              </div>
1275
1276                              {parent.dedicatedVPS.length > 0 ? (
1277                                <div className="grid gap-2">
1278                                  {parent.dedicatedVPS.map((dedicated) => (
1279                                    <div
1280                                      key={dedicated.id}
1281                                      className="flex items-center justify-between p-3 bg-accent/50 rounded-lg"
1282                                    >
1283                                      <div className="flex items-center space-x-3">
1284                                        <div
1285                                          className={`w-2 h-2 rounded-full ${getStatusColor(
1286                                            dedicated.status
1287                                          )}`}
1288                                        />
1289                                        <div>
1290                                          <p className="font-medium">
1291                                            {dedicated.name}
1292                                          </p>
1293                                          <p className="text-xs text-muted-foreground">
1294                                            {dedicated.customerName}{" "}
1295                                            {dedicated.cpu}C/{dedicated.ram}GB/
1296                                            {dedicated.storage}GB •{" "}
1297                                            {dedicated.ipAddress}
1298                                          </p>
1299                                        </div>
1300                                      </div>
1301                                      <div className="flex items-center space-x-2">
1302                                        <Badge variant="outline">
1303                                          {dedicated.status}
1304                                        </Badge>
1305                                        <Button variant="ghost" size="sm">
1306                                          <Settings className="h-3 w-3" />
1307                                        </Button>
1308                                      </div>
1309                                    </div>
1310                                  ))}
1311                                </div>
1312                              ) : (
1313                                <p className="text-sm text-muted-foreground text-center py-4">
1314                                  No dedicated VPS instances
1315                                </p>
1316                              )}
1317                            </div>
1318                          </motion.div>
1319                        )}
1320                      </AnimatePresence>
1321                    </CardContent>
1322                  </Card>
1323                ))}
1324              </div>
1325            </TabsContent>
1326
1327            {/* Shared VPS Tab */}
1328            <TabsContent value="shared" className="space-y-6">
1329              <div className="flex justify-between items-center">
1330                <h2 className="text-xl font-semibold">Shared VPS Instances</h2>
1331                <Button>
1332                  <Plus className="h-4 w-4 mr-2" />
1333                  Add Shared VPS
1334                </Button>
1335              </div>
1336
1337              <div className="grid gap-4">
1338                {vpsParents.flatMap((parent) =>
1339                  parent.sharedVPS.map((shared) => (
1340                    <Card key={shared.id}>
1341                      <CardHeader>
1342                        <div className="flex items-center justify-between">
1343                          <div>
1344                            <CardTitle className="flex items-center space-x-2">
1345                              <span>{shared.name}</span>
1346                              <Badge
1347                                variant={
1348                                  shared.status === "running"
1349                                    ? "default"
1350                                    : "destructive"
1351                                }
1352                              >
1353                                {shared.status}
1354                              </Badge>
1355                            </CardTitle>
1356                            <CardDescription>
1357                              Customer: {shared.customerName} • Parent:{" "}
1358                              {parent.name}
1359                            </CardDescription>
1360                          </div>
1361                          <div className="flex items-center space-x-2">
1362                            <Button variant="outline" size="sm">
1363                              <Play className="h-4 w-4" />
1364                            </Button>
1365                            <Button variant="outline" size="sm">
1366                              <Square className="h-4 w-4" />
1367                            </Button>
1368                            <Button variant="outline" size="sm">
1369                              <RotateCcw className="h-4 w-4" />
1370                            </Button>
1371                            <Button variant="outline" size="sm">
1372                              <Settings className="h-4 w-4" />
1373                            </Button>
1374                          </div>
1375                        </div>
1376                      </CardHeader>
1377                      <CardContent>
1378                        <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
1379                          <div className="flex items-center space-x-2">
1380                            <Cpu className="h-4 w-4 text-muted-foreground" />
1381                            <span className="text-sm">
1382                              {shared.allocatedCpu} cores
1383                            </span>
1384                          </div>
1385                          <div className="flex items-center space-x-2">
1386                            <MemoryStick className="h-4 w-4 text-muted-foreground" />
1387                            <span className="text-sm">
1388                              {shared.allocatedRam} GB RAM
1389                            </span>
1390                          </div>
1391                          <div className="flex items-center space-x-2">
1392                            <HardDrive className="h-4 w-4 text-muted-foreground" />
1393                            <span className="text-sm">
1394                              {shared.allocatedStorage} GB Storage
1395                            </span>
1396                          </div>
1397                          <div className="flex items-center space-x-2">
1398                            <Globe className="h-4 w-4 text-muted-foreground" />
1399                            <span className="text-sm">
1400                              {shared.domain || "No domain"}
1401                            </span>
1402                          </div>
1403                        </div>
1404                      </CardContent>
1405                    </Card>
1406                  ))
1407                )}
1408              </div>
1409            </TabsContent>
1410
1411            {/* Dedicated VPS Tab */}
1412            <TabsContent value="dedicated" className="space-y-6">
1413              <div className="flex justify-between items-center">
1414                <h2 className="text-xl font-semibold">
1415                  Dedicated VPS Instances
1416                </h2>
1417                <Button>
1418                  <Plus className="h-4 w-4 mr-2" />
1419                  Add Dedicated VPS
1420                </Button>
1421              </div>
1422
1423              <div className="grid gap-4">
1424                {vpsParents.flatMap((parent) =>
1425                  parent.dedicatedVPS.map((dedicated) => (
1426                    <Card key={dedicated.id}>
1427                      <CardHeader>
1428                        <div className="flex items-center justify-between">
1429                          <div>
1430                            <CardTitle className="flex items-center space-x-2">
1431                              <span>{dedicated.name}</span>
1432                              <Badge
1433                                variant={
1434                                  dedicated.status === "running"
1435                                    ? "default"
1436                                    : "destructive"
1437                                }
1438                              >
1439                                {dedicated.status}
1440                              </Badge>
1441                            </CardTitle>
1442                            <CardDescription>
1443                              Customer: {dedicated.customerName} • Parent:{" "}
1444                              {parent.name}
1445                            </CardDescription>
1446                          </div>
1447                          <div className="flex items-center space-x-2">
1448                            <Button variant="outline" size="sm">
1449                              <Play className="h-4 w-4" />
1450                            </Button>
1451                            <Button variant="outline" size="sm">
1452                              <Square className="h-4 w-4" />
1453                            </Button>
1454                            <Button variant="outline" size="sm">
1455                              <RotateCcw className="h-4 w-4" />
1456                            </Button>
1457                            <Button variant="outline" size="sm">
1458                              <Settings className="h-4 w-4" />
1459                            </Button>
1460                          </div>
1461                        </div>
1462                      </CardHeader>
1463                      <CardContent>
1464                        <div className="grid grid-cols-1 md:grid-cols-5 gap-4">
1465                          <div className="flex items-center space-x-2">
1466                            <Cpu className="h-4 w-4 text-muted-foreground" />
1467                            <span className="text-sm">
1468                              {dedicated.cpu} cores
1469                            </span>
1470                          </div>
1471                          <div className="flex items-center space-x-2">
1472                            <MemoryStick className="h-4 w-4 text-muted-foreground" />
1473                            <span className="text-sm">
1474                              {dedicated.ram} GB RAM
1475                            </span>
1476                          </div>
1477                          <div className="flex items-center space-x-2">
1478                            <HardDrive className="h-4 w-4 text-muted-foreground" />
1479                            <span className="text-sm">
1480                              {dedicated.storage} GB Storage
1481                            </span>
1482                          </div>
1483                          <div className="flex items-center space-x-2">
1484                            <Server className="h-4 w-4 text-muted-foreground" />
1485                            <span className="text-sm">
1486                              {dedicated.ipAddress}
1487                            </span>
1488                          </div>
1489                          <div className="flex items-center space-x-2">
1490                            <Globe className="h-4 w-4 text-muted-foreground" />
1491                            <span className="text-sm">
1492                              {dedicated.domain || "No domain"}
1493                            </span>
1494                          </div>
1495                        </div>
1496                      </CardContent>
1497                    </Card>
1498                  ))
1499                )}
1500              </div>
1501            </TabsContent>
1502
1503            {/* Monitoring Tab */}
1504            <TabsContent value="monitoring" className="space-y-6">
1505              <h2 className="text-xl font-semibold">System Monitoring</h2>
1506
1507              <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1508                <Card>
1509                  <CardHeader>
1510                    <CardTitle>Resource Usage Overview</CardTitle>
1511                  </CardHeader>
1512                  <CardContent>
1513                    <div className="space-y-4">
1514                      {vpsParents.map((parent) => (
1515                        <div key={parent.id} className="space-y-2">
1516                          <div className="flex items-center justify-between">
1517                            <span className="font-medium">{parent.name}</span>
1518                            <Badge
1519                              variant={
1520                                parent.status === "online"
1521                                  ? "default"
1522                                  : "destructive"
1523                              }
1524                            >
1525                              {parent.status}
1526                            </Badge>
1527                          </div>
1528                          <div className="grid grid-cols-3 gap-2 text-xs">
1529                            <div>
1530                              <div className="flex justify-between mb-1">
1531                                <span>CPU</span>
1532                                <span>
1533                                  {Math.round(
1534                                    (parent.usedResources.cpu / parent.cpu) *
1535                                      100
1536                                  )}
1537                                  %
1538                                </span>
1539                              </div>
1540                              <Progress
1541                                value={
1542                                  (parent.usedResources.cpu / parent.cpu) * 100
1543                                }
1544                                className="h-2"
1545                              />
1546                            </div>
1547                            <div>
1548                              <div className="flex justify-between mb-1">
1549                                <span>RAM</span>
1550                                <span>
1551                                  {Math.round(
1552                                    (parent.usedResources.ram / parent.ram) *
1553                                      100
1554                                  )}
1555                                  %
1556                                </span>
1557                              </div>
1558                              <Progress
1559                                value={
1560                                  (parent.usedResources.ram / parent.ram) * 100
1561                                }
1562                                className="h-2"
1563                              />
1564                            </div>
1565                            <div>
1566                              <div className="flex justify-between mb-1">
1567                                <span>Storage</span>
1568                                <span>
1569                                  {Math.round(
1570                                    (parent.usedResources.storage /
1571                                      parent.storage) *
1572                                      100
1573                                  )}
1574                                  %
1575                                </span>
1576                              </div>
1577                              <Progress
1578                                value={
1579                                  (parent.usedResources.storage /
1580                                    parent.storage) *
1581                                  100
1582                                }
1583                                className="h-2"
1584                              />
1585                            </div>
1586                          </div>
1587                        </div>
1588                      ))}
1589                    </div>
1590                  </CardContent>
1591                </Card>
1592
1593                <Card>
1594                  <CardHeader>
1595                    <CardTitle>System Alerts</CardTitle>
1596                  </CardHeader>
1597                  <CardContent>
1598                    <div className="space-y-3">
1599                      {[
1600                        {
1601                          type: "warning",
1602                          message: "High CPU usage on US-East-Primary",
1603                          time: "5 min ago",
1604                        },
1605                        {
1606                          type: "info",
1607                          message: "Maintenance scheduled for EU-West-Primary",
1608                          time: "1 hour ago",
1609                        },
1610                        {
1611                          type: "success",
1612                          message: "Backup completed successfully",
1613                          time: "2 hours ago",
1614                        },
1615                        {
1616                          type: "error",
1617                          message: "Failed to start VPS instance",
1618                          time: "3 hours ago",
1619                        },
1620                      ].map((alert, index) => (
1621                        <div
1622                          key={index}
1623                          className="flex items-start space-x-3 p-3 rounded-lg bg-accent/50"
1624                        >
1625                          <div
1626                            className={`w-2 h-2 rounded-full mt-2 ${
1627                              alert.type === "error"
1628                                ? "bg-red-500"
1629                                : alert.type === "warning"
1630                                ? "bg-yellow-500"
1631                                : alert.type === "success"
1632                                ? "bg-green-500"
1633                                : "bg-blue-500"
1634                            }`}
1635                          />
1636                          <div className="flex-1">
1637                            <p className="text-sm font-medium">
1638                              {alert.message}
1639                            </p>
1640                            <p className="text-xs text-muted-foreground">
1641                              {alert.time}
1642                            </p>
1643                          </div>
1644                        </div>
1645                      ))}
1646                    </div>
1647                  </CardContent>
1648                </Card>
1649              </div>
1650            </TabsContent>
1651
1652            {/* Settings Tab */}
1653            <TabsContent value="settings" className="space-y-6">
1654              <h2 className="text-xl font-semibold">System Settings</h2>
1655
1656              <div className="grid gap-6">
1657                <Card>
1658                  <CardHeader>
1659                    <CardTitle>General Settings</CardTitle>
1660                    <CardDescription>
1661                      Configure general system preferences
1662                    </CardDescription>
1663                  </CardHeader>
1664                  <CardContent className="space-y-4">
1665                    <div className="flex items-center justify-between">
1666                      <div>
1667                        <Label htmlFor="auto-backup">Automatic Backups</Label>
1668                        <p className="text-sm text-muted-foreground">
1669                          Enable automatic daily backups
1670                        </p>
1671                      </div>
1672                      <Switch id="auto-backup" defaultChecked />
1673                    </div>
1674                    <div className="flex items-center justify-between">
1675                      <div>
1676                        <Label htmlFor="monitoring">Real-time Monitoring</Label>
1677                        <p className="text-sm text-muted-foreground">
1678                          Enable real-time resource monitoring
1679                        </p>
1680                      </div>
1681                      <Switch id="monitoring" defaultChecked />
1682                    </div>
1683                    <div className="flex items-center justify-between">
1684                      <div>
1685                        <Label htmlFor="notifications">
1686                          Email Notifications
1687                        </Label>
1688                        <p className="text-sm text-muted-foreground">
1689                          Receive email alerts for system events
1690                        </p>
1691                      </div>
1692                      <Switch id="notifications" defaultChecked />
1693                    </div>
1694                  </CardContent>
1695                </Card>
1696
1697                <Card>
1698                  <CardHeader>
1699                    <CardTitle>Resource Limits</CardTitle>
1700                    <CardDescription>
1701                      Set default resource allocation limits
1702                    </CardDescription>
1703                  </CardHeader>
1704                  <CardContent className="space-y-4">
1705                    <div className="grid grid-cols-3 gap-4">
1706                      <div>
1707                        <Label htmlFor="max-cpu">Max CPU per Shared VPS</Label>
1708                        <Input id="max-cpu" type="number" defaultValue="8" />
1709                      </div>
1710                      <div>
1711                        <Label htmlFor="max-ram">
1712                          Max RAM per Shared VPS (GB)
1713                        </Label>
1714                        <Input id="max-ram" type="number" defaultValue="16" />
1715                      </div>
1716                      <div>
1717                        <Label htmlFor="max-storage">
1718                          Max Storage per Shared VPS (GB)
1719                        </Label>
1720                        <Input
1721                          id="max-storage"
1722                          type="number"
1723                          defaultValue="200"
1724                        />
1725                      </div>
1726                    </div>
1727                  </CardContent>
1728                </Card>
1729              </div>
1730            </TabsContent>
1731          </Tabs>
1732        </main>
1733      </div>
1734    </div>
1735  );
1736};
1737
1738export default VPSAdminDashboard;

Dependencies

External Libraries

framer-motionlucide-reactreact

Shadcn/UI Components

badgebuttoncarddialoginputlabelprogressselectseparatorswitchtabstextarea

LICENSE

MIT License

Copyright (c) 2025 Aldhaneka

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Shadcn Vaults Project (CC BY-NC 4.0 with Internal Use Exception)

All user-submitted components in the '/blocks' directory are licensed under the Creative Commons Attribution-NonCommercial 4.0 International License (CC BY-NC 4.0),
with the following clarification and exception:

You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material

Under these conditions:
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
- NonCommercial — You may NOT use the material for commercial redistribution, resale, or monetization.

🚫 You MAY NOT:
- Sell or redistribute the components individually or as part of a product (e.g. a UI kit, template marketplace, SaaS component library)
- Offer the components or derivative works in any paid tool, theme pack, or design system

✅ You MAY:
- Use the components in internal company tools, dashboards, or applications that are not sold as products
- Remix or adapt components for private or enterprise projects
- Use them in open-source non-commercial projects

This license encourages sharing, learning, and internal innovation — but prohibits using these components as a basis for monetized products.

Full license text: https://creativecommons.org/licenses/by-nc/4.0/

By submitting a component, contributors agree to these terms.

For questions about licensing, please contact the project maintainers.