Compare commits
No commits in common. "77833f6ee85373fdef1cce3325dd895a65815331" and "6703fed6e0089225cac190ae638a57a056cbd1ff" have entirely different histories.
77833f6ee8
...
6703fed6e0
@ -1,24 +1,25 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useKubernetesStore } from "@/stores/kubernetesStore";
|
import { useKubernetesStore } from "@/stores/kubernetesStore";
|
||||||
|
import { ClusterList } from "@/components/Kubernetes/ClusterList";
|
||||||
import { PortForwardList } from "@/components/Kubernetes/PortForwardList";
|
import { PortForwardList } from "@/components/Kubernetes/PortForwardList";
|
||||||
|
import { AddClusterModal } from "@/components/Kubernetes/AddClusterModal";
|
||||||
import { PortForwardForm } from "@/components/Kubernetes/PortForwardForm";
|
import { PortForwardForm } from "@/components/Kubernetes/PortForwardForm";
|
||||||
import { ResourceBrowser } from "@/components/Kubernetes/ResourceBrowser";
|
import { ResourceBrowser } from "@/components/Kubernetes/ResourceBrowser";
|
||||||
import type { PortForwardResponse, KubeconfigInfo, PortForwardRequest } from "@/lib/tauriCommands";
|
import type { ClusterInfo, PortForwardResponse } from "@/lib/tauriCommands";
|
||||||
import {
|
import {
|
||||||
|
listClustersCmd,
|
||||||
|
removeClusterCmd,
|
||||||
listPortForwardsCmd,
|
listPortForwardsCmd,
|
||||||
stopPortForwardCmd,
|
stopPortForwardCmd,
|
||||||
deletePortForwardCmd,
|
deletePortForwardCmd,
|
||||||
listKubeconfigsCmd,
|
|
||||||
activateKubeconfigCmd,
|
|
||||||
startPortForwardCmd,
|
|
||||||
} from "@/lib/tauriCommands";
|
} from "@/lib/tauriCommands";
|
||||||
|
|
||||||
export function KubernetesPage() {
|
export function KubernetesPage() {
|
||||||
const { selectedClusterId, setSelectedCluster } = useKubernetesStore();
|
const { clusters, addCluster, removeCluster, selectedClusterId } = useKubernetesStore();
|
||||||
const [kubeconfigs, setKubeconfigs] = useState<KubeconfigInfo[]>([]);
|
|
||||||
const [portForwards, setPortForwards] = useState<PortForwardResponse[]>([]);
|
const [portForwards, setPortForwards] = useState<PortForwardResponse[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [isAddClusterOpen, setIsAddClusterOpen] = useState(false);
|
||||||
|
const [isStartPortForwardOpen, setIsStartPortForwardOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadData();
|
loadData();
|
||||||
@ -27,12 +28,12 @@ export function KubernetesPage() {
|
|||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const [kubeconfigsData, portForwardsData] = await Promise.all([
|
const [clustersData, portForwardsData] = await Promise.all([
|
||||||
listKubeconfigsCmd(),
|
listClustersCmd(),
|
||||||
listPortForwardsCmd(),
|
listPortForwardsCmd(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
setKubeconfigs(kubeconfigsData);
|
clustersData.forEach(addCluster);
|
||||||
setPortForwards(portForwardsData);
|
setPortForwards(portForwardsData);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to load data:", err);
|
console.error("Failed to load data:", err);
|
||||||
@ -41,20 +42,13 @@ export function KubernetesPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleActivateKubeconfig = async (id: string) => {
|
const handleRemoveCluster = async (clusterId: string) => {
|
||||||
try {
|
try {
|
||||||
await activateKubeconfigCmd(id);
|
await removeClusterCmd(clusterId);
|
||||||
const [kubeconfigsData] = await Promise.all([listKubeconfigsCmd()]);
|
removeCluster(clusterId);
|
||||||
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) {
|
} catch (err) {
|
||||||
console.error("Failed to activate kubeconfig:", err);
|
console.error("Failed to remove cluster:", err);
|
||||||
alert("Failed to activate kubeconfig");
|
alert("Failed to remove cluster");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,14 +72,12 @@ export function KubernetesPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartPortForward = async (portForward: PortForwardRequest) => {
|
const handleAddCluster = (cluster: ClusterInfo) => {
|
||||||
try {
|
addCluster(cluster);
|
||||||
const result = await startPortForwardCmd(portForward);
|
};
|
||||||
setPortForwards((prev) => [...prev, result]);
|
|
||||||
} catch (err) {
|
const handleStartPortForward = (portForward: PortForwardResponse) => {
|
||||||
console.error("Failed to start port forward:", err);
|
setPortForwards((prev) => [...prev, portForward]);
|
||||||
alert("Failed to start port forward");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@ -108,94 +100,40 @@ export function KubernetesPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Cluster Management Section - Uses kubeconfig files from Settings */}
|
{/* Cluster Management Section */}
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-xl font-semibold">Clusters (from kubeconfig files)</h2>
|
<h2 className="text-xl font-semibold">Clusters</h2>
|
||||||
<div className="flex gap-2">
|
|
||||||
<button
|
<button
|
||||||
onClick={() => window.location.href = "/settings/kubeconfig"}
|
onClick={() => setIsAddClusterOpen(true)}
|
||||||
className="px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-secondary/90"
|
|
||||||
>
|
|
||||||
Manage kubeconfigs
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{kubeconfigs.length === 0 ? (
|
|
||||||
<div className="rounded-lg border border-dashed px-6 py-12 text-center bg-card">
|
|
||||||
<div className="mx-auto w-12 h-12 text-muted-foreground mb-4">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 className="text-lg font-medium mb-2">No kubeconfig files uploaded</h3>
|
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
|
||||||
Upload kubeconfig files in Settings → Kubeconfig to manage Kubernetes clusters
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
onClick={() => window.location.href = "/settings/kubeconfig"}
|
|
||||||
className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
|
className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
|
||||||
>
|
>
|
||||||
Go to Kubeconfig Manager
|
Add Cluster
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<div className="grid gap-4">
|
<ClusterList
|
||||||
{kubeconfigs.map((config) => (
|
clusters={clusters}
|
||||||
<div
|
onAdd={() => setIsAddClusterOpen(true)}
|
||||||
key={config.id}
|
onRemove={handleRemoveCluster}
|
||||||
className={`rounded-lg border bg-card p-4 hover:border-primary/50 transition-colors ${
|
/>
|
||||||
config.is_active ? "border-primary ring-1 ring-primary/20" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="flex items-start justify-between">
|
|
||||||
<div className="space-y-1 flex-1">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<h3 className="font-medium text-lg">{config.name}</h3>
|
|
||||||
{config.is_active && (
|
|
||||||
<span className="px-2 py-1 text-xs font-semibold bg-green-100 text-green-800 rounded">
|
|
||||||
Active
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="text-sm text-muted-foreground space-y-1">
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">Context:</span> {config.context}
|
|
||||||
</div>
|
|
||||||
{config.cluster_url && (
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">Cluster:</span> {config.cluster_url}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
{!config.is_active && (
|
|
||||||
<button
|
|
||||||
onClick={() => handleActivateKubeconfig(config.id)}
|
|
||||||
className="px-3 py-1 text-sm bg-secondary text-secondary-foreground rounded hover:bg-secondary/90"
|
|
||||||
>
|
|
||||||
Activate
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Port Forwarding Section */}
|
{/* Port Forwarding Section */}
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-xl font-semibold">Port Forwarding</h2>
|
<h2 className="text-xl font-semibold">Port Forwarding</h2>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsStartPortForwardOpen(true)}
|
||||||
|
className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
|
||||||
|
>
|
||||||
|
Start Port Forward
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PortForwardList
|
<PortForwardList
|
||||||
portForwards={portForwards}
|
portForwards={portForwards}
|
||||||
onStart={() => {}}
|
onStart={() => setIsStartPortForwardOpen(true)}
|
||||||
onStop={handleStopPortForward}
|
onStop={handleStopPortForward}
|
||||||
onDelete={handleDeletePortForward}
|
onDelete={handleDeletePortForward}
|
||||||
/>
|
/>
|
||||||
@ -208,8 +146,20 @@ export function KubernetesPage() {
|
|||||||
<ResourceBrowser clusterId={selectedClusterId} />
|
<ResourceBrowser clusterId={selectedClusterId} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Add Cluster Modal */}
|
||||||
|
<AddClusterModal
|
||||||
|
isOpen={isAddClusterOpen}
|
||||||
|
onClose={() => setIsAddClusterOpen(false)}
|
||||||
|
onAdd={handleAddCluster}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Port Forward Form */}
|
||||||
|
<PortForwardForm
|
||||||
|
isOpen={isStartPortForwardOpen}
|
||||||
|
onClose={() => setIsStartPortForwardOpen(false)}
|
||||||
|
onStart={handleStartPortForward}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import type { ClusterInfo, ContextInfo, ResourceInfo, KubeconfigInfo } from "@/lib/tauriCommands";
|
import type { ClusterInfo, ContextInfo, ResourceInfo } from "@/lib/tauriCommands";
|
||||||
|
|
||||||
export type ResourceType =
|
export type ResourceType =
|
||||||
| "pods"
|
| "pods"
|
||||||
@ -103,13 +103,6 @@ export const useKubernetesStore = create<KubernetesState>()((set, get) => ({
|
|||||||
// Actions
|
// Actions
|
||||||
setSelectedCluster: (clusterId) => set({ selectedClusterId: clusterId, selectedNamespace: "all" }),
|
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 }),
|
setSelectedNamespace: (namespace) => set({ selectedNamespace: namespace }),
|
||||||
|
|
||||||
addCluster: (cluster) => set((state) => ({
|
addCluster: (cluster) => set((state) => ({
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user