Refactor ClusterServicesComponent: enhance service card layout with improved responsiveness and action button arrangement

This commit is contained in:
2026-02-01 19:38:05 +00:00
parent b27eef2592
commit 7ba269ae0c

View File

@@ -200,89 +200,86 @@ export function ClusterServicesComponent() {
<p className="text-muted-foreground">Loading services...</p>
</Card>
) : (
<div className="space-y-3">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{services.map((service) => (
<Card key={service.name} className="p-4">
<div className="flex items-start gap-3">
<div className="p-2 bg-muted rounded-lg">
{getServiceIcon(service.name)}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<h3 className="font-medium truncate">{service.name}</h3>
{service.version && (
<Badge variant="outline" className="text-xs">
{service.version}
</Badge>
)}
{getStatusBadge(service)}
</div>
<p className="text-sm text-muted-foreground mb-2">{service.description}</p>
{typeof service.status === 'object' && service.status?.message && (
<p className="text-xs text-muted-foreground mb-2">{service.status.message}</p>
<Card key={service.name} className="p-4 hover:shadow-lg hover:border-primary/50 transition-all flex flex-col">
<div className="mb-3">
<div className="flex items-center justify-between gap-2 mb-2">
<h3 className="font-medium truncate">{service.name}</h3>
{service.version && (
<Badge variant="outline" className="text-xs flex-shrink-0">
{service.version}
</Badge>
)}
</div>
<div className="mb-2">
{getStatusBadge(service)}
</div>
<p className="text-sm text-muted-foreground mb-2">{service.description}</p>
{typeof service.status === 'object' && service.status?.message && (
<p className="text-xs text-muted-foreground">{service.status.message}</p>
)}
</div>
{/* Action buttons - horizontal layout with responsive icons */}
<div className="flex flex-wrap gap-2 mt-3">
{(
(typeof service.status === 'string' && service.status === 'not-deployed') ||
(typeof service.status === 'object' && String(service.status?.status) === 'not-deployed') ||
service.deployed === false
) && (
{/* Action buttons */}
<div className="flex flex-col gap-2 mt-auto pt-2 border-t">
{(
(typeof service.status === 'string' && service.status === 'not-deployed') ||
(typeof service.status === 'object' && String(service.status?.status) === 'not-deployed') ||
service.deployed === false
) && (
<Button
size="sm"
onClick={() => handleInstallService(service.name)}
disabled={isInstalling}
className="w-full"
>
{isInstalling ? <Loader2 className="h-4 w-4 animate-spin mr-2" /> : <Download className="h-4 w-4 mr-2" />}
Install
</Button>
)}
{((typeof service.status === 'string' && ['deployed', 'degraded', 'progressing'].includes(service.status)) ||
(typeof service.status === 'object' && ['deployed', 'degraded', 'progressing'].includes(service.status?.status || ''))) && (
<>
<div className="flex gap-2">
<Button
size="sm"
onClick={() => handleInstallService(service.name)}
disabled={isInstalling}
variant="outline"
onClick={() => setStatusService(service.name)}
className="aspect-square p-0"
>
{isInstalling ? <Loader2 className="h-4 w-4 animate-spin sm:mr-1" /> : <Download className="h-4 w-4 sm:mr-1" />}
<span className="hidden sm:inline">Install</span>
<Activity className="h-4 w-4" />
</Button>
)}
{((typeof service.status === 'string' && ['deployed', 'degraded', 'progressing'].includes(service.status)) ||
(typeof service.status === 'object' && ['deployed', 'degraded', 'progressing'].includes(service.status?.status || ''))) && (
<>
<Button
size="sm"
variant="outline"
onClick={() => setLogsService(service.name)}
className="aspect-square p-0"
>
<FileText className="h-4 w-4" />
</Button>
{service.hasConfig && (
<Button
size="sm"
variant="outline"
onClick={() => setStatusService(service.name)}
title="Status"
onClick={() => setConfigService(service.name)}
className="aspect-square p-0"
>
<Activity className="h-4 w-4 sm:mr-1" />
<span className="hidden sm:inline">Status</span>
<Settings className="h-4 w-4" />
</Button>
<Button
size="sm"
variant="outline"
onClick={() => setLogsService(service.name)}
title="Logs"
>
<FileText className="h-4 w-4 sm:mr-1" />
<span className="hidden sm:inline">Logs</span>
</Button>
{service.hasConfig && (
<Button
size="sm"
variant="outline"
onClick={() => setConfigService(service.name)}
title="Configure"
>
<Settings className="h-4 w-4 sm:mr-1" />
<span className="hidden sm:inline">Configure</span>
</Button>
)}
<Button
size="sm"
variant="destructive"
onClick={() => handleDeleteService(service.name)}
disabled={isDeleting}
title="Remove"
>
{isDeleting ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
</Button>
</>
)}
</div>
</div>
)}
<Button
size="sm"
variant="destructive"
onClick={() => handleDeleteService(service.name)}
disabled={isDeleting}
className="aspect-square p-0"
>
{isDeleting ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
</Button>
</div>
</>
)}
</div>
</Card>
))}