From e1eff2baf8e3d5ad12017daa2bbf3ae6a3bcd7c9 Mon Sep 17 00:00:00 2001 From: Kyle Duren Date: Sun, 27 Apr 2025 20:29:09 -0400 Subject: [PATCH 01/54] Update app-sidebar.tsx to open github in new page Made the github link open in a new page, and also not send the referrer, since this is probably running on an internal system, we don't need to send github all our internal hostname info. --- components/app-sidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index 4291609..ed84762 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -115,7 +115,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { - +
CoreControl Logo
From 07497b1832f222594e0195ce5b19c28d0d053aad Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 19:48:30 +0200 Subject: [PATCH 02/54] add gpuUsage and temp fields to server and server_history models in schema.prisma --- package-lock.json | 19 ++----------------- .../migration.sql | 7 +++++++ prisma/schema.prisma | 4 ++++ 3 files changed, 13 insertions(+), 17 deletions(-) create mode 100644 prisma/migrations/20250428174802_temp_and_gpu_monitoring/migration.sql diff --git a/package-lock.json b/package-lock.json index 8c06500..0494041 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "corecontrol", - "version": "0.0.9", + "version": "0.0.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "corecontrol", - "version": "0.0.9", + "version": "0.0.10", "dependencies": { "@prisma/client": "^6.6.0", "@prisma/extension-accelerate": "^1.3.0", @@ -5073,21 +5073,6 @@ "optional": true } } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.0.tgz", - "integrity": "sha512-vHUQS4YVGJPmpjn7r5lEZuMhK5UQBNBRSB+iGDvJjaNk649pTIcRluDWNb9siunyLLiu/LDPHfvxBtNamyuLTw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } } } } diff --git a/prisma/migrations/20250428174802_temp_and_gpu_monitoring/migration.sql b/prisma/migrations/20250428174802_temp_and_gpu_monitoring/migration.sql new file mode 100644 index 0000000..728d59d --- /dev/null +++ b/prisma/migrations/20250428174802_temp_and_gpu_monitoring/migration.sql @@ -0,0 +1,7 @@ +-- AlterTable +ALTER TABLE "server" ADD COLUMN "gpuUsage" TEXT, +ADD COLUMN "temp" TEXT; + +-- AlterTable +ALTER TABLE "server_history" ADD COLUMN "gpuUsage" TEXT, +ADD COLUMN "temp" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7fd3a93..42d2667 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -40,6 +40,8 @@ model server_history { cpuUsage String? ramUsage String? diskUsage String? + gpuUsage String? + temp String? createdAt DateTime @default(now()) } @@ -63,6 +65,8 @@ model server { diskUsage String? online Boolean @default(true) uptime String? + gpuUsage String? + temp String? } model settings { From 61bf108f40fa761ebd01d630b8c0d2da378ad639 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 19:48:59 +0200 Subject: [PATCH 03/54] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed2e6e3..9d7ddc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "corecontrol", - "version": "0.0.10", + "version": "1.0.0", "private": true, "scripts": { "dev": "next dev --turbopack", From 7fc3703a051aac6a99f3c82d2ec25617cf455749 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 19:53:04 +0200 Subject: [PATCH 04/54] Add gpu & temp models agent --- agent/internal/models/models.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/agent/internal/models/models.go b/agent/internal/models/models.go index 4411255..9c8c3fa 100644 --- a/agent/internal/models/models.go +++ b/agent/internal/models/models.go @@ -21,6 +21,8 @@ type Server struct { CpuUsage sql.NullFloat64 RamUsage sql.NullFloat64 DiskUsage sql.NullFloat64 + GpuUsage sql.NullFloat64 + Temp sql.NullFloat64 Uptime sql.NullString } @@ -51,6 +53,14 @@ type UptimeResponse struct { Value string `json:"value"` } +type GPUResponse struct { + Value float64 `json:"value"` +} + +type TempResponse struct { + Value float64 `json:"value"` +} + type Notification struct { ID int Enabled bool From 934768fec88b22e66a0de05c9ecc811c2245c305 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 20:01:51 +0200 Subject: [PATCH 05/54] GPU & Temp receiving in agent --- agent/internal/models/models.go | 14 ++++- agent/internal/server/monitor.go | 97 +++++++++++++++++++++++++------- 2 files changed, 91 insertions(+), 20 deletions(-) diff --git a/agent/internal/models/models.go b/agent/internal/models/models.go index 9c8c3fa..5a73718 100644 --- a/agent/internal/models/models.go +++ b/agent/internal/models/models.go @@ -54,7 +54,19 @@ type UptimeResponse struct { } type GPUResponse struct { - Value float64 `json:"value"` + Proc float64 `json:"proc"` +} + +type TemperatureResponse struct { + Composite []struct { + Label string `json:"label"` + Unit string `json:"unit"` + Value float64 `json:"value"` + Warning float64 `json:"warning"` + Critical float64 `json:"critical"` + Type string `json:"type"` + Key string `json:"key"` + } `json:"Composite"` } type TempResponse struct { diff --git a/agent/internal/server/monitor.go b/agent/internal/server/monitor.go index 45d2acc..4907fa4 100644 --- a/agent/internal/server/monitor.go +++ b/agent/internal/server/monitor.go @@ -31,16 +31,16 @@ func MonitorServers(db *sql.DB, client *http.Client, servers []models.Server, no fmt.Printf("%s Checking...\n", logPrefix) baseURL := strings.TrimSuffix(server.MonitoringURL.String, "/") - var cpuUsage, ramUsage, diskUsage float64 + var cpuUsage, ramUsage, diskUsage, gpuUsage, temp float64 var online = true var uptimeStr string // Get CPU usage online, cpuUsage = fetchCPUUsage(client, baseURL, logPrefix) if !online { - updateServerStatus(db, server.ID, false, 0, 0, 0, "") + updateServerStatus(db, server.ID, false, 0, 0, 0, 0, 0, "") sendStatusChangeNotification(server, online, notificationTemplate, notifSender) - addServerHistoryEntry(db, server.ID, false, 0, 0, 0) + addServerHistoryEntry(db, server.ID, false, 0, 0, 0, 0, 0) continue } @@ -51,9 +51,9 @@ func MonitorServers(db *sql.DB, client *http.Client, servers []models.Server, no memOnline, memUsage := fetchMemoryUsage(client, baseURL, logPrefix) if !memOnline { online = false - updateServerStatus(db, server.ID, false, 0, 0, 0, "") + updateServerStatus(db, server.ID, false, 0, 0, 0, 0, 0, "") sendStatusChangeNotification(server, online, notificationTemplate, notifSender) - addServerHistoryEntry(db, server.ID, false, 0, 0, 0) + addServerHistoryEntry(db, server.ID, false, 0, 0, 0, 0, 0) continue } ramUsage = memUsage @@ -62,26 +62,34 @@ func MonitorServers(db *sql.DB, client *http.Client, servers []models.Server, no diskOnline, diskUsageVal := fetchDiskUsage(client, baseURL, logPrefix) if !diskOnline { online = false - updateServerStatus(db, server.ID, false, 0, 0, 0, "") + updateServerStatus(db, server.ID, false, 0, 0, 0, 0, 0, "") sendStatusChangeNotification(server, online, notificationTemplate, notifSender) - addServerHistoryEntry(db, server.ID, false, 0, 0, 0) + addServerHistoryEntry(db, server.ID, false, 0, 0, 0, 0, 0) continue } diskUsage = diskUsageVal + // Get GPU usage + _, gpuUsageVal := fetchGPUUsage(client, baseURL, logPrefix) + gpuUsage = gpuUsageVal + + // Get Temperature + _, tempVal := fetchTemperature(client, baseURL, logPrefix) + temp = tempVal + // Check if status changed and send notification if needed if online != server.Online { sendStatusChangeNotification(server, online, notificationTemplate, notifSender) } // Update server status with metrics - updateServerStatus(db, server.ID, online, cpuUsage, ramUsage, diskUsage, uptimeStr) + updateServerStatus(db, server.ID, online, cpuUsage, ramUsage, diskUsage, gpuUsage, temp, uptimeStr) // Add entry to server history - addServerHistoryEntry(db, server.ID, online, cpuUsage, ramUsage, diskUsage) + addServerHistoryEntry(db, server.ID, online, cpuUsage, ramUsage, diskUsage, gpuUsage, temp) - fmt.Printf("%s Updated - CPU: %.2f%%, RAM: %.2f%%, Disk: %.2f%%, Uptime: %s\n", - logPrefix, cpuUsage, ramUsage, diskUsage, uptimeStr) + fmt.Printf("%s Updated - CPU: %.2f%%, RAM: %.2f%%, Disk: %.2f%%, GPU: %.2f%%, Temp: %.2f°C, Uptime: %s\n", + logPrefix, cpuUsage, ramUsage, diskUsage, gpuUsage, temp, uptimeStr) } } @@ -194,6 +202,56 @@ func fetchUptime(client *http.Client, baseURL, logPrefix string) string { return uptimeStr } +// Helper function to fetch GPU usage +func fetchGPUUsage(client *http.Client, baseURL, logPrefix string) (bool, float64) { + gpuResp, err := client.Get(fmt.Sprintf("%s/api/4/gpu", baseURL)) + if err != nil { + fmt.Printf("%s GPU request failed: %v\n", logPrefix, err) + return true, 0 // Return true to indicate server is still online + } + defer gpuResp.Body.Close() + + if gpuResp.StatusCode != http.StatusOK { + fmt.Printf("%s Bad GPU status code: %d\n", logPrefix, gpuResp.StatusCode) + return true, 0 // Return true to indicate server is still online + } + + var gpuData models.GPUResponse + if err := json.NewDecoder(gpuResp.Body).Decode(&gpuData); err != nil { + fmt.Printf("%s Failed to parse GPU JSON: %v\n", logPrefix, err) + return true, 0 // Return true to indicate server is still online + } + + return true, gpuData.Proc +} + +// Helper function to fetch temperature +func fetchTemperature(client *http.Client, baseURL, logPrefix string) (bool, float64) { + tempResp, err := client.Get(fmt.Sprintf("%s/api/4/sensors/label/value/Composite", baseURL)) + if err != nil { + fmt.Printf("%s Temperature request failed: %v\n", logPrefix, err) + return true, 0 // Return true to indicate server is still online + } + defer tempResp.Body.Close() + + if tempResp.StatusCode != http.StatusOK { + fmt.Printf("%s Bad temperature status code: %d\n", logPrefix, tempResp.StatusCode) + return true, 0 // Return true to indicate server is still online + } + + var tempData models.TemperatureResponse + if err := json.NewDecoder(tempResp.Body).Decode(&tempData); err != nil { + fmt.Printf("%s Failed to parse temperature JSON: %v\n", logPrefix, err) + return true, 0 // Return true to indicate server is still online + } + + if len(tempData.Composite) > 0 { + return true, tempData.Composite[0].Value + } + + return true, 0 +} + // Helper function to send notification about status change func sendStatusChangeNotification(server models.Server, online bool, template string, notifSender *notifications.NotificationSender) { status := "offline" @@ -208,14 +266,14 @@ func sendStatusChangeNotification(server models.Server, online bool, template st } // Helper function to update server status -func updateServerStatus(db *sql.DB, serverID int, online bool, cpuUsage, ramUsage, diskUsage float64, uptime string) { +func updateServerStatus(db *sql.DB, serverID int, online bool, cpuUsage, ramUsage, diskUsage, gpuUsage, temp float64, uptime string) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _, err := db.ExecContext(ctx, - `UPDATE server SET online = $1, "cpuUsage" = $2::float8, "ramUsage" = $3::float8, "diskUsage" = $4::float8, "uptime" = $5 - WHERE id = $6`, - online, cpuUsage, ramUsage, diskUsage, uptime, serverID, + `UPDATE server SET online = $1, "cpuUsage" = $2::float8, "ramUsage" = $3::float8, "diskUsage" = $4::float8, "gpuUsage" = $5::float8, "temp" = $6::float8, "uptime" = $7 + WHERE id = $8`, + online, cpuUsage, ramUsage, diskUsage, gpuUsage, temp, uptime, serverID, ) if err != nil { fmt.Printf("Failed to update server status (ID: %d): %v\n", serverID, err) @@ -223,15 +281,16 @@ func updateServerStatus(db *sql.DB, serverID int, online bool, cpuUsage, ramUsag } // Helper function to add server history entry -func addServerHistoryEntry(db *sql.DB, serverID int, online bool, cpuUsage, ramUsage, diskUsage float64) { +func addServerHistoryEntry(db *sql.DB, serverID int, online bool, cpuUsage, ramUsage, diskUsage, gpuUsage, temp float64) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _, err := db.ExecContext(ctx, `INSERT INTO server_history( - "serverId", online, "cpuUsage", "ramUsage", "diskUsage", "createdAt" - ) VALUES ($1, $2, $3, $4, $5, now())`, - serverID, online, fmt.Sprintf("%.2f", cpuUsage), fmt.Sprintf("%.2f", ramUsage), fmt.Sprintf("%.2f", diskUsage), + "serverId", online, "cpuUsage", "ramUsage", "diskUsage", "gpuUsage", "temp", "createdAt" + ) VALUES ($1, $2, $3, $4, $5, $6, $7, now())`, + serverID, online, fmt.Sprintf("%.2f", cpuUsage), fmt.Sprintf("%.2f", ramUsage), + fmt.Sprintf("%.2f", diskUsage), fmt.Sprintf("%.2f", gpuUsage), fmt.Sprintf("%.2f", temp), ) if err != nil { fmt.Printf("Failed to insert server history (ID: %d): %v\n", serverID, err) From c9f1d32038fcf66ac749838558a41d6f40e2b0ee Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 20:12:46 +0200 Subject: [PATCH 06/54] Update API Routes to include Temp & GPU Data --- app/api/servers/get/route.ts | 18 ++++++++++++++++++ app/api/servers/monitoring/route.ts | 12 +++++++++--- package-lock.json | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/app/api/servers/get/route.ts b/app/api/servers/get/route.ts index 08533c7..ac17d42 100644 --- a/app/api/servers/get/route.ts +++ b/app/api/servers/get/route.ts @@ -132,6 +132,8 @@ export async function POST(request: NextRequest) { cpu: number[], ram: number[], disk: number[], + gpu: number[], + temp: number[], online: boolean[] }>(); @@ -142,6 +144,8 @@ export async function POST(request: NextRequest) { cpu: [], ram: [], disk: [], + gpu: [], + temp: [], online: [] }); }); @@ -167,6 +171,8 @@ export async function POST(request: NextRequest) { interval.cpu.push(parseUsageValue(record.cpuUsage)); interval.ram.push(parseUsageValue(record.ramUsage)); interval.disk.push(parseUsageValue(record.diskUsage)); + interval.gpu.push(parseUsageValue(record.gpuUsage)); + interval.temp.push(parseUsageValue(record.temp)); interval.online.push(record.online); } }); @@ -178,6 +184,8 @@ export async function POST(request: NextRequest) { cpu: [], ram: [], disk: [], + gpu: [], + temp: [], online: [] }; @@ -189,6 +197,8 @@ export async function POST(request: NextRequest) { cpu: average(data.cpu), ram: average(data.ram), disk: average(data.disk), + gpu: average(data.gpu), + temp: average(data.temp), online: data.online.length ? data.online.filter(Boolean).length / data.online.length >= 0.5 : null @@ -221,6 +231,14 @@ export async function POST(request: NextRequest) { const data = historyMap.get(d.toISOString())?.disk || []; return data.length ? Math.round((data.reduce((a, b) => a + b) / data.length) * 100) / 100 : null; }), + gpu: intervals.map(d => { + const data = historyMap.get(d.toISOString())?.gpu || []; + return data.length ? Math.round((data.reduce((a, b) => a + b) / data.length) * 100) / 100 : null; + }), + temp: intervals.map(d => { + const data = historyMap.get(d.toISOString())?.temp || []; + return data.length ? Math.round((data.reduce((a, b) => a + b) / data.length) * 100) / 100 : null; + }), online: intervals.map(d => { const data = historyMap.get(d.toISOString())?.online || []; return data.length ? data.filter(Boolean).length / data.length >= 0.5 : null; diff --git a/app/api/servers/monitoring/route.ts b/app/api/servers/monitoring/route.ts index a6b3d7d..2a905d5 100644 --- a/app/api/servers/monitoring/route.ts +++ b/app/api/servers/monitoring/route.ts @@ -11,6 +11,8 @@ export async function GET() { cpuUsage: true, ramUsage: true, diskUsage: true, + gpuUsage: true, + temp: true, uptime: true } }); @@ -21,13 +23,17 @@ export async function GET() { cpuUsage: string | null; ramUsage: string | null; diskUsage: string | null; + gpuUsage: string | null; + temp: string | null; uptime: string | null; }) => ({ id: server.id, online: server.online, - cpuUsage: server.cpuUsage ? parseInt(server.cpuUsage) : 0, - ramUsage: server.ramUsage ? parseInt(server.ramUsage) : 0, - diskUsage: server.diskUsage ? parseInt(server.diskUsage) : 0, + cpuUsage: server.cpuUsage ? parseFloat(server.cpuUsage) : 0, + ramUsage: server.ramUsage ? parseFloat(server.ramUsage) : 0, + diskUsage: server.diskUsage ? parseFloat(server.diskUsage) : 0, + gpuUsage: server.gpuUsage ? parseFloat(server.gpuUsage) : 0, + temp: server.temp ? parseFloat(server.temp) : 0, uptime: server.uptime || "" })); diff --git a/package-lock.json b/package-lock.json index 0494041..e7b3393 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5073,6 +5073,21 @@ "optional": true } } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.0.tgz", + "integrity": "sha512-vHUQS4YVGJPmpjn7r5lEZuMhK5UQBNBRSB+iGDvJjaNk649pTIcRluDWNb9siunyLLiu/LDPHfvxBtNamyuLTw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } From 9a35a6ca509066ad8aee200ef8dfe7bdf8b319ad Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 20:28:52 +0200 Subject: [PATCH 07/54] Add temp & gpu display in servers overview --- app/dashboard/servers/Servers.tsx | 43 ++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx index 24d39e9..cd33bbc 100644 --- a/app/dashboard/servers/Servers.tsx +++ b/app/dashboard/servers/Servers.tsx @@ -27,6 +27,7 @@ import { LucideServer, Copy, History, + Thermometer, } from "lucide-react" import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { @@ -100,6 +101,8 @@ interface Server { history?: ServerHistory; port: number; uptime: string; + gpuUsage?: number; + temp?: number; } interface GetServersResponse { @@ -1116,14 +1119,14 @@ export default function Dashboard() {

Resource Usage

-
+
CPU
- {server.cpuUsage || 0}% + {server.cpuUsage !== null && server.cpuUsage !== undefined ? `${server.cpuUsage}%` : "NO DATA"}
RAM
- {server.ramUsage || 0}% + {server.ramUsage !== null && server.ramUsage !== undefined ? `${server.ramUsage}%` : "NO DATA"}
Disk
- {server.diskUsage || 0}% + {server.diskUsage !== null && server.diskUsage !== undefined ? `${server.diskUsage}%` : "NO DATA"}
+ +
+
+
+ + GPU +
+ {server.gpuUsage !== null && server.gpuUsage !== undefined && server.gpuUsage !== 0 ? `${server.gpuUsage}%` : "NO DATA"} +
+
+
80 ? "bg-destructive" : server.gpuUsage && server.gpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${server.gpuUsage || 0}%` }} + /> +
+
+
+ +
+
+
+ + Temp +
+ {server.temp !== null && server.temp !== undefined && server.temp !== 0 ? `${server.temp}°C` : "NO DATA"} +
+
+
80 ? "bg-destructive" : server.temp && server.temp > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${Math.min(server.temp || 0, 100)}%` }} + /> +
From df2769a322724a65a85c6884cfe42ea47c624d50 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 20:30:51 +0200 Subject: [PATCH 08/54] Tempreture & GPU View in Server Component --- app/dashboard/servers/[server_id]/Server.tsx | 141 ++++++++++++++++++- 1 file changed, 138 insertions(+), 3 deletions(-) diff --git a/app/dashboard/servers/[server_id]/Server.tsx b/app/dashboard/servers/[server_id]/Server.tsx index f93076f..8cce38c 100644 --- a/app/dashboard/servers/[server_id]/Server.tsx +++ b/app/dashboard/servers/[server_id]/Server.tsx @@ -30,6 +30,8 @@ interface ServerHistory { ram: (number | null)[]; disk: (number | null)[]; online: (boolean | null)[]; + gpu: (number | null)[]; + temp: (number | null)[]; } } @@ -54,6 +56,8 @@ interface Server { cpuUsage: number; ramUsage: number; diskUsage: number; + gpuUsage: number; + temp: number; history?: ServerHistory; port: number; uptime?: string; @@ -75,6 +79,8 @@ export default function ServerDetail() { const cpuChartRef = { current: null as Chart | null } const ramChartRef = { current: null as Chart | null } const diskChartRef = { current: null as Chart | null } + const gpuChartRef = { current: null as Chart | null } + const tempChartRef = { current: null as Chart | null } const fetchServerDetails = async () => { try { @@ -105,6 +111,8 @@ export default function ServerDetail() { if (cpuChartRef.current) cpuChartRef.current.destroy(); if (ramChartRef.current) ramChartRef.current.destroy(); if (diskChartRef.current) diskChartRef.current.destroy(); + if (gpuChartRef.current) gpuChartRef.current.destroy(); + if (tempChartRef.current) tempChartRef.current.destroy(); // Wait for DOM to be ready const initTimer = setTimeout(() => { @@ -339,6 +347,105 @@ export default function ServerDetail() { } }) } + + const gpuCanvas = document.getElementById(`gpu-chart`) as HTMLCanvasElement + if (gpuCanvas) { + gpuChartRef.current = new Chart(gpuCanvas, { + type: 'line', + data: { + labels: timeLabels, + datasets: [{ + label: 'GPU Usage', + data: history.datasets.gpu, + borderColor: 'rgb(255, 99, 132)', + backgroundColor: 'rgba(255, 99, 132, 0.1)', + fill: true, + spanGaps: false + }] + }, + options: { + ...commonOptions, + plugins: { + title: { + display: true, + text: 'GPU Usage History', + font: { + size: 14 + } + }, + tooltip: { + callbacks: { + title: function(tooltipItems: any) { + return timeLabels[tooltipItems[0].dataIndex]; + } + } + }, + legend: { + display: false + } + }, + scales: { + ...commonOptions.scales, + y: { + ...commonOptions.scales.y, + max: 100 + } + } + } + }) + } + + const tempCanvas = document.getElementById(`temp-chart`) as HTMLCanvasElement + if (tempCanvas) { + tempChartRef.current = new Chart(tempCanvas, { + type: 'line', + data: { + labels: timeLabels, + datasets: [{ + label: 'Temperature', + data: history.datasets.temp, + borderColor: 'rgb(255, 159, 64)', + backgroundColor: 'rgba(255, 159, 64, 0.1)', + fill: true, + spanGaps: false + }] + }, + options: { + ...commonOptions, + plugins: { + title: { + display: true, + text: 'Temperature History', + font: { + size: 14 + } + }, + tooltip: { + callbacks: { + title: function(tooltipItems: any) { + return timeLabels[tooltipItems[0].dataIndex]; + } + } + }, + legend: { + display: false + } + }, + scales: { + ...commonOptions.scales, + y: { + ...commonOptions.scales.y, + max: 100, + ticks: { + callback: function(value: any) { + return value + '°C'; + } + } + } + } + } + }) + } }, 100); return () => { @@ -346,6 +453,8 @@ export default function ServerDetail() { if (cpuChartRef.current) cpuChartRef.current.destroy(); if (ramChartRef.current) ramChartRef.current.destroy(); if (diskChartRef.current) diskChartRef.current.destroy(); + if (gpuChartRef.current) gpuChartRef.current.destroy(); + if (tempChartRef.current) tempChartRef.current.destroy(); }; }, [server, timeRange]); @@ -496,7 +605,7 @@ export default function ServerDetail() { style={{ width: `${server.cpuUsage}%` }} />
- {server.cpuUsage}% + {server.cpuUsage !== null && server.cpuUsage !== undefined ? `${server.cpuUsage}%` : "NO DATA"}
RAM Usage:
@@ -506,7 +615,7 @@ export default function ServerDetail() { style={{ width: `${server.ramUsage}%` }} />
- {server.ramUsage}% + {server.ramUsage !== null && server.ramUsage !== undefined ? `${server.ramUsage}%` : "NO DATA"}
Disk Usage:
@@ -516,7 +625,27 @@ export default function ServerDetail() { style={{ width: `${server.diskUsage}%` }} />
- {server.diskUsage}% + {server.diskUsage !== null && server.diskUsage !== undefined ? `${server.diskUsage}%` : "NO DATA"} +
+
GPU Usage:
+
+
+
80 ? "bg-destructive" : server.gpuUsage && server.gpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${server.gpuUsage || 0}%` }} + /> +
+ {server.gpuUsage !== null && server.gpuUsage !== undefined && server.gpuUsage !== 0 ? `${server.gpuUsage}%` : "NO DATA"} +
+
Temperature:
+
+
+
80 ? "bg-destructive" : server.temp && server.temp > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${Math.min(server.temp || 0, 100)}%` }} + /> +
+ {server.temp !== null && server.temp !== undefined && server.temp !== 0 ? `${server.temp}°C` : "NO DATA"}
@@ -570,6 +699,12 @@ export default function ServerDetail() {
+
+ +
+
+ +
From 5ba95c4b1ac44299b3c4004056265a21dec0af42 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 21:50:21 +0200 Subject: [PATCH 09/54] Add function if a server has no temp or gpu --- app/dashboard/servers/Servers.tsx | 46 ++++++++++++++------ app/dashboard/servers/[server_id]/Server.tsx | 43 +++++++++++------- 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx index cd33bbc..d02bba1 100644 --- a/app/dashboard/servers/Servers.tsx +++ b/app/dashboard/servers/Servers.tsx @@ -118,6 +118,8 @@ interface MonitoringData { ramUsage: number diskUsage: number uptime: number + gpuUsage?: number + temp?: number } export default function Dashboard() { @@ -239,7 +241,6 @@ export default function Dashboard() { console.log("ID:" + server.id) } setServers(response.data.servers) - console.log(response.data.servers) setMaxPage(response.data.maxPage) setTotalItems(response.data.totalItems) setLoading(false) @@ -437,7 +438,9 @@ export default function Dashboard() { online: serverMonitoring.online, cpuUsage: serverMonitoring.cpuUsage, ramUsage: serverMonitoring.ramUsage, - diskUsage: serverMonitoring.diskUsage + diskUsage: serverMonitoring.diskUsage, + gpuUsage: serverMonitoring.gpuUsage ? Number(serverMonitoring.gpuUsage) : 0, + temp: serverMonitoring.temp ? Number(serverMonitoring.temp) : 0 }; } return server; @@ -1169,13 +1172,21 @@ export default function Dashboard() {
-
-
- - GPU -
- {server.gpuUsage !== null && server.gpuUsage !== undefined && server.gpuUsage !== 0 ? `${server.gpuUsage}%` : "NO DATA"} +
+
+ + GPU
+ + {server.online && + server.gpuUsage && + server.gpuUsage !== null && + server.gpuUsage !== undefined && + server.gpuUsage.toString() !== "0" + ? `${server.gpuUsage}%` + : "NO DATA"} + +
80 ? "bg-destructive" : server.gpuUsage && server.gpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} @@ -1186,13 +1197,20 @@ export default function Dashboard() {
-
-
- - Temp -
- {server.temp !== null && server.temp !== undefined && server.temp !== 0 ? `${server.temp}°C` : "NO DATA"} +
+
+ + Temp
+ + {server.online && + server.temp !== null && + server.temp !== undefined && + server.temp.toString() !== "0" + ? `${server.temp}°C` + : "NO DATA"} + +
80 ? "bg-destructive" : server.temp && server.temp > 60 ? "bg-amber-500" : "bg-emerald-500"}`} diff --git a/app/dashboard/servers/[server_id]/Server.tsx b/app/dashboard/servers/[server_id]/Server.tsx index 8cce38c..172b5f0 100644 --- a/app/dashboard/servers/[server_id]/Server.tsx +++ b/app/dashboard/servers/[server_id]/Server.tsx @@ -627,26 +627,35 @@ export default function ServerDetail() {
{server.diskUsage !== null && server.diskUsage !== undefined ? `${server.diskUsage}%` : "NO DATA"}
-
GPU Usage:
-
-
+ {server.gpuUsage && server.gpuUsage !== null && server.gpuUsage !== undefined && server.gpuUsage.toString() !== "0" && ( + <> +
GPU Usage:
+
+
80 ? "bg-destructive" : server.gpuUsage && server.gpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} style={{ width: `${server.gpuUsage || 0}%` }} />
- {server.gpuUsage !== null && server.gpuUsage !== undefined && server.gpuUsage !== 0 ? `${server.gpuUsage}%` : "NO DATA"} -
-
Temperature:
-
-
+ + {server.gpuUsage && server.gpuUsage !== null && server.gpuUsage !== undefined ? `${server.gpuUsage}%` : "NO DATA"} +
+ + )} + {server.temp && server.temp !== null && server.temp !== undefined && server.temp.toString() !== "0" && ( + <> +
Temperature:
+
+
80 ? "bg-destructive" : server.temp && server.temp > 60 ? "bg-amber-500" : "bg-emerald-500"}`} style={{ width: `${Math.min(server.temp || 0, 100)}%` }} />
{server.temp !== null && server.temp !== undefined && server.temp !== 0 ? `${server.temp}°C` : "NO DATA"} -
+
+ + )}
)} @@ -699,12 +708,16 @@ export default function ServerDetail() {
-
- -
-
- -
+ {server.history?.datasets.gpu.some(value => value !== null && value !== 0) && ( +
+ +
+ )} + {server.history?.datasets.temp.some(value => value !== null && value !== 0) && ( +
+ +
+ )}
From 34493d783ffefcf3fe2a06f3180ba02519c8b44d Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 22:23:50 +0200 Subject: [PATCH 10/54] Serevrs.txt mobile friendly --- app/dashboard/servers/Servers.tsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx index d02bba1..8f45505 100644 --- a/app/dashboard/servers/Servers.tsx +++ b/app/dashboard/servers/Servers.tsx @@ -668,9 +668,9 @@ export default function Dashboard() { - + - + Add a server setIcon(value)}> @@ -977,7 +977,7 @@ export default function Dashboard() {

To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration:

-
+                                  
                                     {`services:
   glances:
     image: nicolargo/glances:latest
@@ -1340,7 +1340,7 @@ export default function Dashboard() {
                                                                 
                                                               
                                                             
-                                                            
+                                                            
                                                               
                                                                 Edit VM
                                                                 
@@ -1349,7 +1349,7 @@ export default function Dashboard() {
                                                                       General
                                                                       Hardware
                                                                       
-                                                                        Virtualization
+                                                                        Host
                                                                       
                                                                     
                                                                     
@@ -1749,7 +1749,7 @@ export default function Dashboard() {
                                 Hidden Trigger
                               
                             
-                            
+                            
                               
                                 Edit {server.name}
                                 
@@ -1757,7 +1757,7 @@ export default function Dashboard() {
                                     
                                       General
                                       Hardware
-                                      Virtualization
+                                      Host
                                       Monitoring
                                     
                                     

From 58bd039635046d1956e6cf26ef8fa905f370e505 Mon Sep 17 00:00:00 2001
From: headlessdev 
Date: Mon, 28 Apr 2025 22:27:39 +0200
Subject: [PATCH 11/54] Applications.tsx mobile friendly

---
 app/dashboard/applications/Applications.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/app/dashboard/applications/Applications.tsx b/app/dashboard/applications/Applications.tsx
index a8377d5..979607a 100644
--- a/app/dashboard/applications/Applications.tsx
+++ b/app/dashboard/applications/Applications.tsx
@@ -498,7 +498,7 @@ export default function Dashboard() {
                       
                     
                   
-                  
+                  
                     
                       Add an application
                       
@@ -761,7 +761,7 @@ export default function Dashboard() {
                                       
                                     
                                   
-                                  
+                                  
                                     
                                       
                                         Edit Application
@@ -961,7 +961,7 @@ export default function Dashboard() {
                                   
                                 
                               
-                              
+                              
                                 
                                   
                                     Edit Application

From ff49825eaba062a169e496680c7ccde3dcf69187 Mon Sep 17 00:00:00 2001
From: headlessdev 
Date: Mon, 28 Apr 2025 23:19:55 +0200
Subject: [PATCH 12/54] i18n implementation & Login i18n

---
 app/layout.tsx         |   6 +-
 app/page.tsx           |  16 ++---
 i18n/languages/en.json |  12 ++++
 i18n/request.ts        |  12 ++++
 next.config.ts         |  14 ++---
 package-lock.json      | 139 ++++++++++++++++++++++++++++++++++++++++-
 package.json           |   1 +
 7 files changed, 183 insertions(+), 17 deletions(-)
 create mode 100644 i18n/languages/en.json
 create mode 100644 i18n/request.ts

diff --git a/app/layout.tsx b/app/layout.tsx
index 332c576..63afec7 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -2,6 +2,8 @@ import type { Metadata } from "next";
 import { Geist, Geist_Mono } from "next/font/google";
 import "./globals.css";
 import { ThemeProvider } from "@/components/theme-provider"
+import {NextIntlClientProvider} from 'next-intl';
+import {getLocale} from 'next-intl/server';
 
 const geistSans = Geist({
   variable: "--font-geist-sans",
@@ -34,7 +36,9 @@ export default function RootLayout({
             enableSystem
             disableTransitionOnChange
           >
-            {children}
+            
+              {children}
+            
           
       
     
diff --git a/app/page.tsx b/app/page.tsx
index e03f7b5..3dfafff 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -14,8 +14,10 @@ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }
 import { Input } from "@/components/ui/input"
 import { Label } from "@/components/ui/label"
 import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
+import {useTranslations} from 'next-intl';
 
 export default function Home() {
+  const t = useTranslations('Home');
   const [username, setUsername] = useState("")
   const [password, setPassword] = useState("")
   const [rememberMe, setRememberMe] = useState(false)
@@ -75,20 +77,20 @@ export default function Home() {
             

CoreControl

-

Sign in to access your dashboard

+

{t('LoginCardDescription')}

- Login - Enter your credentials to continue + {t('LoginCardTitle')} + {t('LoginCardDescription')} {errorVisible && ( - Authentication Error + {t('AuthenticationError')} {error} )} @@ -96,7 +98,7 @@ export default function Home() {
@@ -116,7 +118,7 @@ export default function Home() {
@@ -138,7 +140,7 @@ export default function Home() { diff --git a/i18n/languages/en.json b/i18n/languages/en.json new file mode 100644 index 0000000..5280769 --- /dev/null +++ b/i18n/languages/en.json @@ -0,0 +1,12 @@ +{ + "Home": { + "TitleUnder": "Dashboard to manage your entire server infrastructure", + "LoginCardTitle": "Login", + "LoginCardDescription": "Enter your credentials to continue", + "AuthenticationError": "Authentication Error", + "Email": "Email", + "Password": "Password", + "SigninButton": "Sign in", + "SigninButtonSigningIn": "Signing in..." + } +} \ No newline at end of file diff --git a/i18n/request.ts b/i18n/request.ts new file mode 100644 index 0000000..a299eb7 --- /dev/null +++ b/i18n/request.ts @@ -0,0 +1,12 @@ +import {getRequestConfig} from 'next-intl/server'; + +export default getRequestConfig(async () => { + // Provide a static locale, fetch a user setting, + // read from `cookies()`, `headers()`, etc. + const locale = 'en'; + + return { + locale, + messages: (await import(`./languages/${locale}.json`)).default + }; +}); \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index e9ffa30..13bcffe 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ -}; - -export default nextConfig; +import {NextConfig} from 'next'; +import createNextIntlPlugin from 'next-intl/plugin'; + +const nextConfig: NextConfig = {}; + +const withNextIntl = createNextIntlPlugin('./i18n/request.ts'); +export default withNextIntl(nextConfig); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e7b3393..124391e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "corecontrol", - "version": "0.0.10", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "corecontrol", - "version": "0.0.10", + "version": "1.0.0", "dependencies": { "@prisma/client": "^6.6.0", "@prisma/extension-accelerate": "^1.3.0", @@ -39,6 +39,7 @@ "jsonwebtoken": "^9.0.2", "lucide-react": "^0.487.0", "next": "15.3.0", + "next-intl": "^4.1.0", "next-themes": "^0.4.6", "postcss-loader": "^8.1.1", "react": "^19.0.0", @@ -569,6 +570,66 @@ "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", "license": "MIT" }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz", + "integrity": "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/intl-localematcher": "0.6.1", + "decimal.js": "^10.4.3", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz", + "integrity": "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", + "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz", + "integrity": "sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/icu-skeleton-parser": "1.8.14", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz", + "integrity": "sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz", + "integrity": "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==", + "license": "MIT", + "dependencies": { + "tslib": "2" + } + }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.34.1", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz", @@ -2128,6 +2189,12 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, + "node_modules/@schummar/icu-type-parser": { + "version": "1.21.5", + "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz", + "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==", + "license": "MIT" + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -3068,6 +3135,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "license": "MIT" + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3604,6 +3677,18 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/intl-messageformat": { + "version": "10.7.16", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.16.tgz", + "integrity": "sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.2", + "tslib": "^2.8.0" + } + }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -4138,6 +4223,15 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/next/-/next-15.3.0.tgz", @@ -4192,6 +4286,33 @@ } } }, + "node_modules/next-intl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.1.0.tgz", + "integrity": "sha512-JNJRjc7sdnfUxhZmGcvzDszZ60tQKrygV/VLsgzXhnJDxQPn1cN2rVpc53adA1SvBJwPK2O6Sc6b4gYSILjCzw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/intl-localematcher": "^0.5.4", + "negotiator": "^1.0.0", + "use-intl": "^4.1.0" + }, + "peerDependencies": { + "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/next-themes": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", @@ -4972,6 +5093,20 @@ } } }, + "node_modules/use-intl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.1.0.tgz", + "integrity": "sha512-mQvDYFvoGn+bm/PWvlQOtluKCknsQ5a9F1Cj0hMfBjMBVTwnOqLPd6srhjvVdEQEQFVyHM1PfyifKqKYb11M9Q==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "^2.2.0", + "@schummar/icu-type-parser": "1.21.5", + "intl-messageformat": "^10.5.14" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + } + }, "node_modules/use-sidecar": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", diff --git a/package.json b/package.json index 9d7ddc2..ffe241e 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "jsonwebtoken": "^9.0.2", "lucide-react": "^0.487.0", "next": "15.3.0", + "next-intl": "^4.1.0", "next-themes": "^0.4.6", "postcss-loader": "^8.1.1", "react": "^19.0.0", From 4665b225147db7b50c89f1b840352c1221e73c09 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 23:25:32 +0200 Subject: [PATCH 13/54] Dashboard i18n --- app/dashboard/Dashboard.tsx | 40 +++++++++++++++++++------------------ i18n/languages/en.json | 28 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/app/dashboard/Dashboard.tsx b/app/dashboard/Dashboard.tsx index 1275bbf..f2b0e53 100644 --- a/app/dashboard/Dashboard.tsx +++ b/app/dashboard/Dashboard.tsx @@ -17,6 +17,7 @@ import { Separator } from "@/components/ui/separator" import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar" import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" +import { useTranslations } from "next-intl" interface StatsResponse { serverCountNoVMs: number @@ -26,6 +27,7 @@ interface StatsResponse { } export default function Dashboard() { + const t = useTranslations('Dashboard') const [serverCountNoVMs, setServerCountNoVMs] = useState(0) const [serverCountOnlyVMs, setServerCountOnlyVMs] = useState(0) const [applicationCount, setApplicationCount] = useState(0) @@ -62,22 +64,22 @@ export default function Dashboard() { - Dashboard + {t('Title')}
-

Dashboard

+

{t('Title')}

- Servers - Physical and virtual servers overview + {t('Servers.Title')} + {t('Servers.Description')}
@@ -91,7 +93,7 @@ export default function Dashboard() {
{serverCountNoVMs}
-

Physical Servers

+

{t('Servers.PhysicalServers')}

@@ -102,7 +104,7 @@ export default function Dashboard() {
{serverCountOnlyVMs}
-

Virtual Servers

+

{t('Servers.VirtualServers')}

@@ -115,7 +117,7 @@ export default function Dashboard() { asChild > - Manage Servers + {t('Servers.ManageServers')} @@ -125,15 +127,15 @@ export default function Dashboard() {
- Applications - Manage your deployed applications + {t('Applications.Title')} + {t('Applications.Description')}
{applicationCount}
-

Running applications

+

{t('Applications.OnlineApplications')}

@@ -153,8 +155,8 @@ export default function Dashboard() {
- Uptime - Monitor your service availability + {t('Uptime.Title')} + {t('Uptime.Description')}
@@ -177,7 +179,7 @@ export default function Dashboard() { }} >
-

Online applications

+

{t('Uptime.OnlineApplications')}

@@ -188,7 +190,7 @@ export default function Dashboard() { asChild > - View uptime metrics + {t('Uptime.ViewUptimeMetrics')} @@ -198,15 +200,15 @@ export default function Dashboard() {
- Network - Manage network configuration + {t('Network.Title')} + {t('Network.Description')}
{serverCountNoVMs + serverCountOnlyVMs + applicationCount}
-

Active connections

+

{t('Network.ActiveConnections')}

diff --git a/i18n/languages/en.json b/i18n/languages/en.json index 5280769..5f0c464 100644 --- a/i18n/languages/en.json +++ b/i18n/languages/en.json @@ -8,5 +8,33 @@ "Password": "Password", "SigninButton": "Sign in", "SigninButtonSigningIn": "Signing in..." + }, + "Dashboard": { + "Title": "Dashboard", + "Servers": { + "Title": "Servers", + "Description": "Physical and virtual servers overview", + "PhysicalServers": "Physical Servers", + "VirtualServers": "Virtual Servers", + "ManageServers": "Manage Servers" + }, + "Applications": { + "Title": "Applications", + "Description": "Manage your deployed applications", + "OnlineApplications": "Running Applications", + "ViewAllApplications": "View all applications" + }, + "Uptime": { + "Title": "Uptime", + "Description": "Monitor your service availability", + "OnlineApplications": "Online Applications", + "ViewUptimeMetrics": "View uptime metrics" + }, + "Network": { + "Title": "Network", + "Description": "Manage network configuration", + "ActiveConnections": "Active Connections", + "ViewNetworkDetails": "View network details" + } } } \ No newline at end of file From eff7901b67b667386f7fc7aad972f45b860e3e26 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 23:28:34 +0200 Subject: [PATCH 14/54] Sidebar i18n --- components/app-sidebar.tsx | 27 +++++++++++++++------------ i18n/languages/en.json | 11 +++++++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index ed84762..ce2113c 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -37,7 +37,7 @@ import { useRouter } from "next/navigation" import packageJson from "@/package.json" import { cn } from "@/lib/utils" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" - +import { useTranslations } from "next-intl" interface NavItem { title: string icon?: React.ComponentType @@ -46,49 +46,52 @@ interface NavItem { items?: NavItem[] } -const data: { navMain: NavItem[] } = { + + +export function AppSidebar({ ...props }: React.ComponentProps) { + const t = useTranslations('Sidebar') + const data: { navMain: NavItem[] } = { navMain: [ { - title: "Dashboard", + title: t('Dashboard'), icon: LayoutDashboardIcon, url: "/dashboard", }, { - title: "My Infrastructure", + title: t('My Infrastructure'), url: "#", icon: Briefcase, items: [ { - title: "Servers", + title: t('Servers'), icon: Server, url: "/dashboard/servers", }, { - title: "Applications", + title: t('Applications'), icon: AppWindow, url: "/dashboard/applications", }, { - title: "Uptime", + title: t('Uptime'), icon: Activity, url: "/dashboard/uptime", }, { - title: "Network", + title: t('Network'), icon: Network, url: "/dashboard/network", }, ], }, { - title: "Settings", + title: t('Settings'), icon: Settings, url: "/dashboard/settings", }, ], } -export function AppSidebar({ ...props }: React.ComponentProps) { const router = useRouter() const pathname = usePathname() @@ -132,7 +135,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { - Main Navigation + {t('Main Navigation')} @@ -197,7 +200,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { onClick={logout} > - Logout + {t('Logout')} diff --git a/i18n/languages/en.json b/i18n/languages/en.json index 5f0c464..8ad5889 100644 --- a/i18n/languages/en.json +++ b/i18n/languages/en.json @@ -1,4 +1,15 @@ { + "Sidebar": { + "Main Navigation": "Main Navigation", + "Dashboard": "Dashboard", + "My Infrastructure": "My Infrastructure", + "Servers": "Servers", + "Applications": "Applications", + "Uptime": "Uptime", + "Network": "Network", + "Settings": "Settings", + "Logout": "Logout" + }, "Home": { "TitleUnder": "Dashboard to manage your entire server infrastructure", "LoginCardTitle": "Login", From 58e2466875d9daf5eadef9cd9a625d099a596ff1 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Mon, 28 Apr 2025 23:50:18 +0200 Subject: [PATCH 15/54] Servers.tsx i18n 1/2 --- app/dashboard/servers/Servers.tsx | 119 +++++++++++++----------------- i18n/languages/en.json | 63 ++++++++++++++++ 2 files changed, 114 insertions(+), 68 deletions(-) diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx index 8f45505..15ff673 100644 --- a/app/dashboard/servers/Servers.tsx +++ b/app/dashboard/servers/Servers.tsx @@ -66,6 +66,7 @@ import NextLink from "next/link" import { Toaster } from "@/components/ui/sonner" import { toast } from "sonner" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" +import { useTranslations } from "next-intl" interface ServerHistory { labels: string[]; @@ -122,7 +123,8 @@ interface MonitoringData { temp?: number } -export default function Dashboard() { +export default function Servers() { + const t = useTranslations('Servers') const [host, setHost] = useState(false) const [hostServer, setHostServer] = useState(0) const [name, setName] = useState("") @@ -465,18 +467,14 @@ export default function Dashboard() { }; }, []); - // Handler für benutzerdefinierte Zahleneingaben mit Verzögerung const handleItemsPerPageChange = (value: string) => { - // Bestehenden Timer löschen if (debounceTimerRef.current) { clearTimeout(debounceTimerRef.current); } - // Neuen Timer setzen debounceTimerRef.current = setTimeout(() => { const newItemsPerPage = parseInt(value); - // Sicherstellen, dass der Wert im gültigen Bereich liegt if (isNaN(newItemsPerPage) || newItemsPerPage < 1) { toast.error("Bitte eine Zahl zwischen 1 und 100 eingeben"); return; @@ -485,37 +483,31 @@ export default function Dashboard() { const validatedValue = Math.min(Math.max(newItemsPerPage, 1), 100); setItemsPerPage(validatedValue); - setCurrentPage(1); // Zurück zur ersten Seite + setCurrentPage(1); Cookies.set("itemsPerPage-servers", String(validatedValue), { expires: 365, path: "/", sameSite: "strict", }); - // Daten mit neuer Paginierung abrufen getServers(); - }, 600); // 600ms Verzögerung für bessere Eingabe mehrziffriger Zahlen + }, 600); }; - // Handler für voreingestellte Werte aus dem Dropdown const handlePresetItemsPerPageChange = (value: string) => { - // Für voreingestellte Werte sofort anwenden const newItemsPerPage = parseInt(value); - // Nur Standardwerte hier verarbeiten if ([4, 6, 10, 15, 20, 25].includes(newItemsPerPage)) { setItemsPerPage(newItemsPerPage); - setCurrentPage(1); // Zurück zur ersten Seite + setCurrentPage(1); Cookies.set("itemsPerPage-servers", String(newItemsPerPage), { expires: 365, path: "/", sameSite: "strict", }); - // Daten mit neuer Paginierung abrufen getServers(); } else { - // Für benutzerdefinierte Werte den verzögerten Handler verwenden handleItemsPerPageChange(value); } }; @@ -535,11 +527,11 @@ export default function Dashboard() { - My Infrastructure + {t('MyInfrastructure')} - Servers + {t('Servers')} @@ -548,11 +540,11 @@ export default function Dashboard() {
- Your Servers + {t('YourServers')}
-
- +
{icon && }
- +
- Link to a web interface (e.g. Proxmox or Portainer) with which the server can be - managed + {t('AddServer.General.ManagementURLTooltip')} @@ -863,7 +846,7 @@ export default function Dashboard() {
setHost(checked === true)} /> - +
{!host && (
- +
-

Required Server Setup

+

{t('AddServer.Monitoring.SetupTitle')}

- To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration: + {t('AddServer.Monitoring.SetupDescription')}

                                     {`services:
@@ -1000,8 +983,8 @@ export default function Dashboard() {
                     
                   
                   
-                    Cancel
-                    Add
+                    {t('cancel')}
+                    {t('add')}
                   
                 
               
diff --git a/i18n/languages/en.json b/i18n/languages/en.json
index 8ad5889..dc08316 100644
--- a/i18n/languages/en.json
+++ b/i18n/languages/en.json
@@ -47,5 +47,68 @@
             "ActiveConnections": "Active Connections",
             "ViewNetworkDetails": "View network details"
         }
+    },
+    "Servers": {
+        "MyInfrastructure": "My Infrastructure",
+        "Title": "Servers",
+        "YourServers": "Your Servers",
+        "ChangeView": "Change View",
+        "ListView": "List View",
+        "GridView": "Grid View",
+        "ItemsPerPage": {
+            "items": "items",
+            "item": "item",
+            "4": "4 items",
+            "6": "6 items",
+            "10": "10 items",
+            "15": "15 items",
+            "20": "20 items",
+            "25": "25 items",
+            "Custom": "Custom (1-100)"
+        },
+        "Tabs": {
+            "General": "General",
+            "Hardware": "Hardware",
+            "Host": "Host",
+            "Monitoring": "Monitoring"
+        },
+        "optional": "optional",
+        "cancel": "Cancel",
+        "add": "Add",
+        "AddServer": {
+            "Title": "Add a server",
+            "General": {
+                "Title": "Add a server",
+                "CopyServer": "Copy server",
+                "Icon": "Icon",
+                "IconPlaceholder": "Select an icon",
+                "IconSearchPlaceholder": "Search icons...",
+                "Preview": "Preview",
+                "Name": "Name",
+                "OperatingSystem": "Operating System",
+                "OperatingSystemPlaceholder": "Select OS",
+                "IPAdress": "IP Adress",
+                "ManagementURL": "Management URL",
+                "ManagementURLTooltip": "Link to a web interface (e.g. Proxmox or Portainer) with which the server can be managed"
+            },
+            "Hardware": {
+                "CPU": "CPU",
+                "GPU": "GPU",
+                "RAM": "RAM",
+                "Storage": "Storage"
+            },
+            "Host": {
+                "MarkAsHostServer": "Mark as host server",
+                "SelectHostServer": "Select a host server",
+                "SelectHostServerPlaceholder": "Select a host server",
+                "NoHostServer": "No host server"
+            },
+            "Monitoring": {
+                "Enable": "Enable monitoring",
+                "URL": "Monitoring URL",
+                "SetupTitle": "Required Server Setup",
+                "SetupDescription": "To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration:"
+            }
+        }
     }
 }
\ No newline at end of file

From faea966f2fc7a8b19bc9979b72b20287f8904acc Mon Sep 17 00:00:00 2001
From: headlessdev <132705454+crocofied@users.noreply.github.com>
Date: Tue, 29 Apr 2025 00:00:32 +0200
Subject: [PATCH 16/54] Update Crowdin configuration file

---
 crowdin.yml | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 crowdin.yml

diff --git a/crowdin.yml b/crowdin.yml
new file mode 100644
index 0000000..b1044b0
--- /dev/null
+++ b/crowdin.yml
@@ -0,0 +1,3 @@
+files:
+  - source: /i18n/languages/en.json
+    translation: /i18n/languages/%two_letters_code%.json

From 196b70b2adbd3de1caec86290a44110b8b289f04 Mon Sep 17 00:00:00 2001
From: headlessdev <132705454+crocofied@users.noreply.github.com>
Date: Tue, 29 Apr 2025 00:03:53 +0200
Subject: [PATCH 17/54] Delete crowdin.yml

---
 crowdin.yml | 3 ---
 1 file changed, 3 deletions(-)
 delete mode 100644 crowdin.yml

diff --git a/crowdin.yml b/crowdin.yml
deleted file mode 100644
index b1044b0..0000000
--- a/crowdin.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-files:
-  - source: /i18n/languages/en.json
-    translation: /i18n/languages/%two_letters_code%.json

From c4f3b47fc7ecd5e27b748a481ed65e0a46168ab9 Mon Sep 17 00:00:00 2001
From: headlessdev 
Date: Tue, 29 Apr 2025 16:20:34 +0200
Subject: [PATCH 18/54] Servers.tsx i18n

---
 app/dashboard/servers/Servers.tsx | 338 +++++++++++++++---------------
 i18n/languages/en.json            | 276 ++++++++++++++----------
 2 files changed, 342 insertions(+), 272 deletions(-)

diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx
index 15ff673..e124c00 100644
--- a/app/dashboard/servers/Servers.tsx
+++ b/app/dashboard/servers/Servers.tsx
@@ -28,6 +28,8 @@ import {
   Copy,
   History,
   Thermometer,
+  ChevronLeft,
+  ChevronRight,
 } from "lucide-react"
 import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
 import {
@@ -124,7 +126,7 @@ interface MonitoringData {
 }
 
 export default function Servers() {
-  const t = useTranslations('Servers')
+  const t = useTranslations()
   const [host, setHost] = useState(false)
   const [hostServer, setHostServer] = useState(0)
   const [name, setName] = useState("")
@@ -527,11 +529,11 @@ export default function Servers() {
                 
                 
                 
-                  {t('MyInfrastructure')}
+                  {t('Servers.MyInfrastructure')}
                 
                 
                 
-                  {t('Servers')}
+                  {t('Servers.Title')}
                 
               
             
@@ -540,11 +542,11 @@ export default function Servers() {
         
         
- {t('YourServers')} + {t('Servers.YourServers')}
-
- +
{icon && }
- +
- {t('AddServer.General.ManagementURLTooltip')} + {t('Servers.AddServer.General.ManagementURLTooltip')} @@ -846,7 +848,7 @@ export default function Servers() {
setHost(checked === true)} /> - +
{!host && (
- +
-

{t('AddServer.Monitoring.SetupTitle')}

+

{t('Servers.AddServer.Monitoring.SetupTitle')}

- {t('AddServer.Monitoring.SetupDescription')} + {t('Servers.AddServer.Monitoring.SetupDescription')}

                                     {`services:
@@ -983,8 +985,8 @@ export default function Servers() {
                     
                   
                   
-                    {t('cancel')}
-                    {t('add')}
+                    {t('Common.cancel')}
+                    {t('Common.add')}
                   
                 
               
@@ -993,7 +995,7 @@ export default function Servers() {
           
setSearchTerm(e.target.value)} /> @@ -1016,7 +1018,7 @@ export default function Servers() { {server.online && server.uptime && ( - since {server.uptime} + {t('Common.since', { date: server.uptime })} )}
@@ -1045,13 +1047,13 @@ export default function Servers() {
- OS: {server.os || "-"} + {t('Common.Server.OS')}: {server.os || "-"}
- IP: {server.ip || "Not set"} + {t('Common.Server.IP')}: {server.ip || t('Common.notSet')}
@@ -1059,7 +1061,7 @@ export default function Servers() {
- Host: {getHostServerName(server.hostServer)} + {t('Common.Server.Host')}: {getHostServerName(server.hostServer)}
)} @@ -1069,31 +1071,31 @@ export default function Servers() {
-

Hardware Information

+

{t('Servers.ServerCard.HardwareInformation')}

- CPU: {server.cpu || "-"} + {t('Common.Server.CPU')}: {server.cpu || "-"}
- GPU: {server.gpu || "-"} + {t('Common.Server.GPU')}: {server.gpu || "-"}
- RAM: {server.ram || "-"} + {t('Common.Server.RAM')}: {server.ram || "-"}
- Disk: {server.disk || "-"} + {t('Common.Server.Disk')}: {server.disk || "-"}
@@ -1104,15 +1106,15 @@ export default function Servers() {
-

Resource Usage

+

{t('Servers.ServerCard.ResourceUsage')}

- CPU + {t('Common.Server.CPU')}
- {server.cpuUsage !== null && server.cpuUsage !== undefined ? `${server.cpuUsage}%` : "NO DATA"} + {server.cpuUsage !== null && server.cpuUsage !== undefined ? `${server.cpuUsage}%` : t('Common.noData')}
- RAM + {t('Common.Server.RAM')}
- {server.ramUsage !== null && server.ramUsage !== undefined ? `${server.ramUsage}%` : "NO DATA"} + {server.ramUsage !== null && server.ramUsage !== undefined ? `${server.ramUsage}%` : t('Common.noData')}
- Disk + {t('Common.Server.Disk')}
- {server.diskUsage !== null && server.diskUsage !== undefined ? `${server.diskUsage}%` : "NO DATA"} + {server.diskUsage !== null && server.diskUsage !== undefined ? `${server.diskUsage}%` : t('Common.noData')}
-
-
- - GPU +
+
+ + {t('Common.Server.GPU')} +
+ + {server.online && + server.gpuUsage && + server.gpuUsage !== null && + server.gpuUsage !== undefined && + server.gpuUsage.toString() !== "0" + ? `${server.gpuUsage}%` + : t('Common.noData')} +
- - {server.online && - server.gpuUsage && - server.gpuUsage !== null && - server.gpuUsage !== undefined && - server.gpuUsage.toString() !== "0" - ? `${server.gpuUsage}%` - : "NO DATA"} - -
80 ? "bg-destructive" : server.gpuUsage && server.gpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} @@ -1180,20 +1182,20 @@ export default function Servers() {
-
-
- - Temp +
+
+ + {t('Common.Server.Temperature')} +
+ + {server.online && + server.temp !== null && + server.temp !== undefined && + server.temp.toString() !== "0" + ? `${server.temp}°C` + : t('Common.noData')} +
- - {server.online && - server.temp !== null && - server.temp !== undefined && - server.temp.toString() !== "0" - ? `${server.temp}°C` - : "NO DATA"} - -
80 ? "bg-destructive" : server.temp && server.temp > 60 ? "bg-amber-500" : "bg-emerald-500"}`} @@ -1214,7 +1216,7 @@ export default function Servers() { @@ -1230,7 +1232,7 @@ export default function Servers() { - Open Management URL + {t('Servers.ServerCard.OpenManagementURL')} )} @@ -1254,7 +1256,7 @@ export default function Servers() { - Edit server + {t('Servers.ServerCard.EditServer')} @@ -1270,7 +1272,7 @@ export default function Servers() { - Hosted VMs + {t('Servers.ServerCard.HostedVMs')} {server.host && (
@@ -1325,21 +1327,21 @@ export default function Servers() { - Edit VM + {t('Servers.EditServer.Title', { name: hostedVM.name })} - General - Hardware + {t('Common.Server.Tabs.General')} + {t('Common.Server.Tabs.Hardware')} - Host + {t('Common.Server.Tabs.Host')}
- +
{ const iconElements = @@ -1426,7 +1428,7 @@ export default function Servers() {
- +
{editIcon && (
- +
- +
- +
- +
- +
- +
- +
- +
{!editHost && (
- + setEditIcon(value)} > - + {editIcon && (
@@ -1765,7 +1767,7 @@ export default function Servers() { { const iconElements = document.querySelectorAll( @@ -1811,14 +1813,14 @@ export default function Servers() {
- +
{editIcon && }
- +
- +
- +
- +
- + - +
{!editHost && (
- +
-

Required Server Setup

+

{t('Servers.EditServer.Monitoring.SetupTitle')}

- To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration: + {t('Servers.EditServer.Monitoring.SetupDescription')}

                                                 {`services:
@@ -1996,8 +1998,8 @@ export default function Servers() {
                                 
                               
                               
-                                Cancel
-                                
+                                {t('Common.cancel')}
+                                
                               
                             
                           
@@ -2013,24 +2015,24 @@ export default function Servers() {
                                   
                                   
                                     
-                                      Delete {server.name}
+                                      {t('Servers.ServerCard.DeleteConfirmation.Title', { name: server.name })}
                                       
-                                        Are you sure you want to delete this server? This action cannot be undone.
+                                        {t('Servers.ServerCard.DeleteConfirmation.Description')}
                                       
                                     
                                     
-                                      Cancel
+                                      {t('Servers.ServerCard.DeleteConfirmation.Cancel')}
                                        deleteApplication(server.id)}
                                       >
-                                        Delete
+                                        {t('Servers.ServerCard.DeleteConfirmation.Delete')}
                                       
                                     
                                   
                                 
                               
-                              Delete server
+                              {t('Servers.ServerCard.DeleteServer')}
                             
                           
                         
@@ -2071,8 +2073,12 @@ export default function Servers() {
{totalItems > 0 - ? `Showing ${((currentPage - 1) * itemsPerPage) + 1}-${Math.min(currentPage * itemsPerPage, totalItems)} of ${totalItems} servers` - : "No servers found"} + ? t('Servers.Pagination.Showing', { + start: ((currentPage - 1) * itemsPerPage) + 1, + end: Math.min(currentPage * itemsPerPage, totalItems), + total: totalItems + }) + : t('Servers.Pagination.NoServers')}
diff --git a/i18n/languages/en.json b/i18n/languages/en.json index dc08316..57b3195 100644 --- a/i18n/languages/en.json +++ b/i18n/languages/en.json @@ -1,114 +1,178 @@ { - "Sidebar": { - "Main Navigation": "Main Navigation", - "Dashboard": "Dashboard", - "My Infrastructure": "My Infrastructure", - "Servers": "Servers", - "Applications": "Applications", - "Uptime": "Uptime", - "Network": "Network", - "Settings": "Settings", - "Logout": "Logout" - }, - "Home": { - "TitleUnder": "Dashboard to manage your entire server infrastructure", - "LoginCardTitle": "Login", - "LoginCardDescription": "Enter your credentials to continue", - "AuthenticationError": "Authentication Error", - "Email": "Email", - "Password": "Password", - "SigninButton": "Sign in", - "SigninButtonSigningIn": "Signing in..." - }, - "Dashboard": { - "Title": "Dashboard", - "Servers": { - "Title": "Servers", - "Description": "Physical and virtual servers overview", - "PhysicalServers": "Physical Servers", - "VirtualServers": "Virtual Servers", - "ManageServers": "Manage Servers" - }, - "Applications": { - "Title": "Applications", - "Description": "Manage your deployed applications", - "OnlineApplications": "Running Applications", - "ViewAllApplications": "View all applications" - }, - "Uptime": { - "Title": "Uptime", - "Description": "Monitor your service availability", - "OnlineApplications": "Online Applications", - "ViewUptimeMetrics": "View uptime metrics" - }, - "Network": { - "Title": "Network", - "Description": "Manage network configuration", - "ActiveConnections": "Active Connections", - "ViewNetworkDetails": "View network details" - } - }, - "Servers": { - "MyInfrastructure": "My Infrastructure", - "Title": "Servers", - "YourServers": "Your Servers", - "ChangeView": "Change View", - "ListView": "List View", - "GridView": "Grid View", - "ItemsPerPage": { - "items": "items", - "item": "item", - "4": "4 items", - "6": "6 items", - "10": "10 items", - "15": "15 items", - "20": "20 items", - "25": "25 items", - "Custom": "Custom (1-100)" - }, + "Common": { + "ChangeView": "Change View", + "ListView": "List View", + "GridView": "Grid View", + "optional": "optional", + "cancel": "Cancel", + "add": "Add", + "since": "since {date}", + "notSet": "Not set", + "noData": "No data", + "ItemsPerPage": { + "items": "items", + "item": "item", + "4": "4 items", + "6": "6 items", + "10": "10 items", + "15": "15 items", + "20": "20 items", + "25": "25 items", + "Custom": "Custom (1-100)" + }, + "Server": { + "CPU": "CPU", + "GPU": "GPU", + "RAM": "RAM", + "Disk": "Disk", + "OS": "OS", + "IP": "IP", + "Host": "Host", + "Temperature": "Temperature", "Tabs": { "General": "General", "Hardware": "Hardware", "Host": "Host", "Monitoring": "Monitoring" - }, - "optional": "optional", - "cancel": "Cancel", - "add": "Add", - "AddServer": { - "Title": "Add a server", - "General": { - "Title": "Add a server", - "CopyServer": "Copy server", - "Icon": "Icon", - "IconPlaceholder": "Select an icon", - "IconSearchPlaceholder": "Search icons...", - "Preview": "Preview", - "Name": "Name", - "OperatingSystem": "Operating System", - "OperatingSystemPlaceholder": "Select OS", - "IPAdress": "IP Adress", - "ManagementURL": "Management URL", - "ManagementURLTooltip": "Link to a web interface (e.g. Proxmox or Portainer) with which the server can be managed" - }, - "Hardware": { - "CPU": "CPU", - "GPU": "GPU", - "RAM": "RAM", - "Storage": "Storage" - }, - "Host": { - "MarkAsHostServer": "Mark as host server", - "SelectHostServer": "Select a host server", - "SelectHostServerPlaceholder": "Select a host server", - "NoHostServer": "No host server" - }, - "Monitoring": { - "Enable": "Enable monitoring", - "URL": "Monitoring URL", - "SetupTitle": "Required Server Setup", - "SetupDescription": "To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration:" - } } + } + }, + "Sidebar": { + "Main Navigation": "Main Navigation", + "Dashboard": "Dashboard", + "My Infrastructure": "My Infrastructure", + "Servers": "Servers", + "Applications": "Applications", + "Uptime": "Uptime", + "Network": "Network", + "Settings": "Settings", + "Logout": "Logout" + }, + "Home": { + "TitleUnder": "Dashboard to manage your entire server infrastructure", + "LoginCardTitle": "Login", + "LoginCardDescription": "Enter your credentials to continue", + "AuthenticationError": "Authentication Error", + "Email": "Email", + "Password": "Password", + "SigninButton": "Sign in", + "SigninButtonSigningIn": "Signing in..." + }, + "Dashboard": { + "Title": "Dashboard", + "Servers": { + "Title": "Servers", + "Description": "Physical and virtual servers overview", + "PhysicalServers": "Physical Servers", + "VirtualServers": "Virtual Servers", + "ManageServers": "Manage Servers" + }, + "Applications": { + "Title": "Applications", + "Description": "Manage your deployed applications", + "OnlineApplications": "Running Applications", + "ViewAllApplications": "View all applications" + }, + "Uptime": { + "Title": "Uptime", + "Description": "Monitor your service availability", + "OnlineApplications": "Online Applications", + "ViewUptimeMetrics": "View uptime metrics" + }, + "Network": { + "Title": "Network", + "Description": "Manage network configuration", + "ActiveConnections": "Active Connections", + "ViewNetworkDetails": "View network details" + } + }, + "Servers": { + "Title": "Servers", + "MyInfrastructure": "My Infrastructure", + "YourServers": "Your Servers", + "AddServer": { + "Title": "Add a server", + "General": { + "Title": "Add a server", + "CopyServer": "Copy server", + "Icon": "Icon", + "IconPlaceholder": "Select an icon", + "IconSearchPlaceholder": "Search icons...", + "Preview": "Preview", + "Name": "Name", + "OperatingSystem": "Operating System", + "OperatingSystemPlaceholder": "Select OS", + "IPAdress": "IP Adress", + "ManagementURL": "Management URL", + "ManagementURLTooltip": "Link to a web interface (e.g. Proxmox or Portainer) with which the server can be managed" + }, + "Host": { + "MarkAsHostServer": "Mark as host server", + "SelectHostServer": "Select a host server", + "SelectHostServerPlaceholder": "Select a host server", + "NoHostServer": "No host server" + }, + "Monitoring": { + "Enable": "Enable monitoring", + "URL": "Monitoring URL", + "SetupTitle": "Required Server Setup", + "SetupDescription": "To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration:" + } + }, + "ServerCard": { + "HardwareInformation": "Hardware Information", + "ViewDetails": "View Details", + "OpenManagementURL": "Open Management URL", + "EditServer": "Edit Server", + "DeleteServer": "Delete Server", + "HostedVMs": "Hosted VMs", + "ResourceUsage": "Resource Usage", + "DeleteConfirmation": { + "Title": "Delete {name}", + "Description": "Are you sure you want to delete this server? This action cannot be undone.", + "Cancel": "Cancel", + "Delete": "Delete" + } + }, + "EditServer": { + "Title": "Edit {name}", + "Save": "Save", + "General": { + "Title": "General", + "Icon": "Icon", + "Name": "Name", + "OperatingSystem": "Operating System", + "IPAddress": "IP Address", + "ManagementURL": "Management URL" + }, + "Hardware": { + "Title": "Hardware", + "CPU": "CPU", + "GPU": "GPU", + "RAM": "RAM", + "Disk": "Disk" + }, + "Host": { + "Title": "Host", + "MarkAsHostServer": "Mark as host server", + "CannotDisableHost": "Cannot be disabled while hosting VMs", + "SelectHostServer": "Select a host server" + }, + "Monitoring": { + "Title": "Monitoring", + "Enable": "Enable monitoring", + "URL": "Monitoring URL", + "SetupTitle": "Required Server Setup", + "SetupDescription": "To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration:" + } + }, + "Pagination": { + "Showing": "Showing {start}-{end} of {total} servers", + "NoServers": "No servers found" + }, + "Search": { + "Placeholder": "Type to search..." + } } -} \ No newline at end of file + } + \ No newline at end of file From 58dd396241513b30798ca4c1cb59b9de292abe7d Mon Sep 17 00:00:00 2001 From: headlessdev Date: Tue, 29 Apr 2025 16:33:34 +0200 Subject: [PATCH 19/54] Server.tsx i18n --- app/dashboard/servers/[server_id]/Server.tsx | 145 ++++++++++--------- i18n/languages/en.json | 58 ++++++-- 2 files changed, 115 insertions(+), 88 deletions(-) diff --git a/app/dashboard/servers/[server_id]/Server.tsx b/app/dashboard/servers/[server_id]/Server.tsx index 172b5f0..16e8b53 100644 --- a/app/dashboard/servers/[server_id]/Server.tsx +++ b/app/dashboard/servers/[server_id]/Server.tsx @@ -22,6 +22,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ import { ScrollArea } from "@/components/ui/scroll-area" import { Button } from "@/components/ui/button" import NextLink from "next/link" +import { useTranslations } from "next-intl" interface ServerHistory { labels: string[]; @@ -69,6 +70,7 @@ interface GetServersResponse { } export default function ServerDetail() { + const t = useTranslations() const params = useParams() const serverId = params.server_id as string const [server, setServer] = useState(null) @@ -214,7 +216,7 @@ export default function ServerDetail() { data: { labels: timeLabels, datasets: [{ - label: 'CPU Usage', + label: t('Common.Server.CPU') + ' ' + t('Common.Server.Usage'), data: history.datasets.cpu, borderColor: 'rgb(75, 192, 192)', backgroundColor: 'rgba(75, 192, 192, 0.1)', @@ -227,7 +229,7 @@ export default function ServerDetail() { plugins: { title: { display: true, - text: 'CPU Usage History', + text: t('Common.Server.CPU') + ' ' + t('Server.UsageHistory'), font: { size: 14 } @@ -261,7 +263,7 @@ export default function ServerDetail() { data: { labels: timeLabels, datasets: [{ - label: 'RAM Usage', + label: t('Common.Server.RAM') + ' ' + t('Common.Server.Usage'), data: history.datasets.ram, borderColor: 'rgb(153, 102, 255)', backgroundColor: 'rgba(153, 102, 255, 0.1)', @@ -274,7 +276,7 @@ export default function ServerDetail() { plugins: { title: { display: true, - text: 'RAM Usage History', + text: t('Common.Server.RAM') + ' ' + t('Server.UsageHistory'), font: { size: 14 } @@ -308,7 +310,7 @@ export default function ServerDetail() { data: { labels: timeLabels, datasets: [{ - label: 'Disk Usage', + label: t('Common.Server.Disk') + ' ' + t('Common.Server.Usage'), data: history.datasets.disk, borderColor: 'rgb(255, 159, 64)', backgroundColor: 'rgba(255, 159, 64, 0.1)', @@ -321,7 +323,7 @@ export default function ServerDetail() { plugins: { title: { display: true, - text: 'Disk Usage History', + text: t('Common.Server.Disk') + ' ' + t('Server.UsageHistory'), font: { size: 14 } @@ -355,7 +357,7 @@ export default function ServerDetail() { data: { labels: timeLabels, datasets: [{ - label: 'GPU Usage', + label: t('Common.Server.GPU') + ' ' + t('Common.Server.Usage'), data: history.datasets.gpu, borderColor: 'rgb(255, 99, 132)', backgroundColor: 'rgba(255, 99, 132, 0.1)', @@ -368,7 +370,7 @@ export default function ServerDetail() { plugins: { title: { display: true, - text: 'GPU Usage History', + text: t('Common.Server.GPU') + ' ' + t('Common.Server.UsageHistory'), font: { size: 14 } @@ -402,7 +404,7 @@ export default function ServerDetail() { data: { labels: timeLabels, datasets: [{ - label: 'Temperature', + label: t('Common.Server.Temperature'), data: history.datasets.temp, borderColor: 'rgb(255, 159, 64)', backgroundColor: 'rgba(255, 159, 64, 0.1)', @@ -415,7 +417,7 @@ export default function ServerDetail() { plugins: { title: { display: true, - text: 'Temperature History', + text: t('Common.Server.TemperatureHistory'), font: { size: 14 } @@ -478,12 +480,12 @@ export default function ServerDetail() { - My Infrastructure + {t('Servers.MyInfrastructure')} - Servers + {t('Servers.Title')} {server && ( @@ -524,7 +526,7 @@ export default function ServerDetail() { - Loading... + {t('Common.Loading')}
) : server ? ( @@ -540,9 +542,9 @@ export default function ServerDetail() { {server.name} - {server.os || "No OS specified"} • {server.isVM ? "Virtual Machine" : "Physical Server"} + {server.os || t('Common.Server.OS')} • {server.isVM ? t('Server.VM') : t('Server.Physical')} {server.isVM && server.hostServer && ( - <> • Hosted on {server.hostedVMs?.[0]?.name} + <> • {t('Server.HostedOn')} {server.hostedVMs?.[0]?.name} )}
@@ -553,7 +555,7 @@ export default function ServerDetail() { {server.online && server.uptime && ( - since {server.uptime} + {t('Common.since', { date: server.uptime })} )}
@@ -562,25 +564,25 @@ export default function ServerDetail() {
-

Hardware

+

{t('Server.Hardware')}

-
CPU:
+
{t('Common.Server.CPU')}:
{server.cpu || "-"}
-
GPU:
+
{t('Common.Server.GPU')}:
{server.gpu || "-"}
-
RAM:
+
{t('Common.Server.RAM')}:
{server.ram || "-"}
-
Disk:
+
{t('Common.Server.Disk')}:
{server.disk || "-"}
-

Network

+

{t('Server.Network')}

-
IP Address:
+
{t('Common.Server.IP')}:
{server.ip || "-"}
-
Management URL:
+
{t('Server.ManagementURL')}:
{server.url ? ( @@ -595,9 +597,9 @@ export default function ServerDetail() { {server.monitoring && (
-

Current Usage

+

{t('Server.CurrentUsage')}

-
CPU Usage:
+
{t('Common.Server.CPU')} {t('Common.Server.Usage')}:
- {server.cpuUsage !== null && server.cpuUsage !== undefined ? `${server.cpuUsage}%` : "NO DATA"} + {server.cpuUsage !== null && server.cpuUsage !== undefined ? `${server.cpuUsage}%` : t('Common.noData')}
-
RAM Usage:
+
{t('Common.Server.RAM')} {t('Common.Server.Usage')}:
- {server.ramUsage !== null && server.ramUsage !== undefined ? `${server.ramUsage}%` : "NO DATA"} + {server.ramUsage !== null && server.ramUsage !== undefined ? `${server.ramUsage}%` : t('Common.noData')}
-
Disk Usage:
+
{t('Common.Server.Disk')} {t('Common.Server.Usage')}:
- {server.diskUsage !== null && server.diskUsage !== undefined ? `${server.diskUsage}%` : "NO DATA"} + {server.diskUsage !== null && server.diskUsage !== undefined ? `${server.diskUsage}%` : t('Common.noData')}
{server.gpuUsage && server.gpuUsage !== null && server.gpuUsage !== undefined && server.gpuUsage.toString() !== "0" && ( <> -
GPU Usage:
+
{t('Common.Server.GPU')} {t('Common.Server.Usage')}:
-
80 ? "bg-destructive" : server.gpuUsage && server.gpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} - style={{ width: `${server.gpuUsage || 0}%` }} - /> -
- - {server.gpuUsage && server.gpuUsage !== null && server.gpuUsage !== undefined ? `${server.gpuUsage}%` : "NO DATA"} +
80 ? "bg-destructive" : server.gpuUsage && server.gpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${server.gpuUsage || 0}%` }} + /> +
+ {server.gpuUsage && server.gpuUsage !== null && server.gpuUsage !== undefined ? `${server.gpuUsage}%` : t('Common.noData')}
)} {server.temp && server.temp !== null && server.temp !== undefined && server.temp.toString() !== "0" && ( <> -
Temperature:
+
{t('Common.Server.Temperature')}:
-
80 ? "bg-destructive" : server.temp && server.temp > 60 ? "bg-amber-500" : "bg-emerald-500"}`} - style={{ width: `${Math.min(server.temp || 0, 100)}%` }} - /> -
- {server.temp !== null && server.temp !== undefined && server.temp !== 0 ? `${server.temp}°C` : "NO DATA"} +
80 ? "bg-destructive" : server.temp && server.temp > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${Math.min(server.temp || 0, 100)}%` }} + /> +
+ {server.temp !== null && server.temp !== undefined && server.temp !== 0 ? `${server.temp}°C` : t('Common.noData')}
)} @@ -670,30 +671,30 @@ export default function ServerDetail() {
- Resource Usage History + {t('Server.ResourceUsageHistory')} {timeRange === '1h' - ? 'Last hour, per minute' + ? t('Server.TimeRange.LastHour') : timeRange === '1d' - ? 'Last 24 hours, 15-minute intervals' + ? t('Server.TimeRange.Last24Hours') : timeRange === '7d' - ? 'Last 7 days, hourly intervals' - : 'Last 30 days, 4-hour intervals'} + ? t('Server.TimeRange.Last7Days') + : t('Server.TimeRange.Last30Days')}
- +
@@ -728,8 +729,8 @@ export default function ServerDetail() { {server.hostedVMs && server.hostedVMs.length > 0 && ( - Virtual Machines - Virtual machines hosted on this server + {t('Server.VirtualMachines')} + {t('Server.VirtualMachinesDescription')}
@@ -758,7 +759,7 @@ export default function ServerDetail() { {hostedVM.online && hostedVM.uptime && ( - since {hostedVM.uptime} + {t('Common.since', { date: hostedVM.uptime })} )}
@@ -773,43 +774,43 @@ export default function ServerDetail() {
- OS: {hostedVM.os || "-"} + {t('Common.Server.OS')}: {hostedVM.os || "-"}
- IP: {hostedVM.ip || "Not set"} + {t('Common.Server.IP')}: {hostedVM.ip || t('Common.notSet')}
-

Hardware Information

+

{t('Server.HardwareInformation')}

- CPU: {hostedVM.cpu || "-"} + {t('Common.Server.CPU')}: {hostedVM.cpu || "-"}
- GPU: {hostedVM.gpu || "-"} + {t('Common.Server.GPU')}: {hostedVM.gpu || "-"}
- RAM: {hostedVM.ram || "-"} + {t('Common.Server.RAM')}: {hostedVM.ram || "-"}
- Disk: {hostedVM.disk || "-"} + {t('Common.Server.Disk')}: {hostedVM.disk || "-"}
@@ -824,7 +825,7 @@ export default function ServerDetail() {
- CPU + {t('Common.Server.CPU')}
{hostedVM.cpuUsage || 0}% @@ -842,7 +843,7 @@ export default function ServerDetail() {
- RAM + {t('Common.Server.RAM')}
{hostedVM.ramUsage || 0}% @@ -860,7 +861,7 @@ export default function ServerDetail() {
- Disk + {t('Common.Server.Disk')}
{hostedVM.diskUsage || 0}% @@ -885,8 +886,8 @@ export default function ServerDetail() {
) : (
-

Server not found

-

The requested server could not be found or you don't have permission to view it.

+

{t('Server.NotFound')}

+

{t('Server.NotFoundDescription')}

)}
diff --git a/i18n/languages/en.json b/i18n/languages/en.json index 57b3195..39147ef 100644 --- a/i18n/languages/en.json +++ b/i18n/languages/en.json @@ -9,6 +9,25 @@ "since": "since {date}", "notSet": "Not set", "noData": "No data", + "Loading": "Loading...", + "Refresh": "Refresh", + "Server": { + "CPU": "CPU", + "GPU": "GPU", + "RAM": "RAM", + "Disk": "Disk", + "OS": "OS", + "IP": "IP", + "Host": "Host", + "Temperature": "Temperature", + "Usage": "Usage", + "Tabs": { + "General": "General", + "Hardware": "Hardware", + "Host": "Host", + "Monitoring": "Monitoring" + } + }, "ItemsPerPage": { "items": "items", "item": "item", @@ -19,24 +38,31 @@ "20": "20 items", "25": "25 items", "Custom": "Custom (1-100)" - }, - "Server": { - "CPU": "CPU", - "GPU": "GPU", - "RAM": "RAM", - "Disk": "Disk", - "OS": "OS", - "IP": "IP", - "Host": "Host", - "Temperature": "Temperature", - "Tabs": { - "General": "General", - "Hardware": "Hardware", - "Host": "Host", - "Monitoring": "Monitoring" - } } }, + "Server": { + "Hardware": "Hardware", + "Network": "Network", + "CurrentUsage": "Current Usage", + "UsageHistory": "Usage History", + "ResourceUsageHistory": "Resource Usage History", + "TimeRange": { + "Select": "Select time range", + "LastHour": "Last Hour", + "Last24Hours": "Last 24 Hours", + "Last7Days": "Last 7 Days", + "Last30Days": "Last 30 Days" + }, + "VirtualMachines": "Virtual Machines", + "VirtualMachinesDescription": "Virtual machines hosted on this server", + "HardwareInformation": "Hardware Information", + "ManagementURL": "Management URL", + "VM": "VM", + "Physical": "Physical", + "HostedOn": "Hosted on", + "NotFound": "Server not found", + "NotFoundDescription": "The server you are looking for could not be found." + }, "Sidebar": { "Main Navigation": "Main Navigation", "Dashboard": "Dashboard", From 3e4f7c3641378f1e218b736d5a5efbe6aee62388 Mon Sep 17 00:00:00 2001 From: headlessdev Date: Tue, 29 Apr 2025 19:38:48 +0200 Subject: [PATCH 20/54] i18n final --- app/dashboard/applications/Applications.tsx | 131 +++---- app/dashboard/network/Networks.tsx | 6 +- app/dashboard/settings/Settings.tsx | 228 +++++------ app/dashboard/uptime/Uptime.tsx | 69 ++-- i18n/languages/de.json | 403 ++++++++++++++++++++ i18n/languages/en.json | 201 ++++++++++ 6 files changed, 797 insertions(+), 241 deletions(-) create mode 100644 i18n/languages/de.json diff --git a/app/dashboard/applications/Applications.tsx b/app/dashboard/applications/Applications.tsx index 979607a..0565efb 100644 --- a/app/dashboard/applications/Applications.tsx +++ b/app/dashboard/applications/Applications.tsx @@ -85,6 +85,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { useTranslations } from "next-intl"; interface Application { id: number; @@ -112,6 +113,7 @@ interface ApplicationsResponse { } export default function Dashboard() { + const t = useTranslations(); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [icon, setIcon] = useState(""); @@ -182,31 +184,28 @@ export default function Dashboard() { }; const handleItemsPerPageChange = (value: string) => { - // Clear any existing timer if (debounceTimerRef.current) { clearTimeout(debounceTimerRef.current); } - // Set a new timer debounceTimerRef.current = setTimeout(() => { const newItemsPerPage = parseInt(value); - // Ensure the value is within the valid range if (isNaN(newItemsPerPage) || newItemsPerPage < 1) { - toast.error("Please enter a number between 1 and 100"); + toast.error(t('Applications.Messages.NumberValidation')); return; } const validatedValue = Math.min(Math.max(newItemsPerPage, 1), 100); setItemsPerPage(validatedValue); - setCurrentPage(1); // Reset to first page when changing items per page + setCurrentPage(1); Cookies.set("itemsPerPage-app", String(validatedValue), { expires: 365, path: "/", sameSite: "strict", }); - }, 300); // 300ms delay + }, 300); }; const add = async () => { @@ -221,10 +220,10 @@ export default function Dashboard() { uptimecheckUrl: customUptimeCheck ? uptimecheckUrl : "", }); getApplications(); - toast.success("Application added successfully"); + toast.success(t('Applications.Messages.AddSuccess')); } catch (error: any) { console.log(error.response?.data); - toast.error("Failed to add application"); + toast.error(t('Applications.Messages.AddError')); } }; @@ -244,7 +243,7 @@ export default function Dashboard() { setLoading(false); } catch (error: any) { console.log(error.response?.data); - toast.error("Failed to get applications"); + toast.error(t('Applications.Messages.GetError')); } }; @@ -265,10 +264,10 @@ export default function Dashboard() { try { await axios.post("/api/applications/delete", { id }); getApplications(); - toast.success("Application deleted successfully"); + toast.success(t('Applications.Messages.DeleteSuccess')); } catch (error: any) { console.log(error.response?.data); - toast.error("Failed to delete application"); + toast.error(t('Applications.Messages.DeleteError')); } }; @@ -306,10 +305,10 @@ export default function Dashboard() { }); getApplications(); setEditId(null); - toast.success("Application edited successfully"); + toast.success(t('Applications.Messages.EditSuccess')); } catch (error: any) { console.log(error.response.data); - toast.error("Failed to edit application"); + toast.error(t('Applications.Messages.EditError')); } }; @@ -363,11 +362,11 @@ export default function Dashboard() { - My Infrastructure + {t('Applications.Breadcrumb.MyInfrastructure')} - Applications + {t('Applications.Breadcrumb.Applications')} @@ -376,11 +375,11 @@ export default function Dashboard() {
- Your Applications + {t('Applications.Title')}
-