From e928011839d24853e6df038ce9bdb139eb2aebfd Mon Sep 17 00:00:00 2001 From: Shaun Arman Date: Sun, 7 Jun 2026 12:19:08 -0500 Subject: [PATCH 1/2] fix(kubernetes): use kubeconfig files from Settings instead of duplicate cluster management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove duplicate 'Add Cluster' button and modal - Remove duplicate 'Start Port Forward' button and modal - KubernetesPage now uses kubeconfig files from Settings → Kubeconfig - Clusters section displays kubeconfig files with active indicator - Port forwarding section shows active port forwards without duplicate controls - All tests passing, build successful --- src/pages/Kubernetes/KubernetesPage.tsx | 155 +++++++++++++++--------- 1 file changed, 99 insertions(+), 56 deletions(-) diff --git a/src/pages/Kubernetes/KubernetesPage.tsx b/src/pages/Kubernetes/KubernetesPage.tsx index 7cfcac60..e910eca2 100644 --- a/src/pages/Kubernetes/KubernetesPage.tsx +++ b/src/pages/Kubernetes/KubernetesPage.tsx @@ -1,25 +1,24 @@ import React, { useState, useEffect } from "react"; import { useKubernetesStore } from "@/stores/kubernetesStore"; -import { ClusterList } from "@/components/Kubernetes/ClusterList"; + import { PortForwardList } from "@/components/Kubernetes/PortForwardList"; -import { AddClusterModal } from "@/components/Kubernetes/AddClusterModal"; import { PortForwardForm } from "@/components/Kubernetes/PortForwardForm"; import { ResourceBrowser } from "@/components/Kubernetes/ResourceBrowser"; -import type { ClusterInfo, PortForwardResponse } from "@/lib/tauriCommands"; +import type { PortForwardResponse, KubeconfigInfo, PortForwardRequest } from "@/lib/tauriCommands"; import { - listClustersCmd, - removeClusterCmd, listPortForwardsCmd, stopPortForwardCmd, deletePortForwardCmd, + listKubeconfigsCmd, + activateKubeconfigCmd, + startPortForwardCmd, } from "@/lib/tauriCommands"; export function KubernetesPage() { - const { clusters, addCluster, removeCluster, selectedClusterId } = useKubernetesStore(); + const { selectedClusterId } = useKubernetesStore(); + const [kubeconfigs, setKubeconfigs] = useState([]); const [portForwards, setPortForwards] = useState([]); const [isLoading, setIsLoading] = useState(true); - const [isAddClusterOpen, setIsAddClusterOpen] = useState(false); - const [isStartPortForwardOpen, setIsStartPortForwardOpen] = useState(false); useEffect(() => { loadData(); @@ -28,12 +27,12 @@ export function KubernetesPage() { const loadData = async () => { setIsLoading(true); try { - const [clustersData, portForwardsData] = await Promise.all([ - listClustersCmd(), + const [kubeconfigsData, portForwardsData] = await Promise.all([ + listKubeconfigsCmd(), listPortForwardsCmd(), ]); - clustersData.forEach(addCluster); + setKubeconfigs(kubeconfigsData); setPortForwards(portForwardsData); } catch (err) { console.error("Failed to load data:", err); @@ -42,13 +41,13 @@ export function KubernetesPage() { } }; - const handleRemoveCluster = async (clusterId: string) => { + const handleActivateKubeconfig = async (id: string) => { try { - await removeClusterCmd(clusterId); - removeCluster(clusterId); + await activateKubeconfigCmd(id); + await loadData(); } catch (err) { - console.error("Failed to remove cluster:", err); - alert("Failed to remove cluster"); + console.error("Failed to activate kubeconfig:", err); + alert("Failed to activate kubeconfig"); } }; @@ -72,12 +71,14 @@ export function KubernetesPage() { } }; - const handleAddCluster = (cluster: ClusterInfo) => { - addCluster(cluster); - }; - - const handleStartPortForward = (portForward: PortForwardResponse) => { - setPortForwards((prev) => [...prev, portForward]); + const handleStartPortForward = async (portForward: PortForwardRequest) => { + try { + const result = await startPortForwardCmd(portForward); + setPortForwards((prev) => [...prev, result]); + } catch (err) { + console.error("Failed to start port forward:", err); + alert("Failed to start port forward"); + } }; if (isLoading) { @@ -100,40 +101,94 @@ export function KubernetesPage() {

- {/* Cluster Management Section */} + {/* Cluster Management Section - Uses kubeconfig files from Settings */}
-

Clusters

- +

Clusters (from kubeconfig files)

+
+ +
- setIsAddClusterOpen(true)} - onRemove={handleRemoveCluster} - /> + {kubeconfigs.length === 0 ? ( +
+
+ + + +
+

No kubeconfig files uploaded

+

+ Upload kubeconfig files in Settings → Kubeconfig to manage Kubernetes clusters +

+ +
+ ) : ( +
+ {kubeconfigs.map((config) => ( +
+
+
+
+

{config.name}

+ {config.is_active && ( + + Active + + )} +
+
+
+ Context: {config.context} +
+ {config.cluster_url && ( +
+ Cluster: {config.cluster_url} +
+ )} +
+
+
+ {!config.is_active && ( + + )} +
+
+
+ ))} +
+ )}
{/* Port Forwarding Section */}

Port Forwarding

-
setIsStartPortForwardOpen(true)} + onStart={() => {}} onStop={handleStopPortForward} onDelete={handleDeletePortForward} /> @@ -146,20 +201,8 @@ export function KubernetesPage() {
)} - - {/* Add Cluster Modal */} - setIsAddClusterOpen(false)} - onAdd={handleAddCluster} - /> - - {/* Port Forward Form */} - setIsStartPortForwardOpen(false)} - onStart={handleStartPortForward} - /> ); } + + From 5b85480608ea821d56a72c9e87797bfe0860d88c Mon Sep 17 00:00:00 2001 From: Shaun Arman Date: Sun, 7 Jun 2026 12:29:39 -0500 Subject: [PATCH 2/2] fix(kubernetes): sync active kubeconfig to store's selectedClusterId - Update handleActivateKubeconfig to call setSelectedCluster after activation - ResourceBrowser now loads resources for the activated kubeconfig's cluster - All tests passing, build successful --- src/pages/Kubernetes/KubernetesPage.tsx | 11 +++++++++-- src/stores/kubernetesStore.ts | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/pages/Kubernetes/KubernetesPage.tsx b/src/pages/Kubernetes/KubernetesPage.tsx index e910eca2..b3ddeef5 100644 --- a/src/pages/Kubernetes/KubernetesPage.tsx +++ b/src/pages/Kubernetes/KubernetesPage.tsx @@ -15,7 +15,7 @@ import { } from "@/lib/tauriCommands"; export function KubernetesPage() { - const { selectedClusterId } = useKubernetesStore(); + const { selectedClusterId, setSelectedCluster } = useKubernetesStore(); const [kubeconfigs, setKubeconfigs] = useState([]); const [portForwards, setPortForwards] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -44,7 +44,14 @@ export function KubernetesPage() { const handleActivateKubeconfig = async (id: string) => { try { await activateKubeconfigCmd(id); - await loadData(); + const [kubeconfigsData] = await Promise.all([listKubeconfigsCmd()]); + setKubeconfigs(kubeconfigsData); + + // Select the active cluster from the activated kubeconfig + const activeConfig = kubeconfigsData.find((c) => c.is_active); + if (activeConfig) { + setSelectedCluster(activeConfig.id); + } } catch (err) { console.error("Failed to activate kubeconfig:", err); alert("Failed to activate kubeconfig"); diff --git a/src/stores/kubernetesStore.ts b/src/stores/kubernetesStore.ts index 2cca272a..69551a92 100644 --- a/src/stores/kubernetesStore.ts +++ b/src/stores/kubernetesStore.ts @@ -1,5 +1,5 @@ import { create } from "zustand"; -import type { ClusterInfo, ContextInfo, ResourceInfo } from "@/lib/tauriCommands"; +import type { ClusterInfo, ContextInfo, ResourceInfo, KubeconfigInfo } from "@/lib/tauriCommands"; export type ResourceType = | "pods" @@ -103,6 +103,13 @@ export const useKubernetesStore = create()((set, get) => ({ // Actions setSelectedCluster: (clusterId) => set({ selectedClusterId: clusterId, selectedNamespace: "all" }), + selectClusterFromKubeconfig: (kubeconfigs: KubeconfigInfo[]) => { + const activeConfig = kubeconfigs.find((c) => c.is_active); + if (activeConfig) { + set({ selectedClusterId: activeConfig.id, selectedNamespace: "all" }); + } + }, + setSelectedNamespace: (namespace) => set({ selectedNamespace: namespace }), addCluster: (cluster) => set((state) => ({