From 62dc39837e317fcac5e3f76a59e1d5f14f4daa19 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:10:49 +0330 Subject: [PATCH] Import source: src/components/features/feature-page Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- src/components/features/feature-page.tsx | 1516 ++++++++++++++++++++++ 1 file changed, 1516 insertions(+) create mode 100644 src/components/features/feature-page.tsx diff --git a/src/components/features/feature-page.tsx b/src/components/features/feature-page.tsx new file mode 100644 index 0000000..2c2ccaa --- /dev/null +++ b/src/components/features/feature-page.tsx @@ -0,0 +1,1516 @@ +"use client"; + +import dynamic from "next/dynamic"; +import Link from "next/link"; +import type { ColumnDef } from "@tanstack/react-table"; +import { useQuery } from "@tanstack/react-query"; +import { formatDistanceToNow } from "date-fns"; +import { + AtSign, + CheckCircle2, + Clock3, + Cpu, + Database, + ExternalLink, + FileText, + FolderOpen, + Gauge, + Globe2, + HardDrive, + KeyRound, + Mail, + Network, + Palette, + Plus, + Server, + Settings, + Shield, + Terminal, +} from "lucide-react"; +import type { LucideIcon } from "lucide-react"; +import { ControlShell } from "@/components/shell/control-shell"; +import { PageHeader } from "@/components/common/page-header"; +import { ResourceMeter } from "@/components/common/resource-meter"; +import { StatusBadge } from "@/components/common/status-badge"; +import { DataTable } from "@/components/common/data-table"; +import { + SkeletonPanel, + ErrorState, + PermissionDeniedState, +} from "@/components/common/loading-states"; +import { DangerousActionDialog } from "@/components/common/confirm-dialog"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Progress } from "@/components/ui/progress"; +import { Input } from "@/components/ui/input"; +import { panelService } from "@/api/services/panel-service"; +import type { + AuditEntry, + Automation, + Backup, + Database as DatabaseModel, + DatabaseAdminTool, + Domain, + DockerContainer, + Mailbox, + NginxSite, + RuntimeDefinition, + SecurityFinding, + Server as ServerModel, + ServiceStatus, + Website, +} from "@/api/contracts/models"; +import { can } from "@/lib/permissions"; +import { findRoute, groupRoutes, routeItems } from "@/lib/routes"; +import { cn, formatBytes, titleize } from "@/lib/utils"; + +const TerminalPanel = dynamic( + () => import("@/components/common/terminal-panel").then((mod) => mod.TerminalPanel), + { ssr: false, loading: () => }, +); +const AppearanceSettings = dynamic( + () => + import("@/components/features/appearance-settings").then((mod) => mod.AppearanceSettings), + { ssr: false, loading: () => }, +); +const DnsEditor = dynamic( + () => import("@/components/features/dns-editor").then((mod) => mod.DnsEditor), + { ssr: false, loading: () => }, +); +const FileManager = dynamic( + () => import("@/components/features/file-manager").then((mod) => mod.FileManager), + { ssr: false, loading: () => }, +); +const ToolLauncher = dynamic( + () => import("@/components/features/tool-launcher").then((mod) => mod.ToolLauncher), + { ssr: false, loading: () => }, +); +const UsageChart = dynamic( + () => import("@/components/features/charts").then((mod) => mod.UsageChart), + { ssr: false, loading: () => }, +); +const TrafficChart = dynamic( + () => import("@/components/features/charts").then((mod) => mod.TrafficChart), + { ssr: false, loading: () => }, +); +const WizardForm = dynamic( + () => import("@/components/features/wizard-form").then((mod) => mod.WizardForm), + { ssr: false, loading: () => }, +); + +const websiteColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Website" }, + { accessorKey: "domain", header: "Domain" }, + { accessorKey: "runtime", header: "Runtime" }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { + accessorKey: "ssl", + header: "SSL", + cell: ({ row }) => , + }, + { + accessorKey: "lastDeployment", + header: "Last deployment", + cell: ({ row }) => timeAgo(row.original.lastDeployment), + }, +]; + +const domainColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Domain" }, + { accessorKey: "type", header: "Type" }, + { accessorKey: "documentRoot", header: "Document root" }, + { + accessorKey: "sslStatus", + header: "SSL", + cell: ({ row }) => , + }, + { + accessorKey: "propagation", + header: "Propagation", + cell: ({ row }) => `${row.original.propagation}%`, + }, +]; + +const databaseColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Database" }, + { accessorKey: "engine", header: "Engine" }, + { accessorKey: "size", header: "Size", cell: ({ row }) => formatBytes(row.original.size) }, + { accessorKey: "tables", header: "Tables" }, + { accessorKey: "connections", header: "Connections" }, + { + accessorKey: "lastBackup", + header: "Last backup", + cell: ({ row }) => timeAgo(row.original.lastBackup), + }, +]; + +const mailboxColumns: ColumnDef[] = [ + { accessorKey: "address", header: "Address" }, + { accessorKey: "domain", header: "Domain" }, + { + accessorKey: "used", + header: "Storage", + cell: ({ row }) => `${formatBytes(row.original.used)} / ${formatBytes(row.original.quota)}`, + }, + { + accessorKey: "forwarding", + header: "Forwarding", + cell: ({ row }) => (row.original.forwarding ? "Enabled" : "Disabled"), + }, + { + accessorKey: "authStatus", + header: "Auth", + cell: ({ row }) => , + }, +]; + +const securityColumns: ColumnDef[] = [ + { + accessorKey: "severity", + header: "Severity", + cell: ({ row }) => ( + + {row.original.severity} + + ), + }, + { accessorKey: "title", header: "Finding" }, + { accessorKey: "target", header: "Target" }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { accessorKey: "recommendation", header: "Recommendation" }, +]; + +const backupColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Backup" }, + { accessorKey: "scope", header: "Scope" }, + { accessorKey: "destination", header: "Destination" }, + { accessorKey: "size", header: "Size", cell: ({ row }) => formatBytes(row.original.size) }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { + accessorKey: "createdAt", + header: "Created", + cell: ({ row }) => timeAgo(row.original.createdAt), + }, +]; + +const automationColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Workflow" }, + { accessorKey: "trigger", header: "Trigger" }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { + accessorKey: "successRate", + header: "Success", + cell: ({ row }) => `${row.original.successRate}%`, + }, + { + accessorKey: "lastRun", + header: "Last run", + cell: ({ row }) => timeAgo(row.original.lastRun), + }, +]; + +const auditColumns: ColumnDef[] = [ + { accessorKey: "actor", header: "Actor" }, + { accessorKey: "action", header: "Action" }, + { accessorKey: "target", header: "Target" }, + { accessorKey: "ipAddress", header: "IP address" }, + { accessorKey: "requestId", header: "Request ID" }, + { + accessorKey: "createdAt", + header: "Created", + cell: ({ row }) => timeAgo(row.original.createdAt), + }, +]; + +const serverColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Server" }, + { accessorKey: "hostname", header: "Hostname" }, + { accessorKey: "os", header: "OS" }, + { accessorKey: "panelVersion", header: "Panel version" }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { accessorKey: "location", header: "Location" }, +]; + +const runtimeColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Runtime" }, + { + accessorKey: "versions", + header: "Versions", + cell: ({ row }) => row.original.versions.join(", "), + }, + { + accessorKey: "extensions", + header: "Extensions", + cell: ({ row }) => row.original.extensions.join(", "), + }, + { + accessorKey: "processManagers", + header: "Process managers", + cell: ({ row }) => row.original.processManagers.join(", "), + }, +]; + +const serviceColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Service" }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { accessorKey: "uptime", header: "Uptime" }, + { accessorKey: "detail", header: "Detail" }, +]; + +const nginxColumns: ColumnDef[] = [ + { + accessorKey: "serverNames", + header: "Server names", + cell: ({ row }) => row.original.serverNames.join(", ") || "(default)", + }, + { + accessorKey: "listens", + header: "Listen", + cell: ({ row }) => row.original.listens.join(", "), + }, + { + accessorKey: "proxyPasses", + header: "Proxy targets", + cell: ({ row }) => row.original.proxyPasses.join(", ") || row.original.root || "static", + }, + { + accessorKey: "tls", + header: "TLS", + cell: ({ row }) => ( + + {row.original.tls ? "enabled" : "not detected"} + + ), + }, +]; + +const dockerColumns: ColumnDef[] = [ + { accessorKey: "name", header: "Container" }, + { accessorKey: "image", header: "Image" }, + { accessorKey: "status", header: "Status" }, + { accessorKey: "ports", header: "Ports" }, +]; + +function timeAgo(value: string) { + return `${formatDistanceToNow(new Date(value))} ago`; +} + +export function FeaturePage({ path }: { path: string }) { + const route = findRoute(path) ?? routeItems.find((item) => item.path === "/dashboard")!; + const { data } = useQuery({ queryKey: ["me"], queryFn: () => panelService.auth.me() }); + const permissions = data?.data?.permissions ?? []; + const allowed = !data?.data || can(permissions, route.permission); + const breadcrumbs = [ + { label: "Home", href: "/dashboard" }, + { label: route.category }, + { label: route.label }, + ]; + + return ( + + + {!allowed ? : } + + ); +} + +function RouteContent({ path }: { path: string }) { + if (path === "/dashboard") return ; + if (path === "/tools") return ; + if (path === "/files") return ; + if (path.endsWith("/dns")) return ; + if (path === "/advanced/terminal") return ; + if (path === "/websites/new") return ; + if (path === "/databases/new") return ; + if (["/databases/phpmyadmin", "/databases/adminer", "/databases/pgadmin"].includes(path)) { + return ; + } + if (path === "/backups/new") return ; + if (path === "/automation/new") return ; + if (path === "/restore") return ; + if (path === "/roles") return ; + if (path === "/settings") return ; + if (path === "/security") return ; + if (path.includes("/logs") || path === "/advanced/logs") return ; + return ; +} + +function DashboardPage() { + const { data, isLoading, error, refetch } = useQuery({ + queryKey: ["dashboard-summary"], + queryFn: () => panelService.dashboard.summary(), + }); + if (isLoading) return ; + if (error || data?.error || !data?.data) { + return ( + void refetch()} + /> + ); + } + const summary = data.data; + const stats: Array<[string, string, LucideIcon]> = [ + ["Username", summary.account.username, AtSign], + ["Primary domain", summary.account.primaryDomain, Globe2], + ["Home directory", summary.account.homeDirectory, FolderOpen], + ["Shared IP", summary.account.sharedIp, Network], + ["Dedicated IP", summary.account.dedicatedIp ?? "Not assigned", Server], + ["Last login", timeAgo(summary.user.lastLogin), Clock3], + ["Theme", summary.account.theme, Palette], + ["Server", summary.server.name, Cpu], + ]; + return ( +
+
+
+ {stats.map(([label, value, Icon]) => ( + + +
+
{label}
+
{value}
+
+ + + +
+
+ ))} +
+ + +
+ +
+ ); +} + +const dashboardGroups = ["Email", "Files", "Domains", "Databases", "Security", "Advanced"]; + +/** + * cPanel Jupiter-style grouped tool grid: each category renders as a glass + * card with a dense grid of icon links into the matching module pages. + */ +function DashboardToolGroups() { + const grouped = groupRoutes(routeItems); + return ( +
+ {dashboardGroups + .map((group) => [group, grouped[group] ?? []] as const) + .filter(([, tools]) => tools.length) + .map(([group, tools]) => { + const HeaderIcon = tools[0]?.icon ?? Settings; + return ( + + + + + + {group} + + + {tools.slice(0, 9).map((tool) => { + const Icon = tool.icon; + return ( + + + {tool.label} + + ); + })} + + + ); + })} +
+ ); +} + +function ModulePage({ path }: { path: string }) { + const route = findRoute(path); + const category = route?.category ?? "Module"; + const table = useModuleTable(category, path); + return ( +
+
+ + {category === "Server Administration" || path.startsWith("/servers") ? ( + + ) : null} + + {category === "Metrics" ? : null} + {table} +
+ +
+ ); +} + +function SystemDiscoveryPanel() { + const { data, isLoading, error, refetch } = useQuery({ + queryKey: ["system-discovery"], + queryFn: () => panelService.system.discovery(), + }); + + if (isLoading) return ; + if (error || data?.error || !data?.data) { + return ( + void refetch()} + /> + ); + } + + const discovery = data.data; + return ( +
+ + +
+ Live host discovery + + Read-only Nginx and Docker detection for this CoaxysPanel host. + +
+ detected +
+ + {[ + ["Panel host", discovery.currentPanel.hostname], + ["Frontend proxy", discovery.currentPanel.frontend], + ["Backend proxy", discovery.currentPanel.backend], + ["Nginx sites", String(discovery.nginx.sites.length)], + ["Docker containers", String(discovery.docker.containers.length)], + ["Detected", timeAgo(discovery.detectedAt)], + ].map(([label, value]) => ( +
+
{label}
+
{value}
+
+ ))} +
+
+
+ + + Nginx sites + Parsed from the active Nginx configuration. + + + + + + + + Docker containers + + Currently running containers detected on the host. + + + + + + +
+
+ ); +} + +function DatabaseAdminToolsPage({ selectedPath }: { selectedPath: string }) { + const { data, isLoading, error, refetch } = useQuery({ + queryKey: ["database-admin-tools"], + queryFn: () => panelService.databases.adminTools(), + }); + const selected = selectedPath.split("/").pop(); + const tools = data?.data ?? []; + + if (isLoading) return ; + if (error || data?.error) { + return ( + void refetch()} + /> + ); + } + + return ( +
+
+ + + Database administration launchers + + Open database administration tools without exposing database credentials in + CoaxysPanel. + + + + {tools.map((tool) => ( + + ))} + + + +
+ + + Connection notes + + phpMyAdmin is reverse-proxied at this panel hostname. + + + +
+
Launch URL
+
+ https://cp.asabbagh.com/phpmyadmin/ +
+
+

+ Use a real database user such as an application database account. CoaxysPanel does + not show stored database passwords. +

+
+
+
+ ); +} + +function AdminToolCard({ + tool, + highlighted, +}: { + tool: DatabaseAdminTool; + highlighted: boolean; +}) { + return ( + + +
+ + + + + {tool.status} + +
+
+

{tool.name}

+

{tool.engine}

+
+

{tool.note}

+
+ {tool.launchUrl ? ( + + ) : ( + + )} +
+
+
+ ); +} + +function FeaturedRecords({ category }: { category: string }) { + const records: Record = { + Email: ["admin@example.com", "support@example.com", "DKIM aligned", "Queue: 14 deferred"], + Databases: ["coaxys_wp", "coaxys_app", "Remote access restricted", "Last backup verified"], + Websites: ["example.com", "docs.example.com", "Staging available", "Rollback ready"], + Security: ["Security score", "Firewall active", "Malware scan clean", "API tokens scoped"], + }; + const items = records[category]; + if (!items) return null; + return ( + + + {items.map((item) => ( +
+ {item} +
+ ))} +
+
+ ); +} + +function MetricsCharts() { + const { data } = useQuery({ + queryKey: ["metrics-history"], + queryFn: () => panelService.metrics.history(), + }); + const points = data?.data ?? []; + if (!points.length) return null; + return ( +
+ + +
+ ); +} + +function ModuleOverview({ category, path }: { category: string; path: string }) { + const route = findRoute(path); + const Icon = route?.icon ?? Settings; + const featureNames = featureMap[category] ?? featureMap.default; + return ( + + +
+ + + {route?.label ?? titleize(path)} + + {route?.description} +
+ {route?.danger ? ( + + ) : ( + + )} +
+ + {featureNames.map((feature) => ( +
+ + {feature} +
+ ))} +
+
+ ); +} + +function useModuleTable(category: string, path: string) { + if (category === "Websites") + return ( + panelService.websites.list()} + columns={websiteColumns} + search="Search websites" + /> + ); + if (category === "Domains") + return ( + panelService.domains.list()} + columns={domainColumns} + search="Search domains" + /> + ); + if (category === "Databases") + return ( + panelService.databases.list()} + columns={databaseColumns} + search="Search databases" + /> + ); + if (category === "Email") + return ( + panelService.email.list()} + columns={mailboxColumns} + search="Search mailboxes" + /> + ); + if (category === "Security") + return ( + panelService.security.findings()} + columns={securityColumns} + search="Search findings" + /> + ); + if (category === "Backups") + return ( + panelService.backups.list()} + columns={backupColumns} + search="Search backups" + /> + ); + if (category === "Automation") + return ( + panelService.automation.list()} + columns={automationColumns} + search="Search workflows" + /> + ); + if (category === "Audit") + return ( + panelService.audit.list()} + columns={auditColumns} + search="Search audit logs" + /> + ); + if (category === "Server Administration" || path.startsWith("/servers")) + return ( + panelService.servers.list()} + columns={serverColumns} + search="Search servers" + /> + ); + if (category === "Software") + return ( + panelService.software.runtimes()} + columns={runtimeColumns} + search="Search runtimes" + /> + ); + if (category === "Advanced" || path.includes("services")) + return ( + panelService.servers.services()} + columns={serviceColumns} + search="Search services" + /> + ); + return ; +} + +function QueryTable({ + queryKey, + queryFn, + columns, + search, +}: { + queryKey: string[]; + queryFn: () => Promise<{ data: T[] | null; error: unknown }>; + columns: ColumnDef[]; + search: string; +}) { + const { data, isLoading, error, refetch } = useQuery({ queryKey, queryFn }); + if (isLoading) return ; + if (error || data?.error) + return ( + void refetch()} + /> + ); + return ; +} + +function GenericOperationsTable() { + const rows = [ + { + name: "General settings", + status: "healthy", + owner: "coaxys", + updated: "2026-06-12 10:14 UTC", + }, + { + name: "Feature policy", + status: "healthy", + owner: "server-admin", + updated: "2026-06-11 18:22 UTC", + }, + { + name: "Notification route", + status: "warning", + owner: "support", + updated: "2026-06-10 09:01 UTC", + }, + ]; + const columns: ColumnDef<(typeof rows)[number]>[] = [ + { accessorKey: "name", header: "Name" }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => , + }, + { accessorKey: "owner", header: "Owner" }, + { accessorKey: "updated", header: "Updated" }, + ]; + return ; +} + +function RightPanel({ category, path }: { category: string; path: string }) { + return ( + + ); +} + +function LogsPage() { + const lines = Array.from({ length: 120 }, (_, index) => { + const level = index % 17 === 0 ? "error" : index % 7 === 0 ? "warn" : "info"; + return `[2026-06-12T${String(index % 24).padStart(2, "0")}:14:22Z] ${level} request_id=req_${index.toString(16)} path=/index.php status=${level === "error" ? 500 : 200}`; + }); + return ( +
+ + + + + + + + + + + {lines.map((line) => { + const level = line.includes(" error ") + ? "error" + : line.includes(" warn ") + ? "warn" + : "info"; + return ( +
+ {line} +
+ ); + })} +
+
+
+ ); +} + +function AutomationBuilder() { + const nodes = [ + ["Trigger", "Git push, schedule, webhook, backup completion"], + ["Condition", "Branch, environment, status, resource threshold"], + ["Action", "Deploy, backup, notify, issue certificate, run mock task"], + ["Branch", "Production approval and staging path"], + ]; + return ( +
+ + + Visual workflow builder + + Build triggers, conditions, actions, branches, validation, test mode, and execution + preview. + + + + {nodes.map(([title, description], index) => ( +
+ + {index + 1} + +

{title}

+

{description}

+
+ ))} +
+
+ + + Execution preview + + + + + + + +
+ ); +} + +function RestorePage() { + return ( +
+ + + + Danger zone + + Restores require typed confirmation and mock two-factor approval. + + + + + + +
+ ); +} + +function SecurityDashboard() { + return ( +
+
+ {[ + ["Security score", "86/100", Shield], + ["Critical findings", "0", CheckCircle2], + ["Blocked IPs", "38", Network], + ["Failed logins", "12", KeyRound], + ].map(([label, value, Icon]) => ( + + +
+
{String(label)}
+
+ {String(value)} +
+
+ + + +
+
+ ))} +
+ +
+ ); +} + +function PermissionMatrix() { + const modules = routeItems.filter( + (item, index, array) => + array.findIndex((entry) => entry.permission === item.permission) === index, + ); + const roles = [ + "Super administrator", + "Server administrator", + "Reseller", + "Hosting account owner", + "Developer", + "Billing viewer", + "Support operator", + "Read-only auditor", + "Custom role", + ]; + return ( + + + Permission editor + + Detailed module access matrix for built-in and custom roles. + + + + + + + + {roles.map((role) => ( + + ))} + + + + {modules.map((module) => ( + + + {roles.map((role, index) => ( + + ))} + + ))} + +
+ Module + + {role} +
+ {module.category} + + +
+
+
+ ); +} + +function SettingsPage() { + return ( +
+ + +
+ ); +} + +function SettingsFormPanels() { + return ( +
+ + + Panel settings + + Branding, theme, locale, security, notifications, defaults, APIs, privacy, and + maintenance. + + + + {[ + "Branding", + "Logo upload", + "Accent color", + "Locale", + "Date and time format", + "Session timeout", + "Password policy", + "Two-factor policy", + "Email settings", + "Backup defaults", + "DNS defaults", + "SSL defaults", + "Runtime defaults", + "File-manager settings", + "API settings", + "Feature flags", + "Privacy", + "Data retention", + "Maintenance mode", + ].map((item) => ( + + ))} + + + + + Live branding preview + + +
+
+
+ CP +
+
+
CoaxysPanel
+
+ Server Hosting Control Center +
+
+
+ +
+
+
+
+ ); +} + +const websiteSteps = [ + "General information", + "Domain selection", + "Runtime", + "Repository or upload", + "Database", + "Environment variables", + "Resource limits", + "SSL", + "Backup policy", + "Review and create", +]; + +const databaseSteps = [ + "Database name", + "User", + "Password", + "Permissions", + "Remote access", + "Backup policy", + "Confirmation", +]; + +const backupSteps = [ + "Scope", + "Destination", + "Schedule", + "Retention", + "Encryption", + "Verification", + "Review", +]; + +const featureMap: Record = { + Websites: [ + "Website list", + "Runtime configuration", + "Deployment history", + "Logs", + "Cloning", + "Staging", + "Maintenance mode", + "SSL assignment", + "Rollback", + ], + Domains: [ + "Domains", + "Subdomains", + "Aliases", + "Redirects", + "DNSSEC", + "Nameservers", + "Propagation status", + "Certificate status", + ], + Databases: [ + "Database wizard", + "Users", + "Privilege matrix", + "Remote access", + "Backups", + "Restore", + "Active connections", + "Slow queries", + ], + Email: [ + "Mailboxes", + "Forwarders", + "Routing", + "Filters", + "DKIM", + "SPF", + "DMARC", + "Queue", + "Client configuration", + ], + Metrics: [ + "Visitors", + "Access logs", + "Error logs", + "Bandwidth", + "Resource usage", + "Top URLs", + "Top countries", + "SSL timeline", + ], + Security: [ + "SSL/TLS", + "SSH", + "Firewall", + "Malware scanning", + "Security score", + "Passkeys", + "API tokens", + "Sessions", + ], + Software: [ + "PHP manager", + "Node.js manager", + "Python manager", + "Docker apps", + "Composer", + "npm scripts", + "Redis", + "OPcache", + ], + Advanced: [ + "Cron jobs", + "DNS lookup", + "Terminal", + "Log viewer", + "Queue manager", + "API explorer", + "Timezone", + "Maintenance", + ], + "Server Administration": [ + "Server overview", + "Services", + "Processes", + "Network", + "Updates", + "Filesystem mounts", + "Cluster", + "Migration", + ], + Users: [ + "Hosting users", + "Team members", + "Roles", + "Invitations", + "Impersonation", + "Suspensions", + "Migration", + "Sessions", + ], + Resellers: [ + "Reseller accounts", + "Packages", + "Quotas", + "Feature lists", + "Ownership transfer", + "Account migration", + ], + Backups: [ + "Full backup", + "Website backup", + "Database backup", + "Email backup", + "Snapshots", + "Retention", + "Destinations", + "Verification", + ], + Automation: [ + "Scheduled tasks", + "Pipelines", + "Webhooks", + "Triggers", + "Conditions", + "Actions", + "Retry policies", + "Execution history", + ], + Notifications: [ + "Notification center", + "Read state", + "Categories", + "Preferences", + "Email settings", + "Webhooks", + "Critical alerts", + ], + Support: [ + "Documentation", + "Knowledge base", + "Diagnostics", + "Tickets", + "Replies", + "Attachments", + "Diagnostic report", + ], + Preferences: [ + "Branding", + "Theme", + "Locale", + "Session timeout", + "Security defaults", + "Feature flags", + "Privacy", + ], + default: [ + "Search", + "Filtering", + "Sorting", + "Bulk operations", + "Validation", + "Loading states", + "Error states", + "Permission states", + ], +};