feat(k8s-ui): HPA 创建按钮醒目化 + K8sWorkloads 命名空间切换
DeploymentDetail: - HPA 未配置时,状态卡片内直接显示「创建 HPA」按钮 - 无需切换到 HPA Tab 即可一键创建 K8sWorkloads: - 新增命名空间下拉选择器(自动加载集群全部 ns) - 切换集群时自动重置命名空间为「全部」 - Deployment/Pod 列表按命名空间过滤 - 统计卡片始终显示全量数据(不受 ns 过滤影响)
This commit is contained in:
1 parent
77045622fc
commit
f7b667b878
2 files changed
+43
-4
No files matched your search
@@ -220,7 +220,19 @@ export function DeploymentDetail({ clusterId, namespace, deploymentName, onBack
|
||||
<Card className="bg-slate-900 border-slate-800">
|
||||
<CardContent className="p-3">
|
||||
<p className="text-xs text-slate-500">HPA</p>
|
||||
<p className="text-lg font-bold text-purple-400">{hpas.length > 0 ? '已启用' : '未配置'}</p>
|
||||
{hpas.length > 0 ? (
|
||||
<p className="text-lg font-bold text-purple-400">已启用</p>
|
||||
) : (
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-lg font-bold text-slate-500">未配置</p>
|
||||
<CreateHPADialog
|
||||
clusterId={clusterId}
|
||||
namespace={namespace}
|
||||
deploymentName={deploymentName}
|
||||
onCreated={loadData}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -22,6 +22,8 @@ export function K8sWorkloads() {
|
||||
const { toast } = useToast();
|
||||
const [clusters, setClusters] = useState<any[]>([]);
|
||||
const [selectedCluster, setSelectedCluster] = useState('');
|
||||
const [namespaces, setNamespaces] = useState<string[]>([]);
|
||||
const [selectedNamespace, setSelectedNamespace] = useState('all');
|
||||
const [deployments, setDeployments] = useState<any[]>([]);
|
||||
const [pods, setPods] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -43,6 +45,18 @@ export function K8sWorkloads() {
|
||||
|
||||
useEffect(() => { loadClusters(); }, [loadClusters]);
|
||||
|
||||
// Load namespaces when cluster changes
|
||||
const loadNamespaces = useCallback(async () => {
|
||||
if (!selectedCluster) return;
|
||||
try {
|
||||
const res: any = await k8sApi.getNamespaces(selectedCluster);
|
||||
const nsList: string[] = Array.isArray(res) ? res : (res?.list || res?.data || []);
|
||||
setNamespaces(nsList);
|
||||
} catch { setNamespaces([]); }
|
||||
}, [selectedCluster]);
|
||||
|
||||
useEffect(() => { loadNamespaces(); }, [loadNamespaces]);
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
if (!selectedCluster) return;
|
||||
setLoading(true);
|
||||
@@ -60,10 +74,12 @@ export function K8sWorkloads() {
|
||||
useEffect(() => { loadData(); }, [loadData]);
|
||||
|
||||
const filteredDeps = deployments.filter((d) =>
|
||||
(d.name || '').toLowerCase().includes(search.toLowerCase()),
|
||||
(d.name || '').toLowerCase().includes(search.toLowerCase()) &&
|
||||
(selectedNamespace === 'all' || d.namespace === selectedNamespace),
|
||||
);
|
||||
const filteredPods = pods.filter((p) =>
|
||||
(p.name || '').toLowerCase().includes(search.toLowerCase()),
|
||||
(p.name || '').toLowerCase().includes(search.toLowerCase()) &&
|
||||
(selectedNamespace === 'all' || p.namespace === selectedNamespace),
|
||||
);
|
||||
|
||||
const getPodStatusBadge = (status: string) => {
|
||||
@@ -112,7 +128,7 @@ export function K8sWorkloads() {
|
||||
<p className="text-sm text-slate-500 mt-1">Deployment 与 Pod 运行状态</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Select value={selectedCluster} onValueChange={setSelectedCluster}>
|
||||
<Select value={selectedCluster} onValueChange={(v) => { setSelectedCluster(v); setSelectedNamespace('all'); }}>
|
||||
<SelectTrigger className="w-48 h-9 bg-slate-800/50 border-slate-700 text-slate-200">
|
||||
<SelectValue placeholder="选择集群" />
|
||||
</SelectTrigger>
|
||||
@@ -122,6 +138,17 @@ export function K8sWorkloads() {
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={selectedNamespace} onValueChange={setSelectedNamespace}>
|
||||
<SelectTrigger className="w-40 h-9 bg-slate-800/50 border-slate-700 text-slate-200">
|
||||
<SelectValue placeholder="命名空间" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="bg-slate-800 border-slate-700 max-h-[300px]">
|
||||
<SelectItem value="all">全部命名空间</SelectItem>
|
||||
{namespaces.map((ns) => (
|
||||
<SelectItem key={ns} value={ns}>{ns}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="icon" className="h-9 w-9 border-slate-700 text-slate-400" onClick={loadData} disabled={loading}>
|
||||
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCw className="h-4 w-4" />}
|
||||
</Button>
|
||||
|
||||
Reference in new issue
Block a user