feat(i18n): localize frontend components and add missing translations

- Replaced hardcoded UI strings with translation keys across frontend files
- Added and updated English(en) and Khmer(km) translation files for settings, notifications, and server components
- Improved localization and multi-language support throughout the frontend
This commit is contained in:
lyker189
2025-10-02 05:10:11 +07:00
parent a4364936e3
commit b6ef4ff7a5
62 changed files with 2721 additions and 639 deletions
@@ -4,6 +4,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Table, TableBody } from "@/components/ui/table";
import { DockerContainer } from "@/types/docker.types";
import { DockerMetricsDialog } from "./DockerMetricsDialog";
import { useLanguage } from "@/contexts/LanguageContext";
import {
DockerTableSearch,
DockerTableHeader,
@@ -18,6 +19,7 @@ interface DockerContainersTableProps {
}
export const DockerContainersTable = ({ containers, isLoading, onRefresh }: DockerContainersTableProps) => {
const { t } = useLanguage();
const [searchTerm, setSearchTerm] = useState("");
const [selectedContainer, setSelectedContainer] = useState<DockerContainer | null>(null);
const [metricsDialogOpen, setMetricsDialogOpen] = useState(false);
@@ -49,7 +51,7 @@ export const DockerContainersTable = ({ containers, isLoading, onRefresh }: Dock
<CardHeader className="pb-4 px-0">
<div className="flex flex-col gap-4">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<CardTitle className="text-lg sm:text-xl font-semibold">Docker Containers</CardTitle>
<CardTitle className="text-lg sm:text-xl font-semibold">{t('dockerContainers', 'docker')}</CardTitle>
<DockerTableSearch
searchTerm={searchTerm}
onSearchChange={setSearchTerm}
@@ -10,6 +10,7 @@ import { DockerContainer, DockerMetrics } from "@/types/docker.types";
import { dockerService } from "@/services/dockerService";
import { Loader2, Cpu, HardDrive, Network, MemoryStick } from "lucide-react";
import { useTheme } from "@/contexts/ThemeContext";
import { useLanguage } from "@/contexts/LanguageContext";
interface DockerMetricsDialogProps {
container: DockerContainer | null;
@@ -20,16 +21,17 @@ interface DockerMetricsDialogProps {
type TimeRange = '60m' | '1d' | '7d' | '1m' | '3m';
const timeRangeOptions = [
{ value: '60m' as TimeRange, label: '60 minutes', hours: 1 },
{ value: '1d' as TimeRange, label: '1 day', hours: 24 },
{ value: '7d' as TimeRange, label: '7 days', hours: 24 * 7 },
{ value: '1m' as TimeRange, label: '1 month', hours: 24 * 30 },
{ value: '3m' as TimeRange, label: '3 months', hours: 24 * 90 },
{ value: '60m' as TimeRange, label: 'minutes60', hours: 1 },
{ value: '1d' as TimeRange, label: 'day1', hours: 24 },
{ value: '7d' as TimeRange, label: 'days7', hours: 24 * 7 },
{ value: '1m' as TimeRange, label: 'month1', hours: 24 * 30 },
{ value: '3m' as TimeRange, label: 'months3', hours: 24 * 90 },
];
export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMetricsDialogProps) => {
const [timeRange, setTimeRange] = useState<TimeRange>("1d");
const { theme } = useTheme();
const { t } = useLanguage();
const {
data: metrics = [],
@@ -232,11 +234,11 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<DialogContent className="max-w-7xl max-h-[95vh] overflow-y-auto bg-background text-foreground">
<DialogHeader>
<DialogTitle className="flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="flex items-center gap-2">
<div className="h-8 w-8 rounded bg-primary/10 flex items-center justify-center">
<Cpu className="h-4 w-4 text-primary" />
</div>
Container Metrics: {container.name}
{t('containerMetricsTitle', 'docker', { name: container.name })}
</div>
<div className="flex items-center gap-2">
<Select value={timeRange} onValueChange={(value: TimeRange) => setTimeRange(value)}>
@@ -246,7 +248,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<SelectContent>
{timeRangeOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
{t(option.label, 'docker')}
</SelectItem>
))}
</SelectContent>
@@ -254,22 +256,22 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
</div>
</DialogTitle>
<p className="text-sm text-muted-foreground">
Docker ID: {container.docker_id} {container.hostname}
{t('dockerId', 'docker')}: {container.docker_id} {container.hostname}
</p>
</DialogHeader>
{isLoading ? (
<div className="flex items-center justify-center h-96">
<Loader2 className="h-8 w-8 animate-spin" />
<span className="ml-2">Loading metrics...</span>
<span className="ml-2">{t('loadingMetrics', 'docker')}</span>
</div>
) : error ? (
<div className="flex items-center justify-center h-96 text-muted-foreground">
<p>Error loading metrics: {error.message}</p>
<p>{t('errorLoadingMetrics', 'docker')}: {String((error as any)?.message ?? '')}</p>
</div>
) : chartData.length === 0 ? (
<div className="flex items-center justify-center h-96 text-muted-foreground">
<p>No metrics data available for this container</p>
<p>{t('noMetricsAvailable', 'docker')}</p>
</div>
) : (
<>
@@ -277,7 +279,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
{latestMetric && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<MetricCard
title="CPU"
title={t('cpu', 'docker')}
used={`${latestMetric.cpuUsage}%`}
total={`${latestMetric.cpuCores} cores`}
free={`${(100 - latestMetric.cpuUsage).toFixed(1)}%`}
@@ -286,7 +288,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
color={chartConfig.cpuUsage.color}
/>
<MetricCard
title="Memory"
title={t('memoryTitle', 'docker')}
used={latestMetric.ramUsed}
total={latestMetric.ramTotal}
free={latestMetric.ramFree}
@@ -295,7 +297,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
color={chartConfig.ramUsagePercent.color}
/>
<MetricCard
title="Disk"
title={t('diskTitle', 'docker')}
used={latestMetric.diskUsed}
total={latestMetric.diskTotal}
free={latestMetric.diskFree}
@@ -304,10 +306,10 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
color={chartConfig.diskUsagePercent.color}
/>
<MetricCard
title="Network"
title={t('network', 'docker')}
used={`RX: ${latestMetric.networkRx}`}
total={`TX: ${latestMetric.networkTx}`}
free={`Speed: ${latestMetric.networkRxSpeed} KB/s`}
free={`${t('networkSpeedKbs', 'docker').replace('(KB/s)', '')}: ${latestMetric.networkRxSpeed} KB/s`}
percentage={0}
icon={Network}
color={chartConfig.networkRx.color}
@@ -319,19 +321,19 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<TabsList className="grid w-full grid-cols-4 bg-muted">
<TabsTrigger value="cpu" className="flex items-center gap-2 data-[state=active]:bg-background">
<Cpu className="h-4 w-4" />
CPU
{t('cpu', 'docker')}
</TabsTrigger>
<TabsTrigger value="memory" className="flex items-center gap-2 data-[state=active]:bg-background">
<MemoryStick className="h-4 w-4" />
Memory
{t('memoryTitle', 'docker')}
</TabsTrigger>
<TabsTrigger value="disk" className="flex items-center gap-2 data-[state=active]:bg-background">
<HardDrive className="h-4 w-4" />
Disk
{t('diskTitle', 'docker')}
</TabsTrigger>
<TabsTrigger value="network" className="flex items-center gap-2 data-[state=active]:bg-background">
<Network className="h-4 w-4" />
Network
{t('network', 'docker')}
</TabsTrigger>
</TabsList>
@@ -339,7 +341,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">CPU Usage (%)</CardTitle>
<CardTitle className="text-foreground">{t('cpuUsagePct', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-80">
@@ -365,7 +367,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={chartConfig.cpuUsage.color}
strokeWidth={2}
dot={{ r: 3, fill: chartConfig.cpuUsage.color }}
name="CPU Usage (%)"
name={t('cpuUsagePct', 'docker')}
/>
</LineChart>
</ChartContainer>
@@ -374,7 +376,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">CPU Usage vs Available</CardTitle>
<CardTitle className="text-foreground">{t('cpuUsageVsAvailable', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-80">
@@ -401,7 +403,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={theme === 'dark' ? "#6b7280" : "#9ca3af"}
fill={theme === 'dark' ? "#6b7280" : "#9ca3af"}
fillOpacity={0.3}
name="CPU Available (%)"
name={t('cpuAvailablePct', 'docker')}
/>
<Area
type="monotone"
@@ -410,7 +412,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={chartConfig.cpuUsage.color}
fill={chartConfig.cpuUsage.color}
fillOpacity={0.6}
name="CPU Usage (%)"
name={t('cpuUsagePct', 'docker')}
/>
</AreaChart>
</ChartContainer>
@@ -423,7 +425,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">Memory Usage (%)</CardTitle>
<CardTitle className="text-foreground">{t('ramUsagePct', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-80">
@@ -459,7 +461,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">Memory Usage (Bytes)</CardTitle>
<CardTitle className="text-foreground">{t('memoryUsageBytes', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-80">
@@ -479,8 +481,8 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
content={<ChartTooltipContent className="bg-popover border-border" />}
cursor={{ stroke: getGridColor() }}
formatter={(value, name) => [
name === 'Used Memory' ? formatBytes(Number(value)) :
name === 'Total Memory' ? formatBytes(Number(value)) : value,
name === t('usedMemory', 'docker') ? formatBytes(Number(value)) :
name === t('totalMemory', 'docker') ? formatBytes(Number(value)) : value,
name
]}
/>
@@ -491,7 +493,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={theme === 'dark' ? "#6b7280" : "#9ca3af"}
fill={theme === 'dark' ? "#6b7280" : "#9ca3af"}
fillOpacity={0.3}
name="Total Memory"
name={t('totalMemory', 'docker')}
/>
<Area
type="monotone"
@@ -500,7 +502,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={chartConfig.ramUsagePercent.color}
fill={chartConfig.ramUsagePercent.color}
fillOpacity={0.6}
name="Used Memory"
name={t('usedMemory', 'docker')}
/>
</AreaChart>
</ChartContainer>
@@ -513,7 +515,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">Disk Usage (%)</CardTitle>
<CardTitle className="text-foreground">{t('diskUsagePct', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-80">
@@ -540,7 +542,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={chartConfig.diskUsagePercent.color}
fill={chartConfig.diskUsagePercent.color}
fillOpacity={0.6}
name="Disk Usage (%)"
name={t('diskUsagePct', 'docker')}
/>
</AreaChart>
</ChartContainer>
@@ -549,7 +551,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">Disk Usage (Bytes)</CardTitle>
<CardTitle className="text-foreground">{t('diskUsageBytes', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-80">
@@ -569,8 +571,8 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
content={<ChartTooltipContent className="bg-popover border-border" />}
cursor={{ stroke: getGridColor() }}
formatter={(value, name) => [
name === 'Used Disk' ? formatBytes(Number(value)) :
name === 'Total Disk' ? formatBytes(Number(value)) : value,
name === t('usedDisk', 'docker') ? formatBytes(Number(value)) :
name === t('totalDisk', 'docker') ? formatBytes(Number(value)) : value,
name
]}
/>
@@ -581,7 +583,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={theme === 'dark' ? "#6b7280" : "#9ca3af"}
fill={theme === 'dark' ? "#6b7280" : "#9ca3af"}
fillOpacity={0.3}
name="Total Disk"
name={t('totalDisk', 'docker')}
/>
<Area
type="monotone"
@@ -590,7 +592,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
stroke={chartConfig.diskUsagePercent.color}
fill={chartConfig.diskUsagePercent.color}
fillOpacity={0.6}
name="Used Disk"
name={t('usedDisk', 'docker')}
/>
</AreaChart>
</ChartContainer>
@@ -603,7 +605,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">Network Traffic</CardTitle>
<CardTitle className="text-foreground">{t('networkTraffic', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-64">
@@ -627,7 +629,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
dataKey="networkRxBytes"
stroke={chartConfig.networkRx.color}
strokeWidth={2}
name="RX Bytes"
name={t('rxBytes', 'docker')}
dot={{ r: 2 }}
/>
<Line
@@ -635,7 +637,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
dataKey="networkTxBytes"
stroke={chartConfig.networkTx.color}
strokeWidth={2}
name="TX Bytes"
name={t('txBytes', 'docker')}
dot={{ r: 2 }}
/>
</LineChart>
@@ -645,7 +647,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-foreground">Network Speed (KB/s)</CardTitle>
<CardTitle className="text-foreground">{t('networkSpeedKbs', 'docker')}</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-64">
@@ -669,7 +671,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
dataKey="networkRxSpeed"
stroke={chartConfig.networkRx.color}
strokeWidth={2}
name="RX Speed (KB/s)"
name={t('rxSpeedKbs', 'docker')}
dot={{ r: 2 }}
/>
<Line
@@ -677,7 +679,7 @@ export const DockerMetricsDialog = ({ container, open, onOpenChange }: DockerMet
dataKey="networkTxSpeed"
stroke={chartConfig.networkTx.color}
strokeWidth={2}
name="TX Speed (KB/s)"
name={t('txSpeedKbs', 'docker')}
dot={{ r: 2 }}
/>
</LineChart>
@@ -4,6 +4,7 @@ import { Badge } from "@/components/ui/badge";
import { Container, Play, Square, AlertTriangle } from "lucide-react";
import { DockerStats } from "@/types/docker.types";
import { useTheme } from "@/contexts/ThemeContext";
import { useLanguage } from "@/contexts/LanguageContext";
interface DockerStatsCardsProps {
stats: DockerStats;
@@ -11,10 +12,11 @@ interface DockerStatsCardsProps {
export const DockerStatsCards = ({ stats }: DockerStatsCardsProps) => {
const { theme } = useTheme();
const { t } = useLanguage();
const cards = [
{
title: "Total Containers",
title: t('totalContainers', 'docker'),
value: stats.total,
icon: Container,
color: "text-blue-600",
@@ -23,7 +25,7 @@ export const DockerStatsCards = ({ stats }: DockerStatsCardsProps) => {
: "linear-gradient(135deg, rgba(65, 59, 55, 0.8) 0%, #3b82f6 100%)"
},
{
title: "Running",
title: t('running', 'docker'),
value: stats.running,
icon: Play,
color: "text-green-600",
@@ -32,7 +34,7 @@ export const DockerStatsCards = ({ stats }: DockerStatsCardsProps) => {
: "linear-gradient(135deg, rgba(65, 59, 55, 0.8) 0%, #10b981 100%)"
},
{
title: "Stopped",
title: t('stopped', 'docker'),
value: stats.stopped,
icon: Square,
color: "text-gray-600",
@@ -41,7 +43,7 @@ export const DockerStatsCards = ({ stats }: DockerStatsCardsProps) => {
: "linear-gradient(135deg, rgba(65, 59, 55, 0.8) 0%, #6b7280 100%)"
},
{
title: "Warning",
title: t('warning', 'docker'),
value: stats.warning,
icon: AlertTriangle,
color: "text-amber-600",
@@ -90,7 +92,7 @@ export const DockerStatsCards = ({ stats }: DockerStatsCardsProps) => {
variant="outline"
className="text-xs font-mono font-bold px-2 py-1 rounded-md bg-white/20 backdrop-blur-sm text-white border border-white/30"
>
Containers
{t('containersLabel', 'docker')}
</Badge>
</div>
</CardContent>
@@ -1,36 +1,38 @@
import { Badge } from "@/components/ui/badge";
import { useLanguage } from "@/contexts/LanguageContext";
interface DockerStatusBadgeProps {
status: 'running' | 'stopped' | 'warning';
}
export const DockerStatusBadge = ({ status }: DockerStatusBadgeProps) => {
const { t } = useLanguage();
const getStatusConfig = (status: string) => {
switch (status) {
case 'running':
return {
variant: 'default' as const,
className: 'bg-emerald-100 text-emerald-800 border-emerald-200 hover:bg-emerald-200',
label: 'Running'
label: t('running', 'docker')
};
case 'stopped':
return {
variant: 'secondary' as const,
className: 'bg-gray-100 text-gray-800 border-gray-200 hover:bg-gray-200',
label: 'Stopped'
label: t('stopped', 'docker')
};
case 'warning':
return {
variant: 'destructive' as const,
className: 'bg-amber-100 text-amber-800 border-amber-200 hover:bg-amber-200',
label: 'Warning'
label: t('warning', 'docker')
};
default:
return {
variant: 'outline' as const,
className: 'bg-gray-100 text-gray-600 border-gray-200',
label: 'Unknown'
label: t('unknown', 'docker')
};
}
};
@@ -1,20 +1,22 @@
import { TableCell, TableRow } from "@/components/ui/table";
import { useLanguage } from "@/contexts/LanguageContext";
interface DockerEmptyStateProps {
searchTerm: string;
}
export const DockerEmptyState = ({ searchTerm }: DockerEmptyStateProps) => {
const { t } = useLanguage();
return (
<TableRow>
<TableCell colSpan={8} className="text-center py-12 text-muted-foreground">
<div className="flex flex-col items-center gap-2">
<div className="text-lg font-medium">
{searchTerm ? "No containers found" : "No containers running"}
{searchTerm ? t('noContainersFound', 'docker') : t('noContainersRunning', 'docker')}
</div>
<div className="text-sm">
{searchTerm ? "Try adjusting your search terms." : "Start some containers to see them here."}
{searchTerm ? t('tryAdjustSearch', 'docker') : t('startSomeContainers', 'docker')}
</div>
</div>
</TableCell>
@@ -3,6 +3,7 @@ import { Button } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from "@/components/ui/dropdown-menu";
import { MoreHorizontal, Eye, Play, Pause, Square, Trash2, BarChart3, RefreshCw } from "lucide-react";
import { DockerContainer } from "@/types/docker.types";
import { useLanguage } from "@/contexts/LanguageContext";
interface DockerRowActionsProps {
container: DockerContainer;
@@ -12,11 +13,12 @@ interface DockerRowActionsProps {
}
export const DockerRowActions = ({ container, containerStatus, onContainerAction, onViewMetrics }: DockerRowActionsProps) => {
const { t } = useLanguage();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0 hover:bg-muted">
<span className="sr-only">Open menu</span>
<span className="sr-only">{t('openMenu', 'docker')}</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
@@ -26,14 +28,14 @@ export const DockerRowActions = ({ container, containerStatus, onContainerAction
className="cursor-pointer hover:bg-muted"
>
<BarChart3 className="mr-2 h-4 w-4" />
View Metrics
{t('viewMetrics', 'docker')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => onContainerAction('view-detail', container.id, container.name)}
className="cursor-pointer hover:bg-muted"
>
<Eye className="mr-2 h-4 w-4" />
View Details
{t('viewDetails', 'docker')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
@@ -1,18 +1,20 @@
import { TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { useLanguage } from "@/contexts/LanguageContext";
export const DockerTableHeader = () => {
const { t } = useLanguage();
return (
<TableHeader>
<TableRow className="border-border bg-muted/30">
<TableHead className="min-w-[200px] font-semibold">Container</TableHead>
<TableHead className="min-w-[100px] font-semibold">Status</TableHead>
<TableHead className="min-w-[140px] font-semibold">CPU Usage</TableHead>
<TableHead className="min-w-[160px] font-semibold">Memory</TableHead>
<TableHead className="min-w-[160px] font-semibold">Disk</TableHead>
<TableHead className="min-w-[100px] font-semibold">Uptime</TableHead>
<TableHead className="min-w-[160px] font-semibold">Last Checked</TableHead>
<TableHead className="min-w-[80px] text-center font-semibold">Actions</TableHead>
<TableHead className="min-w-[200px] font-semibold">{t('container', 'docker')}</TableHead>
<TableHead className="min-w-[100px] font-semibold">{t('status', 'docker')}</TableHead>
<TableHead className="min-w-[140px] font-semibold">{t('cpuUsage', 'docker')}</TableHead>
<TableHead className="min-w-[160px] font-semibold">{t('memory', 'docker')}</TableHead>
<TableHead className="min-w-[160px] font-semibold">{t('disk', 'docker')}</TableHead>
<TableHead className="min-w-[100px] font-semibold">{t('uptime', 'docker')}</TableHead>
<TableHead className="min-w-[160px] font-semibold">{t('lastChecked', 'docker')}</TableHead>
<TableHead className="min-w-[80px] text-center font-semibold">{t('actions', 'docker')}</TableHead>
</TableRow>
</TableHeader>
);
@@ -2,6 +2,7 @@
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Search, RefreshCw } from "lucide-react";
import { useLanguage } from "@/contexts/LanguageContext";
interface DockerTableSearchProps {
searchTerm: string;
@@ -11,12 +12,13 @@ interface DockerTableSearchProps {
}
export const DockerTableSearch = ({ searchTerm, onSearchChange, onRefresh, isLoading }: DockerTableSearchProps) => {
const { t } = useLanguage();
return (
<div className="flex flex-col sm:flex-row gap-3 w-full sm:w-auto">
<div className="relative flex-1 sm:flex-initial">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" />
<Input
placeholder="Search containers..."
placeholder={t('searchContainersPlaceholder', 'docker')}
value={searchTerm}
onChange={(e) => onSearchChange(e.target.value)}
className="pl-10 sm:w-64 bg-background border-border"
@@ -30,7 +32,7 @@ export const DockerTableSearch = ({ searchTerm, onSearchChange, onRefresh, isLoa
className="w-full sm:w-auto bg-background border-border hover:bg-muted"
>
<RefreshCw className={`h-4 w-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />
<span className="sm:inline">Refresh</span>
<span className="sm:inline">{t('refresh', 'docker')}</span>
</Button>
</div>
);