/* eslint-disable @typescript-eslint/no-explicit-any */ import { TableCell, TableRow } from '@/components/ui/table'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Boxes, Container, Network, FileText, Shield, Activity, Clock, FileCode, Pencil, Terminal, HardDrive, Trash2, Eye, } from 'lucide-react'; import i18n from '@/i18n'; export type ResourceType = | 'deployments' | 'pods' | 'services' | 'ingresses' | 'configmaps' | 'secrets' | 'hpas' | 'cronjobs' | 'pvcs' | 'statefulsets' | 'daemonsets' | 'serviceaccounts' | 'roles' | 'rolebindings'; // 支持可视化编辑/新建的资源类型 // Logan.Li export const VISUAL_RESOURCE_TYPES: ResourceType[] = ['services', 'ingresses', 'configmaps', 'secrets', 'pvcs']; /** Deployment 列表:新建 + YAML 导入,不做批量导出 // Logan.Li */ export const DEPLOYMENT_LIST_TYPES: ResourceType[] = ['deployments']; /** 支持命名空间 YAML 批量导出(对齐集群导出)// Logan.Li */ export const EXPORT_YAML_TYPES: ResourceType[] = ['services', 'ingresses', 'configmaps', 'secrets']; /** 列表页保留 CSV/JSON 导出的配置类资源 // Logan.Li */ export const BULK_EXPORT_TYPES: ResourceType[] = ['services', 'ingresses', 'configmaps', 'secrets', 'pvcs']; export interface ResourceRowOpts { clusterCode: string; namespace: string; onDetail?: (item: any) => void; onYaml?: (name: string) => void; onEdit?: (name: string) => void; onTerminal?: (item: any) => void; onFileBrowser?: (item: any) => void; onDeletePod?: (item: any) => void; onPodDetail?: (item: any) => void; } export const VisualActions = ({ name, opts }: { name: string; opts: { onYaml?: (n: string) => void; onEdit?: (n: string) => void } }) => (
); export const RESOURCE_CONFIG: Record; columns: string[]; renderRow: (item: any, opts: ResourceRowOpts) => React.ReactNode; }> = { deployments: { title: 'Deployments', subtitle: i18n.t('k8s.nsResource.deployDesc'), icon: Boxes, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('common.name'), i18n.t('kubernetes.container.image')], renderRow: (d, opts) => ( opts.onDetail?.(d)}> {d.name} {d.namespace} {(() => { const ready = d.ready_replicas || 0; const total = d.replicas || 0; const pct = total > 0 ? (ready / total) * 100 : 0; const done = ready === total; return (
{ready}/{total}
); })()} {d.image || '-'} ), }, pods: { title: 'Pods', subtitle: i18n.t('k8s.nsResource.podDesc'), icon: Container, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('system.terminalStatus'), i18n.t('kubernetes.node.title'), 'CPU', i18n.t('kubernetes.pod.memory'), i18n.t('agent.agentServiceRestart'), i18n.t('kubernetes.container.image'), i18n.t('system.auditAction')], renderRow: (p, opts) => { const statusMap: Record = { Running: 'bg-[var(--dg-green)]/20 text-[var(--dg-green)] border-[var(--dg-green)]/30', Pending: 'bg-[var(--dg-orange)]/20 text-[var(--dg-orange)] border-[var(--dg-orange)]/30', Failed: 'bg-[var(--dg-red)]/20 text-[var(--dg-red)] border-[var(--dg-red)]/30' }; return ( opts.onPodDetail?.(p)}>
{p.name}
{p.namespace} {p.status || 'Unknown'} {p.node_name || '-'} {p.cpu_usage_m || '-'} {p.mem_usage_mi || '-'} 0 ? 'text-[var(--dg-orange)]' : 'text-[var(--dg-text-muted)]')}>{p.restart_count || 0} {p.image || '-'}
); }, }, services: { title: 'Services', subtitle: i18n.t('k8s.nsResource.serviceDesc'), icon: Network, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('system.credentialType'), 'Cluster IP', i18n.t('system.ldapPort'), i18n.t('system.auditAction')], renderRow: (s, opts) => ( {s.name} {s.namespace} {s.type || '-'} {s.cluster_ip || '-'} {s.ports || '-'} e.stopPropagation()}> ), }, ingresses: { title: 'Ingresses', subtitle: i18n.t('k8s.nsResource.ingressDesc'), icon: Network, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), 'Hosts', 'TLS', i18n.t('system.auditAction')], renderRow: (i, opts) => { const hosts = i.hosts || []; return ( {i.name} {i.namespace} {hosts.length > 0 ? hosts.join(', ') : '-'} {i.tls ? 'HTTPS' : 'HTTP'} e.stopPropagation()}> ); }, }, configmaps: { title: 'ConfigMaps', subtitle: i18n.t('k8s.nsResource.configMapDesc'), icon: FileText, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('common.name'), i18n.t('system.auditAction')], renderRow: (c, opts) => ( {c.name} {c.namespace} {c.key_count || '-'} e.stopPropagation()}> ), }, secrets: { title: 'Secrets', subtitle: i18n.t('k8s.nsResource.secretDesc'), icon: Shield, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('system.credentialType'), i18n.t('system.auditAction')], renderRow: (s, opts) => ( {s.name} {s.namespace} {s.type || '-'} e.stopPropagation()}> ), }, hpas: { title: 'HPAs', subtitle: i18n.t('k8s.nsResource.hpaDesc'), icon: Activity, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('monitor.alertEvents.col.target'), i18n.t('k8s.hpaCronHpa.col.minMax'), 'CPU%', 'Mem%'], renderRow: (h, _opts) => ( {h.name} {h.namespace} {h.target_kind}/{h.target_name} {h.min_replicas}/{h.max_replicas} {h.cpu_percent ?? '-'}% {h.mem_percent ?? '-'}% ), }, cronjobs: { title: 'CronJobs', subtitle: i18n.t('automation.cronJobs'), icon: Clock, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('kubernetes.workload.scheduling'), i18n.t('system.terminalStatus'), i18n.t('automation.scriptLastExec')], renderRow: (cj) => ( {cj.name} {cj.namespace} {cj.schedule || '-'} {cj.suspend ? i18n.t('kubernetes.deployment.paused') : i18n.t('agent.agentServiceRunning')} {cj.last_schedule || '-'} ), }, pvcs: { title: i18n.t('k8s.nsResource.pvcDesc'), subtitle: 'PersistentVolumeClaim', icon: Boxes, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('system.terminalStatus'), i18n.t('kubernetes.storage.pvcSize'), 'StorageClass', i18n.t('system.auditAction')], renderRow: (p, opts) => ( {p.name} {p.namespace} {p.phase || '-'} {p.size || '-'} {p.storage_class || '-'} e.stopPropagation()}> ), }, statefulsets: { title: 'StatefulSets', subtitle: i18n.t('k8s.nsResource.stsDesc'), icon: Boxes, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('common.name'), i18n.t('kubernetes.pod.ready'), i18n.t('kubernetes.container.image')], renderRow: (s, opts) => ( opts.onDetail?.(s)}> {s.name} {s.namespace} {s.replicas || 0} {s.ready || 0} {s.image || '-'} ), }, daemonsets: { title: 'DaemonSets', subtitle: i18n.t('k8s.nsResource.dsDesc'), icon: Boxes, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('monitor.siteProtocol.http.expectedPrefix'), i18n.t('cloud.current'), i18n.t('kubernetes.pod.ready'), i18n.t('kubernetes.container.image')], renderRow: (d, opts) => ( opts.onDetail?.(d)}> {d.name} {d.namespace} {d.desired || 0} {d.current || 0} {d.ready || 0} {d.image || '-'} ), }, serviceaccounts: { title: 'ServiceAccounts', subtitle: i18n.t('k8s.nsResource.saDesc'), icon: Shield, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('common.name'), i18n.t('common.namespace'), i18n.t('system.userCreatedAt'), i18n.t('system.auditAction')], renderRow: (sa, opts) => ( {sa.name} {sa.namespace} {sa.secret_count ?? 0} {sa.image_pull_secrets && sa.image_pull_secrets.length > 0 ? sa.image_pull_secrets.join(', ') : '-'} {sa.age || '-'} e.stopPropagation()}> ), }, roles: { title: 'Roles', subtitle: i18n.t('k8s.nsResource.roleDesc'), icon: Shield, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('common.name'), i18n.t('system.apiKeyScope'), i18n.t('system.userCreatedAt'), i18n.t('system.auditAction')], renderRow: (r, opts) => { const verbs = r.verbs || []; const resources = r.resources || []; const verbsStr = verbs.length > 4 ? verbs.slice(0, 4).join(', ') + ` +${verbs.length - 4}` : verbs.join(', '); const resStr = resources.length > 4 ? resources.slice(0, 4).join(', ') + ` +${resources.length - 4}` : resources.join(', '); return ( {r.name} {r.namespace} {r.rule_count ?? 0}
verbs: {verbsStr || '-'} resources: {resStr || '-'}
{r.age || '-'} e.stopPropagation()}>
); }, }, rolebindings: { title: 'RoleBindings', subtitle: i18n.t('k88s.nsResource.rbDesc'), icon: Shield, columns: [i18n.t('kubernetes.secret.secretName'), i18n.t('kubernetes.namespace.title'), i18n.t('common.name'), i18n.t('common.namespace'), i18n.t('system.userCreatedAt'), i18n.t('system.auditAction')], renderRow: (rb, opts) => { const subjects = rb.subjects || []; const subjStr = subjects.length > 3 ? subjects.slice(0, 3).join(', ') + ` +${subjects.length - 3}` : subjects.join(', '); return ( {rb.name} {rb.namespace} {rb.role_ref_kind || '-'}/{rb.role_ref_name || '-'} {subjStr || '-'} {rb.age || '-'} e.stopPropagation()}>
); }, }, };