Files
LokiStack/frontend/src/components/ResourceCard.tsx
T
opsx 24caeefb3a 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
2026-10-27 03:10:42 +00:00

99 lines
3.4 KiB
TypeScript

import { memo } from 'react'
import type { LucideIcon } from 'lucide-react'
import { Card, CardContent } from '@/components/ui/card'
import { cn } from '@/lib/utils'
export interface ResourceField {
label: string
value: React.ReactNode
/** 值提示(截断时 title) */
title?: string
}
interface ResourceCardProps {
/** 头部图标 */
icon: LucideIcon
/** 图标配色(text-info/success/warning 等语义 token 类) */
iconClassName?: string
title: string
/** 标题旁附加(如 ready 状态点、uuid) */
titleExtra?: React.ReactNode
/** 右上角徽章(状态/保留天数等) */
badges?: React.ReactNode
/** 副标题/描述(单行截断) */
description?: string
/** 信息字段(两列网格;奇数个最后一项占整行) */
fields: ResourceField[]
/** 底部状态消息(如错误信息,浅底块) */
message?: string
/** 底部操作区(border-top 分隔) */
actions: React.ReactNode
}
/**
* 资源卡片 — 五大资源页(集群/主机/存储/部署/采集)统一样式:
* 图标+标题+徽章 → 描述 → 两列信息网格(label 上 value 下) → 分隔线操作区。
* 统一 p-4 内边距、hover 阴影、等高布局(网格内自动对齐)。
*/
export const ResourceCard = memo(function ResourceCard({
icon: Icon,
iconClassName = 'text-muted-foreground',
title,
titleExtra,
badges,
description,
fields,
message,
actions,
}: ResourceCardProps) {
return (
<Card className="border-border hover:shadow-md transition-shadow h-full">
<CardContent className="p-4 flex flex-col gap-3 h-full">
{/* 头部:图标 + 标题 + 徽章 */}
<div className="flex items-start gap-3">
<div className="w-9 h-9 rounded-lg bg-muted/70 flex items-center justify-center shrink-0">
<Icon className={cn('size-4', iconClassName)} />
</div>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2 flex-wrap">
<h3 className="font-medium text-sm text-foreground truncate" title={title}>
{title}
</h3>
{titleExtra}
{badges && <span className="ml-auto flex items-center gap-1.5 shrink-0">{badges}</span>}
</div>
{description && (
<p className="text-xs text-muted-foreground truncate mt-0.5" title={description}>
{description}
</p>
)}
</div>
</div>
{/* 信息:两列网格(label 灰小字在上,value 在下) */}
<div className="grid grid-cols-2 gap-x-4 gap-y-2 text-xs">
{fields.map((f) => (
<div key={f.label} className="min-w-0">
<p className="text-muted-foreground leading-4">{f.label}</p>
<p className="font-medium text-foreground truncate leading-5" title={f.title}>
{f.value}
</p>
</div>
))}
</div>
{/* 状态消息(错误/提示) */}
{message && (
<p className="rounded-md bg-muted/60 px-2.5 py-1.5 text-xs text-muted-foreground" title={message}>
{message}
</p>
)}
{/* 操作区:贴底 */}
{/* 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>
)
})