mirror of
https://github.com/crocofied/CoreControl.git
synced 2025-12-18 16:07:10 +00:00
Servers.tsx i18n 1/2
This commit is contained in:
parent
eff7901b67
commit
58e2466875
@ -66,6 +66,7 @@ import NextLink from "next/link"
|
|||||||
import { Toaster } from "@/components/ui/sonner"
|
import { Toaster } from "@/components/ui/sonner"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
|
|
||||||
interface ServerHistory {
|
interface ServerHistory {
|
||||||
labels: string[];
|
labels: string[];
|
||||||
@ -122,7 +123,8 @@ interface MonitoringData {
|
|||||||
temp?: number
|
temp?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Servers() {
|
||||||
|
const t = useTranslations('Servers')
|
||||||
const [host, setHost] = useState<boolean>(false)
|
const [host, setHost] = useState<boolean>(false)
|
||||||
const [hostServer, setHostServer] = useState<number>(0)
|
const [hostServer, setHostServer] = useState<number>(0)
|
||||||
const [name, setName] = useState<string>("")
|
const [name, setName] = useState<string>("")
|
||||||
@ -465,18 +467,14 @@ export default function Dashboard() {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Handler für benutzerdefinierte Zahleneingaben mit Verzögerung
|
|
||||||
const handleItemsPerPageChange = (value: string) => {
|
const handleItemsPerPageChange = (value: string) => {
|
||||||
// Bestehenden Timer löschen
|
|
||||||
if (debounceTimerRef.current) {
|
if (debounceTimerRef.current) {
|
||||||
clearTimeout(debounceTimerRef.current);
|
clearTimeout(debounceTimerRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neuen Timer setzen
|
|
||||||
debounceTimerRef.current = setTimeout(() => {
|
debounceTimerRef.current = setTimeout(() => {
|
||||||
const newItemsPerPage = parseInt(value);
|
const newItemsPerPage = parseInt(value);
|
||||||
|
|
||||||
// Sicherstellen, dass der Wert im gültigen Bereich liegt
|
|
||||||
if (isNaN(newItemsPerPage) || newItemsPerPage < 1) {
|
if (isNaN(newItemsPerPage) || newItemsPerPage < 1) {
|
||||||
toast.error("Bitte eine Zahl zwischen 1 und 100 eingeben");
|
toast.error("Bitte eine Zahl zwischen 1 und 100 eingeben");
|
||||||
return;
|
return;
|
||||||
@ -485,37 +483,31 @@ export default function Dashboard() {
|
|||||||
const validatedValue = Math.min(Math.max(newItemsPerPage, 1), 100);
|
const validatedValue = Math.min(Math.max(newItemsPerPage, 1), 100);
|
||||||
|
|
||||||
setItemsPerPage(validatedValue);
|
setItemsPerPage(validatedValue);
|
||||||
setCurrentPage(1); // Zurück zur ersten Seite
|
setCurrentPage(1);
|
||||||
Cookies.set("itemsPerPage-servers", String(validatedValue), {
|
Cookies.set("itemsPerPage-servers", String(validatedValue), {
|
||||||
expires: 365,
|
expires: 365,
|
||||||
path: "/",
|
path: "/",
|
||||||
sameSite: "strict",
|
sameSite: "strict",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Daten mit neuer Paginierung abrufen
|
|
||||||
getServers();
|
getServers();
|
||||||
}, 600); // 600ms Verzögerung für bessere Eingabe mehrziffriger Zahlen
|
}, 600);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handler für voreingestellte Werte aus dem Dropdown
|
|
||||||
const handlePresetItemsPerPageChange = (value: string) => {
|
const handlePresetItemsPerPageChange = (value: string) => {
|
||||||
// Für voreingestellte Werte sofort anwenden
|
|
||||||
const newItemsPerPage = parseInt(value);
|
const newItemsPerPage = parseInt(value);
|
||||||
|
|
||||||
// Nur Standardwerte hier verarbeiten
|
|
||||||
if ([4, 6, 10, 15, 20, 25].includes(newItemsPerPage)) {
|
if ([4, 6, 10, 15, 20, 25].includes(newItemsPerPage)) {
|
||||||
setItemsPerPage(newItemsPerPage);
|
setItemsPerPage(newItemsPerPage);
|
||||||
setCurrentPage(1); // Zurück zur ersten Seite
|
setCurrentPage(1);
|
||||||
Cookies.set("itemsPerPage-servers", String(newItemsPerPage), {
|
Cookies.set("itemsPerPage-servers", String(newItemsPerPage), {
|
||||||
expires: 365,
|
expires: 365,
|
||||||
path: "/",
|
path: "/",
|
||||||
sameSite: "strict",
|
sameSite: "strict",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Daten mit neuer Paginierung abrufen
|
|
||||||
getServers();
|
getServers();
|
||||||
} else {
|
} else {
|
||||||
// Für benutzerdefinierte Werte den verzögerten Handler verwenden
|
|
||||||
handleItemsPerPageChange(value);
|
handleItemsPerPageChange(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -535,11 +527,11 @@ export default function Dashboard() {
|
|||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
<BreadcrumbSeparator className="hidden md:block" />
|
<BreadcrumbSeparator className="hidden md:block" />
|
||||||
<BreadcrumbItem>
|
<BreadcrumbItem>
|
||||||
<BreadcrumbPage>My Infrastructure</BreadcrumbPage>
|
<BreadcrumbPage>{t('MyInfrastructure')}</BreadcrumbPage>
|
||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
<BreadcrumbSeparator className="hidden md:block" />
|
<BreadcrumbSeparator className="hidden md:block" />
|
||||||
<BreadcrumbItem>
|
<BreadcrumbItem>
|
||||||
<BreadcrumbPage>Servers</BreadcrumbPage>
|
<BreadcrumbPage>{t('Servers')}</BreadcrumbPage>
|
||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
</BreadcrumbList>
|
</BreadcrumbList>
|
||||||
</Breadcrumb>
|
</Breadcrumb>
|
||||||
@ -548,11 +540,11 @@ export default function Dashboard() {
|
|||||||
<Toaster />
|
<Toaster />
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-3xl font-bold">Your Servers</span>
|
<span className="text-3xl font-bold">{t('YourServers')}</span>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="outline" size="icon" title="Change view">
|
<Button variant="outline" size="icon" title={t('ChangeView')}>
|
||||||
{isGridLayout ? (
|
{isGridLayout ? (
|
||||||
<LayoutGrid className="h-4 w-4" />
|
<LayoutGrid className="h-4 w-4" />
|
||||||
) : (
|
) : (
|
||||||
@ -562,10 +554,10 @@ export default function Dashboard() {
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
<DropdownMenuItem onClick={() => toggleLayout(false)}>
|
<DropdownMenuItem onClick={() => toggleLayout(false)}>
|
||||||
<List className="h-4 w-4 mr-2" /> List View
|
<List className="h-4 w-4 mr-2" /> {t('ListView')}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => toggleLayout(true)}>
|
<DropdownMenuItem onClick={() => toggleLayout(true)}>
|
||||||
<LayoutGrid className="h-4 w-4 mr-2" /> Grid View
|
<LayoutGrid className="h-4 w-4 mr-2" /> {t('GridView')}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
@ -581,23 +573,23 @@ export default function Dashboard() {
|
|||||||
>
|
>
|
||||||
<SelectTrigger className="w-[140px]">
|
<SelectTrigger className="w-[140px]">
|
||||||
<SelectValue>
|
<SelectValue>
|
||||||
{itemsPerPage} {itemsPerPage === 1 ? 'item' : 'items'}
|
{itemsPerPage} {itemsPerPage === 1 ? t('ItemsPerPage.item') : t('ItemsPerPage.items')}
|
||||||
</SelectValue>
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{![4, 6, 10, 15, 20, 25].includes(itemsPerPage) ? (
|
{![4, 6, 10, 15, 20, 25].includes(itemsPerPage) ? (
|
||||||
<SelectItem value={String(itemsPerPage)}>
|
<SelectItem value={String(itemsPerPage)}>
|
||||||
{itemsPerPage} {itemsPerPage === 1 ? 'item' : 'items'} (custom)
|
{itemsPerPage} {itemsPerPage === 1 ? t('ItemsPerPage.item') : t('ItemsPerPage.items')} ({t('ItemsPerPage.Custom')})
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
) : null}
|
) : null}
|
||||||
<SelectItem value="4">4 items</SelectItem>
|
<SelectItem value="4">{t('4')}</SelectItem>
|
||||||
<SelectItem value="6">6 items</SelectItem>
|
<SelectItem value="6">{t('6')}</SelectItem>
|
||||||
<SelectItem value="10">10 items</SelectItem>
|
<SelectItem value="10">{t('10')}</SelectItem>
|
||||||
<SelectItem value="15">15 items</SelectItem>
|
<SelectItem value="15">{t('15')}</SelectItem>
|
||||||
<SelectItem value="20">20 items</SelectItem>
|
<SelectItem value="20">{t('20')}</SelectItem>
|
||||||
<SelectItem value="25">25 items</SelectItem>
|
<SelectItem value="25">{t('25')}</SelectItem>
|
||||||
<div className="p-2 border-t mt-1">
|
<div className="p-2 border-t mt-1">
|
||||||
<Label htmlFor="custom-items" className="text-xs font-medium">Custom (1-100)</Label>
|
<Label htmlFor="custom-items" className="text-xs font-medium">{t('ItemsPerPage.Custom')}</Label>
|
||||||
<div className="flex items-center gap-2 mt-1">
|
<div className="flex items-center gap-2 mt-1">
|
||||||
<Input
|
<Input
|
||||||
id="custom-items"
|
id="custom-items"
|
||||||
@ -608,8 +600,6 @@ export default function Dashboard() {
|
|||||||
className="h-8"
|
className="h-8"
|
||||||
defaultValue={itemsPerPage}
|
defaultValue={itemsPerPage}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
// Änderung nicht sofort anwenden während des Tippens
|
|
||||||
// Nur visuelles Feedback für die Validierung
|
|
||||||
const value = parseInt(e.target.value);
|
const value = parseInt(e.target.value);
|
||||||
if (isNaN(value) || value < 1 || value > 100) {
|
if (isNaN(value) || value < 1 || value > 100) {
|
||||||
e.target.classList.add("border-red-500");
|
e.target.classList.add("border-red-500");
|
||||||
@ -618,7 +608,6 @@ export default function Dashboard() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
// Änderung anwenden, wenn das Input den Fokus verliert
|
|
||||||
const value = parseInt(e.target.value);
|
const value = parseInt(e.target.value);
|
||||||
if (value >= 1 && value <= 100) {
|
if (value >= 1 && value <= 100) {
|
||||||
handleItemsPerPageChange(e.target.value);
|
handleItemsPerPageChange(e.target.value);
|
||||||
@ -626,7 +615,6 @@ export default function Dashboard() {
|
|||||||
}}
|
}}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
// Bestehenden Debounce-Timer löschen, um sofort anzuwenden
|
|
||||||
if (debounceTimerRef.current) {
|
if (debounceTimerRef.current) {
|
||||||
clearTimeout(debounceTimerRef.current);
|
clearTimeout(debounceTimerRef.current);
|
||||||
debounceTimerRef.current = null;
|
debounceTimerRef.current = null;
|
||||||
@ -634,7 +622,6 @@ export default function Dashboard() {
|
|||||||
|
|
||||||
const value = parseInt((e.target as HTMLInputElement).value);
|
const value = parseInt((e.target as HTMLInputElement).value);
|
||||||
if (value >= 1 && value <= 100) {
|
if (value >= 1 && value <= 100) {
|
||||||
// Änderung sofort bei Enter anwenden
|
|
||||||
const validatedValue = Math.min(Math.max(value, 1), 100);
|
const validatedValue = Math.min(Math.max(value, 1), 100);
|
||||||
setItemsPerPage(validatedValue);
|
setItemsPerPage(validatedValue);
|
||||||
setCurrentPage(1);
|
setCurrentPage(1);
|
||||||
@ -644,11 +631,8 @@ export default function Dashboard() {
|
|||||||
sameSite: "strict",
|
sameSite: "strict",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Kurze Verzögerung hinzufügen für bessere Reaktionsfähigkeit
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getServers();
|
getServers();
|
||||||
|
|
||||||
// Dropdown schließen
|
|
||||||
document.body.click();
|
document.body.click();
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
@ -656,7 +640,7 @@ export default function Dashboard() {
|
|||||||
}}
|
}}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
/>
|
/>
|
||||||
<span className="text-xs text-muted-foreground whitespace-nowrap">items</span>
|
<span className="text-xs text-muted-foreground whitespace-nowrap">{t('ItemsPerPage.items')}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
@ -671,7 +655,7 @@ export default function Dashboard() {
|
|||||||
<AlertDialogContent className="max-w-[95vw] w-[600px] max-h-[90vh] overflow-y-auto">
|
<AlertDialogContent className="max-w-[95vw] w-[600px] max-h-[90vh] overflow-y-auto">
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
|
<AlertDialogTitle className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
|
||||||
<span>Add a server</span>
|
<span>{t('AddServer.Title')}</span>
|
||||||
<Select
|
<Select
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
@ -727,20 +711,20 @@ export default function Dashboard() {
|
|||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
<Tabs defaultValue="general" className="w-full">
|
<Tabs defaultValue="general" className="w-full">
|
||||||
<TabsList className="w-full">
|
<TabsList className="w-full">
|
||||||
<TabsTrigger value="general">General</TabsTrigger>
|
<TabsTrigger value="general">{t('Tabs.General')}</TabsTrigger>
|
||||||
<TabsTrigger value="hardware">Hardware</TabsTrigger>
|
<TabsTrigger value="hardware">{t('Tabs.Hardware')}</TabsTrigger>
|
||||||
<TabsTrigger value="virtualization">Host</TabsTrigger>
|
<TabsTrigger value="virtualization">{t('Tabs.Host')}</TabsTrigger>
|
||||||
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
|
<TabsTrigger value="monitoring">{t('Tabs.Monitoring')}</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent value="general">
|
<TabsContent value="general">
|
||||||
<div className="space-y-4 pt-4">
|
<div className="space-y-4 pt-4">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
||||||
<div className="grid w-full sm:w-[calc(100%-52px)] items-center gap-1.5">
|
<div className="grid w-full sm:w-[calc(100%-52px)] items-center gap-1.5">
|
||||||
<Label htmlFor="icon">Icon</Label>
|
<Label htmlFor="icon">{t('AddServer.General.Icon')}</Label>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Select value={icon} onValueChange={(value) => setIcon(value)}>
|
<Select value={icon} onValueChange={(value) => setIcon(value)}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue placeholder="Select an icon">
|
<SelectValue placeholder={t('AddServer.General.IconPlaceholder')}>
|
||||||
{icon && (
|
{icon && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<DynamicIcon name={icon as any} size={18} />
|
<DynamicIcon name={icon as any} size={18} />
|
||||||
@ -751,7 +735,7 @@ export default function Dashboard() {
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent className="max-h-[300px]">
|
<SelectContent className="max-h-[300px]">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Search icons..."
|
placeholder={t('AddServer.General.IconSearchPlaceholder')}
|
||||||
className="mb-2"
|
className="mb-2"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const iconElements = document.querySelectorAll("[data-icon-item]")
|
const iconElements = document.querySelectorAll("[data-icon-item]")
|
||||||
@ -792,14 +776,14 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid w-[52px] items-center gap-1.5">
|
<div className="grid w-[52px] items-center gap-1.5">
|
||||||
<Label htmlFor="icon">Preview</Label>
|
<Label htmlFor="icon">{t('AddServer.General.Preview')}</Label>
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
{icon && <DynamicIcon name={icon as any} size={36} />}
|
{icon && <DynamicIcon name={icon as any} size={36} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="name">Name</Label>
|
<Label htmlFor="name">{t('AddServer.General.Name')}</Label>
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
type="text"
|
type="text"
|
||||||
@ -810,11 +794,11 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="description">
|
<Label htmlFor="description">
|
||||||
Operating System <span className="text-stone-600">(optional)</span>
|
{t('AddServer.General.OperatingSystem')} <span className="text-stone-600">({t('optional')})</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Select value={os} onValueChange={(value) => setOs(value)}>
|
<Select value={os} onValueChange={(value) => setOs(value)}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue placeholder="Select OS" />
|
<SelectValue placeholder={t('AddServer.General.OperatingSystemPlaceholder')} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="Windows">Windows</SelectItem>
|
<SelectItem value="Windows">Windows</SelectItem>
|
||||||
@ -825,7 +809,7 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="ip">
|
<Label htmlFor="ip">
|
||||||
IP Adress <span className="text-stone-600">(optional)</span>
|
{t('AddServer.General.IPAdress')} <span className="text-stone-600">({t('optional')})</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="ip"
|
id="ip"
|
||||||
@ -840,12 +824,11 @@ export default function Dashboard() {
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Label htmlFor="publicURL">
|
<Label htmlFor="publicURL">
|
||||||
Management URL <span className="text-stone-600">(optional)</span>
|
{t('AddServer.General.ManagementURL')} <span className="text-stone-600">({t('optional')})</span>
|
||||||
</Label>
|
</Label>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
Link to a web interface (e.g. Proxmox or Portainer) with which the server can be
|
{t('AddServer.General.ManagementURLTooltip')}
|
||||||
managed
|
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
@ -863,7 +846,7 @@ export default function Dashboard() {
|
|||||||
<div className="space-y-4 pt-4">
|
<div className="space-y-4 pt-4">
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="cpu">
|
<Label htmlFor="cpu">
|
||||||
CPU <span className="text-stone-600">(optional)</span>
|
{t('AddServer.Hardware.CPU')} <span className="text-stone-600">({t('optional')})</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="cpu"
|
id="cpu"
|
||||||
@ -875,7 +858,7 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="gpu">
|
<Label htmlFor="gpu">
|
||||||
GPU <span className="text-stone-600">(optional)</span>
|
{t('AddServer.Hardware.GPU')} <span className="text-stone-600">({t('optional')})</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="gpu"
|
id="gpu"
|
||||||
@ -887,7 +870,7 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="ram">
|
<Label htmlFor="ram">
|
||||||
RAM <span className="text-stone-600">(optional)</span>
|
{t('AddServer.Hardware.RAM')} <span className="text-stone-600">({t('optional')})</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="ram"
|
id="ram"
|
||||||
@ -899,7 +882,7 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="disk">
|
<Label htmlFor="disk">
|
||||||
Disk <span className="text-stone-600">(optional)</span>
|
{t('AddServer.Hardware.Disk')} <span className="text-stone-600">({t('optional')})</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="disk"
|
id="disk"
|
||||||
@ -919,11 +902,11 @@ export default function Dashboard() {
|
|||||||
checked={host}
|
checked={host}
|
||||||
onCheckedChange={(checked) => setHost(checked === true)}
|
onCheckedChange={(checked) => setHost(checked === true)}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="hostCheckbox">Mark as host server</Label>
|
<Label htmlFor="hostCheckbox">{t('AddServer.Host.MarkAsHostServer')}</Label>
|
||||||
</div>
|
</div>
|
||||||
{!host && (
|
{!host && (
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label>Host Server</Label>
|
<Label>{t('AddServer.Host.SelectHostServer')}</Label>
|
||||||
<Select
|
<Select
|
||||||
value={hostServer?.toString()}
|
value={hostServer?.toString()}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
@ -935,10 +918,10 @@ export default function Dashboard() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Select a host server" />
|
<SelectValue placeholder={t('AddServer.Host.SelectHostServerPlaceholder')} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="0">No host server</SelectItem>
|
<SelectItem value="0">{t('AddServer.Host.NoHostServer')}</SelectItem>
|
||||||
{hostServers.map((server) => (
|
{hostServers.map((server) => (
|
||||||
<SelectItem key={server.id} value={server.id.toString()}>
|
<SelectItem key={server.id} value={server.id.toString()}>
|
||||||
{server.name}
|
{server.name}
|
||||||
@ -958,12 +941,12 @@ export default function Dashboard() {
|
|||||||
checked={monitoring}
|
checked={monitoring}
|
||||||
onCheckedChange={(checked) => setMonitoring(checked === true)}
|
onCheckedChange={(checked) => setMonitoring(checked === true)}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="monitoringCheckbox">Enable monitoring</Label>
|
<Label htmlFor="monitoringCheckbox">{t('AddServer.Monitoring.Enable')}</Label>
|
||||||
</div>
|
</div>
|
||||||
{monitoring && (
|
{monitoring && (
|
||||||
<>
|
<>
|
||||||
<div className="grid w-full items-center gap-1.5">
|
<div className="grid w-full items-center gap-1.5">
|
||||||
<Label htmlFor="monitoringURL">Monitoring URL</Label>
|
<Label htmlFor="monitoringURL">{t('AddServer.Monitoring.URL')}</Label>
|
||||||
<Input
|
<Input
|
||||||
id="monitoringURL"
|
id="monitoringURL"
|
||||||
type="text"
|
type="text"
|
||||||
@ -973,9 +956,9 @@ export default function Dashboard() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 p-4 border rounded-lg bg-muted">
|
<div className="mt-4 p-4 border rounded-lg bg-muted">
|
||||||
<h4 className="text-sm font-semibold mb-2">Required Server Setup</h4>
|
<h4 className="text-sm font-semibold mb-2">{t('AddServer.Monitoring.SetupTitle')}</h4>
|
||||||
<p className="text-sm text-muted-foreground mb-3">
|
<p className="text-sm text-muted-foreground mb-3">
|
||||||
To enable monitoring, you need to install Glances on your server. Here's an example Docker Compose configuration:
|
{t('AddServer.Monitoring.SetupDescription')}
|
||||||
</p>
|
</p>
|
||||||
<pre className="bg-background p-4 rounded-md text-sm overflow-x-auto">
|
<pre className="bg-background p-4 rounded-md text-sm overflow-x-auto">
|
||||||
<code>{`services:
|
<code>{`services:
|
||||||
@ -1000,8 +983,8 @@ export default function Dashboard() {
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>{t('cancel')}</AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={add}>Add</AlertDialogAction>
|
<AlertDialogAction onClick={add}>{t('add')}</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|||||||
@ -47,5 +47,68 @@
|
|||||||
"ActiveConnections": "Active Connections",
|
"ActiveConnections": "Active Connections",
|
||||||
"ViewNetworkDetails": "View network details"
|
"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:"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user