fix(deployments): 卡片按钮布局拥挤 + 去掉冗余的日志查询/采集器/跳转入口

用户反馈 /deployments 卡片按钮布局乱,且「日志查询」「采集器」和 endpoint 跳转按钮多余。

问题根因:
  1. ResourceCard 的操作区是 flex 但没有 flex-wrap,
     而 DeploymentCard 在部署/停止/重启按钮上用了 flex-1,
     窄卡片里 7 个按钮互相挤压、换行错位、宽度不均
  2. endpoint 在 K8s 模式下是 http://loki.log.svc.cluster.local:3100
     这类集群内地址,浏览器点不开,展示出来纯属噪音

修复:
  - ResourceCard 操作区加 flex-wrap + items-center(按钮多时自动规整换行)
  - DeploymentCard 去掉 4 处 flex-1(按钮按内容宽度排布)
  - 去掉「访问」字段(不再展示 cluster-local endpoint)
  - 去掉「日志查询」跳转按钮(左下导航已有入口)
  - 去掉「采集器」跳转按钮(同上)
  - 去掉 endpoint 的 ExternalLink 跳转按钮
  - 清理不再使用的 import:Link(react-router)、ExternalLink(lucide)

卡片保留的按钮:配置 / 部署(或 停止+重启)/ 日志 / 删除

镜像:lghost/lokistack:latest + v0.1 = sha256:d89b9cfa0054
This commit is contained in:
opsx committed 2026-10-27 03:10:42 +00:00
1 parent 188d9460fe
commit 24caeefb3a
2 files changed
+10 -26

No files matched your search

+2 -1
View File
@@ -90,7 +90,8 @@ export const ResourceCard = memo(function ResourceCard({
)}
{/* 操作区:贴底 */}
<div className="flex gap-2 pt-3 border-t border-border mt-auto">{actions}</div>
{/* flex-wrap:按钮多时自动换行,避免在窄卡片里被 flex-1 压扁/溢出 */}
<div className="flex flex-wrap items-center gap-2 pt-3 border-t border-border mt-auto">{actions}</div>
</CardContent>
</Card>
)
@@ -1,6 +1,5 @@
import { memo, useEffect, useState } from 'react'
import { Link } from 'react-router'
import { Play, Square, RotateCw, Trash2, Terminal, ExternalLink, Pencil, Rocket } from 'lucide-react'
import { Play, Square, RotateCw, Trash2, Terminal, Pencil, Rocket } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { StatusBadge } from '@/components/StatusBadge'
import { deploymentApi } from '@/api'
@@ -26,7 +25,7 @@ interface DeploymentCardProps {
onEditRetention: (d: LokiDeployment) => void
}
/** 部署卡片 — 列表项展示与操作入口(部署/停止/重启/日志/访问/删除) */
/** 部署卡片 — 列表项展示与操作入口(配置/部署/停止/重启/日志/删除) */
export const DeploymentCard = memo(function DeploymentCard({
deployment: d,
operating,
@@ -83,9 +82,8 @@ export const DeploymentCard = memo(function DeploymentCard({
{ label: '副本', value: `${d.replicas} · 保留 ${d.retentionDays || 30} 天` },
] : [{ label: '保留', value: `${d.retentionDays || 30} 天` }]),
{ label: '存储', value: d.storageConfig?.name || '本地' },
...(d.endpoint ? [{ label: '访问', value: (
<span className="text-primary">{d.endpoint.replace(/^https?:\/\//, '')}</span>
), title: d.endpoint }] : []),
// 不再展示 endpoint:K8s 模式下它是 http://loki.log.svc.cluster.local:3100
// 这类集群内地址,浏览器点不开,纯属噪音
...(d.grafanaEnabled && d.grafanaEndpoint ? [{ label: 'Grafana', value: (
<a href={d.grafanaEndpoint} target="_blank" rel="noopener noreferrer" className="text-primary hover:underline" title={`${d.grafanaEndpoint}(admin/admin)`}>
{d.grafanaEndpoint.replace(/^https?:\/\//, '')}
@@ -104,41 +102,26 @@ export const DeploymentCard = memo(function DeploymentCard({
<Pencil className="size-3 mr-1" />配置
</Button>
{canDeploy ? (
<Button variant="outline" size="sm" className="flex-1 text-xs bg-success/10 text-primary hover:bg-success/20 border-success/30" onClick={() => onDeploy(d.id)} disabled={isBusy}>
<Button variant="outline" size="sm" className="text-xs bg-success/10 text-primary hover:bg-success/20 border-success/30" onClick={() => onDeploy(d.id)} disabled={isBusy}>
<Play className="size-3 mr-1" />{isBusy ? '部署中...' : '部署'}
</Button>
) : isDeploying ? (
<Button variant="outline" size="sm" className="flex-1 text-xs" disabled>
<Button variant="outline" size="sm" className="text-xs" disabled>
<RotateCw className="size-3 mr-1 animate-spin" />部署中...
</Button>
) : (
<>
<Button variant="outline" size="sm" className="flex-1 text-xs" onClick={() => onStop(d.id)}>
<Button variant="outline" size="sm" className="text-xs" onClick={() => onStop(d.id)}>
<Square className="size-3 mr-1" />停止
</Button>
<Button variant="outline" size="sm" className="flex-1 text-xs" onClick={() => onRestart(d.id)} disabled={isBusy}>
<Button variant="outline" size="sm" className="text-xs" onClick={() => onRestart(d.id)} disabled={isBusy}>
<RotateCw className={`size-3 mr-1 ${isBusy ? 'animate-spin' : ''}`} />重启
</Button>
</>
)}
{d.status === 'running' && (
<>
<Button variant="outline" size="sm" className="text-xs" asChild>
<Link to="/logs">日志查询</Link>
</Button>
<Button variant="outline" size="sm" className="text-xs" asChild>
<Link to="/collectors">采集器</Link>
</Button>
</>
)}
<Button variant="outline" size="sm" className="text-xs" onClick={() => onViewLogs(d)}>
<Terminal className="size-3 mr-1" />日志
</Button>
{d.endpoint && (
<Button variant="outline" size="sm" className="text-xs text-primary hover:text-primary/80" onClick={() => window.open(d.endpoint, '_blank', 'noopener,noreferrer')} title="浏览器访问">
<ExternalLink className="size-3" />
</Button>
)}
<Button variant="outline" size="sm" aria-label={`删除部署 ${d.name}`} className="text-destructive hover:text-destructive hover:bg-destructive/10" onClick={() => onDelete(d)}>
<Trash2 className="size-3.5" />
</Button>