diff --git a/ui/app/providers.tsx b/ui/app/providers.tsx index 248a899..9f47742 100644 --- a/ui/app/providers.tsx +++ b/ui/app/providers.tsx @@ -1,6 +1,7 @@ 'use client' -import { KubernetesProvider } from '@/contexts/KubernetesContext' +import { KubernetesProvider } from '@kubernetesjs/react/context' +import { NamespaceProvider } from '@/contexts/NamespaceContext' interface ProvidersProps { children: React.ReactNode @@ -8,8 +9,14 @@ interface ProvidersProps { export function Providers({ children }: ProvidersProps) { return ( - - {children} + + + {children} + ) -} \ No newline at end of file +} diff --git a/ui/components/dashboard-layout.tsx b/ui/components/dashboard-layout.tsx index 683c44f..04d05d0 100644 --- a/ui/components/dashboard-layout.tsx +++ b/ui/components/dashboard-layout.tsx @@ -5,7 +5,7 @@ import Link from 'next/link' import { usePathname } from 'next/navigation' import { Button } from '@/components/ui/button' import { NamespaceSwitcher } from '@/components/namespace-switcher' -import { useKubernetes } from '@/hooks' +import { usePreferredNamespace } from '@/hooks' import { Package, Server, @@ -38,7 +38,7 @@ interface DashboardLayoutProps { export function DashboardLayout({ children }: DashboardLayoutProps) { const [sidebarOpen, setSidebarOpen] = useState(true) const pathname = usePathname() - const { config } = useKubernetes() + const { namespace } = usePreferredNamespace() // Find active section based on pathname const activeSection = navigationItems.find(item => item.href === pathname)?.label || 'Overview' @@ -87,7 +87,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
- Cluster: {config.restEndpoint} + Namespace: {namespace}
@@ -99,4 +99,4 @@ export function DashboardLayout({ children }: DashboardLayoutProps) { ) -} \ No newline at end of file +} diff --git a/ui/components/namespace-switcher.tsx b/ui/components/namespace-switcher.tsx index d843f48..67ad402 100644 --- a/ui/components/namespace-switcher.tsx +++ b/ui/components/namespace-switcher.tsx @@ -1,6 +1,7 @@ 'use client' -import { useKubernetes, useNamespaces } from '@/hooks' +import { useNamespaces } from '@/hooks' +import { usePreferredNamespace } from '../contexts/NamespaceContext' import { Select, SelectContent, @@ -13,10 +14,10 @@ import { RefreshCw } from 'lucide-react' import { Button } from '@/components/ui/button' export function NamespaceSwitcher() { - const { namespace, setNamespace } = useKubernetes() + const { namespace, setNamespace } = usePreferredNamespace() const { data, isLoading, error, refetch } = useNamespaces() - const namespaces = data?.items?.map(item => item.metadata?.name).filter(Boolean) || [] + const namespaces = data?.items?.map((item: any) => item.metadata?.name).filter(Boolean) || [] return (
@@ -33,22 +34,22 @@ export function NamespaceSwitcher() {
All Namespaces - + All
- {namespaces.map((ns) => ( + {namespaces.map((ns: any) => (
{ns} {ns === 'default' && ( - + Default )} {(ns === 'kube-system' || ns === 'kube-public') && ( - + System )} @@ -68,4 +69,4 @@ export function NamespaceSwitcher() {
) -} \ No newline at end of file +} diff --git a/ui/components/resources/pods.tsx b/ui/components/resources/pods.tsx index fcbebca..c529156 100644 --- a/ui/components/resources/pods.tsx +++ b/ui/components/resources/pods.tsx @@ -16,8 +16,8 @@ import { Clock, XCircle } from 'lucide-react' -import { type Pod as K8sPod } from 'kubernetesjs' -import { usePods, useDeletePod, usePodLogs, useKubernetes } from '@/hooks' + +import { usePods, useDeletePod, usePodLogs, usePreferredNamespace } from '@/hooks' interface Pod { name: string @@ -27,19 +27,19 @@ interface Pod { restarts: number age: string nodeName: string - k8sData?: K8sPod + k8sData?: any } export function PodsView() { const [selectedPod, setSelectedPod] = useState(null) // Use TanStack Query hooks - const { namespace } = useKubernetes() + const { namespace } = usePreferredNamespace() const { data, isLoading, error, refetch } = usePods() const deletePodMutation = useDeletePod() // Helper function to determine pod status - function determinePodStatus(pod: K8sPod): Pod['status'] { + function determinePodStatus(pod: any): Pod['status'] { const phase = pod.status?.phase if (phase === 'Running') return 'Running' if (phase === 'Pending') return 'Pending' @@ -49,11 +49,11 @@ export function PodsView() { } // Format pods from query data - const pods: Pod[] = data?.items?.map(item => { + const pods: Pod[] = data?.items?.map((item: any) => { const containerStatuses = item.status?.containerStatuses || [] - const readyContainers = containerStatuses.filter(cs => cs.ready).length + const readyContainers = containerStatuses.filter((cs: any) => cs.ready).length const totalContainers = containerStatuses.length - const totalRestarts = containerStatuses.reduce((sum, cs) => sum + (cs.restartCount || 0), 0) + const totalRestarts = containerStatuses.reduce((sum: number, cs: any) => sum + (cs.restartCount || 0), 0) return { name: item.metadata!.name!, @@ -93,27 +93,27 @@ export function PodsView() { const getStatusBadge = (status: Pod['status']) => { switch (status) { case 'Running': - return + return {status} case 'Pending': - return + return {status} case 'Failed': - return + return {status} case 'Succeeded': - return + return {status} default: - return {status} + return {status} } } diff --git a/ui/components/templates/template-dialog.tsx b/ui/components/templates/template-dialog.tsx index 2e1432e..8b32f8a 100644 --- a/ui/components/templates/template-dialog.tsx +++ b/ui/components/templates/template-dialog.tsx @@ -14,14 +14,15 @@ import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Alert, AlertDescription } from '@/components/ui/alert' import { Loader2, CheckCircle, XCircle } from 'lucide-react' -import { type Deployment, type Service } from 'kubernetesjs' -import { useKubernetes } from '@/hooks' + +import { usePreferredNamespace } from '@/hooks' +import { useCreateAppsV1NamespacedDeploymentMutation, useCreateCoreV1NamespacedServiceMutation } from '@kubernetesjs/react' interface Template { id: string name: string description: string - icon: React.ComponentType<{ className?: string }> + icon: any details: { image: string ports: number[] @@ -36,7 +37,9 @@ interface TemplateDialogProps { } export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogProps) { - const { client: k8sClient, namespace: contextNamespace } = useKubernetes() + const { namespace: contextNamespace } = usePreferredNamespace() + const createDeployment = useCreateAppsV1NamespacedDeploymentMutation() + const createService = useCreateCoreV1NamespacedServiceMutation() // Deploy template function const deployTemplate = async (params: { @@ -50,7 +53,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP const { templateId, name, namespace, image, ports, environment } = params // Create deployment configuration - const deployment: Deployment = { + const deployment = { apiVersion: 'apps/v1', kind: 'Deployment', metadata: { @@ -88,11 +91,13 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP // Handle specific args for minio if (templateId === 'minio') { - deployment.spec!.template.spec!.containers[0].args = ['server', '/data'] + if (deployment.spec?.template?.spec?.containers?.[0]) { + (deployment.spec.template.spec.containers[0] as any).args = ['server', '/data'] + } } // Create service configuration - const service: Service = { + const service = { apiVersion: 'v1', kind: 'Service', metadata: { @@ -117,14 +122,14 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP } // Create deployment first using typed client - await k8sClient.createAppsV1NamespacedDeployment({ + await createDeployment.mutateAsync({ path: { namespace }, query: {}, body: deployment, }) // Then create service using typed client - await k8sClient.createCoreV1NamespacedService({ + await createService.mutateAsync({ path: { namespace }, query: {}, body: service, @@ -205,7 +210,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP setDeploymentName(e.target.value)} + onChange={(e: any) => setDeploymentName(e.target.value)} className="col-span-3" disabled={isDeploying} /> @@ -218,7 +223,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP setNamespace(e.target.value)} + onChange={(e: any) => setNamespace(e.target.value)} className="col-span-3" disabled={isDeploying} /> @@ -290,4 +295,4 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP ) -} \ No newline at end of file +} diff --git a/ui/contexts/KubernetesContext.tsx b/ui/contexts/KubernetesContext.tsx deleted file mode 100644 index 9d7fb9e..0000000 --- a/ui/contexts/KubernetesContext.tsx +++ /dev/null @@ -1,99 +0,0 @@ -'use client' - -import React, { createContext, useContext, useMemo, useState } from 'react' -import { KubernetesClient } from 'kubernetesjs' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' - -// Configuration types -export interface KubernetesConfig { - restEndpoint: string - namespace?: string - headers?: Record -} - -// Context types -interface KubernetesContextValue { - client: KubernetesClient - config: KubernetesConfig - namespace: string - setNamespace: (namespace: string) => void - updateConfig: (config: Partial) => void -} - -// Create context -const KubernetesContext = createContext(undefined) - -// Query client for TanStack Query -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - retry: 3, - staleTime: 30 * 1000, // 30 seconds - gcTime: 5 * 60 * 1000, // 5 minutes - }, - }, -}) - -// Provider props -interface KubernetesProviderProps { - children: React.ReactNode - initialConfig?: Partial -} - -// Provider component -export function KubernetesProvider({ - children, - initialConfig -}: KubernetesProviderProps) { - const [config, setConfig] = useState({ - restEndpoint: initialConfig?.restEndpoint || process.env.NEXT_PUBLIC_K8S_API_URL || '/api/k8s', - namespace: initialConfig?.namespace || 'default', - headers: initialConfig?.headers || {}, - }) - - const [namespace, setNamespace] = useState(config.namespace || 'default') - - // Create client instance - const client = useMemo(() => { - return new KubernetesClient({ - restEndpoint: config.restEndpoint, - }) - }, [config.restEndpoint]) - - // Update config function - const updateConfig = (newConfig: Partial) => { - setConfig(prev => ({ ...prev, ...newConfig })) - if (newConfig.namespace) { - setNamespace(newConfig.namespace) - } - } - - const contextValue: KubernetesContextValue = { - client, - config, - namespace, - setNamespace, - updateConfig, - } - - return ( - - - {children} - - - ) -} - -// Hook to use Kubernetes context -export function useKubernetes() { - const context = useContext(KubernetesContext) - if (!context) { - throw new Error('useKubernetes must be used within a KubernetesProvider') - } - return context -} - -// Export query client for use in hooks -export { queryClient } \ No newline at end of file diff --git a/ui/contexts/NamespaceContext.tsx b/ui/contexts/NamespaceContext.tsx new file mode 100644 index 0000000..e9ae377 --- /dev/null +++ b/ui/contexts/NamespaceContext.tsx @@ -0,0 +1,52 @@ +'use client' + +import { createContext, useContext, useState, useEffect } from 'react' + +interface NamespaceContextValue { + namespace: string + setNamespace: (namespace: string) => void +} + +const NamespaceContext = createContext(undefined) + +interface NamespaceProviderProps { + children: React.ReactNode +} + +export function NamespaceProvider({ children }: NamespaceProviderProps) { + const [namespace, setNamespace] = useState('default') + + useEffect(() => { + if (typeof window !== 'undefined') { + const savedNamespace = localStorage.getItem('kubernetes-namespace') + if (savedNamespace) { + setNamespace(savedNamespace) + } + } + }, []) + + useEffect(() => { + if (typeof window !== 'undefined') { + localStorage.setItem('kubernetes-namespace', namespace) + } + }, [namespace]) + + const contextValue: NamespaceContextValue = { + namespace, + setNamespace, + } + + return ( + + {children} + + ) +} + +export function usePreferredNamespace() { + const context = useContext(NamespaceContext) + if (!context) { + throw new Error('usePreferredNamespace must be used within a NamespaceProvider') + } + return context +} diff --git a/ui/hooks/index.ts b/ui/hooks/index.ts index c1f70e3..cc03db5 100644 --- a/ui/hooks/index.ts +++ b/ui/hooks/index.ts @@ -7,6 +7,7 @@ export * from './useConfigMaps' export * from './usePods' export * from './useDaemonSets' export * from './useReplicaSets' +export * from './useJobs' // Re-export context hook -export { useKubernetes } from '../contexts/KubernetesContext' \ No newline at end of file +export { usePreferredNamespace } from '../contexts/NamespaceContext' diff --git a/ui/hooks/useConfigMaps.ts b/ui/hooks/useConfigMaps.ts index 927cf20..c1b25dc 100644 --- a/ui/hooks/useConfigMaps.ts +++ b/ui/hooks/useConfigMaps.ts @@ -1,111 +1,52 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { ConfigMap, ConfigMapList } from 'kubernetesjs' +import { + useListCoreV1NamespacedConfigMapQuery, + useListCoreV1ConfigMapForAllNamespacesQuery, + useReadCoreV1NamespacedConfigMapQuery, + useCreateCoreV1NamespacedConfigMapMutation, + useReplaceCoreV1NamespacedConfigMapMutation, + useDeleteCoreV1NamespacedConfigMapMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' -// Query keys -const CONFIGMAPS_KEY = ['configmaps'] as const export function useConfigMaps(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...CONFIGMAPS_KEY, ns], - queryFn: async () => { - if (ns === '_all') { - const result = await client.listCoreV1ConfigMapForAllNamespaces({ - query: {}, - }) - return result - } else { - const result = await client.listCoreV1NamespacedConfigMap({ - path: { namespace: ns }, - query: {}, - }) - return result - } - }, - refetchOnMount: 'always', - staleTime: 0, + const allConfigMapsQuery = useListCoreV1ConfigMapForAllNamespacesQuery({ + query: {}, }) + + const namespacedConfigMapsQuery = useListCoreV1NamespacedConfigMapQuery({ + path: { namespace: ns }, + query: {}, + }) + + if (ns === '_all') { + return allConfigMapsQuery + } else { + return namespacedConfigMapsQuery + } } export function useConfigMap(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...CONFIGMAPS_KEY, ns, name], - queryFn: async () => { - const result = await client.readCoreV1NamespacedConfigMap({ - path: { namespace: ns, name }, - query: {}, - }) - return result - }, - enabled: !!name, - refetchOnMount: 'always', - staleTime: 0, + return useReadCoreV1NamespacedConfigMapQuery({ + path: { namespace: ns, name }, + query: {}, }) } export function useCreateConfigMap() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ configMap, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.createCoreV1NamespacedConfigMap({ - path: { namespace: ns }, - query: {}, - body: configMap, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...CONFIGMAPS_KEY, ns] }) - }, - }) + return useCreateCoreV1NamespacedConfigMapMutation() } export function useUpdateConfigMap() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, configMap, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.replaceCoreV1NamespacedConfigMap({ - path: { namespace: ns, name }, - query: {}, - body: configMap, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...CONFIGMAPS_KEY, ns] }) - }, - }) + return useReplaceCoreV1NamespacedConfigMapMutation() } export function useDeleteConfigMap() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, namespace }) => { - const ns = namespace || defaultNamespace - await client.deleteCoreV1NamespacedConfigMap({ - path: { namespace: ns, name }, - query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...CONFIGMAPS_KEY, ns] }) - }, - }) -} \ No newline at end of file + return useDeleteCoreV1NamespacedConfigMapMutation() +} diff --git a/ui/hooks/useDaemonSets.ts b/ui/hooks/useDaemonSets.ts index 6c473f7..c948be3 100644 --- a/ui/hooks/useDaemonSets.ts +++ b/ui/hooks/useDaemonSets.ts @@ -1,69 +1,42 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { DaemonSet, DaemonSetList } from 'kubernetesjs' +import { + useListAppsV1NamespacedDaemonSetQuery, + useListAppsV1DaemonSetForAllNamespacesQuery, + useReadAppsV1NamespacedDaemonSetQuery, + useDeleteAppsV1NamespacedDaemonSetMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' -// Query keys -const DAEMONSETS_KEY = ['daemonsets'] as const export function useDaemonSets(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...DAEMONSETS_KEY, ns], - queryFn: async () => { - if (ns === '_all') { - const result = await client.listAppsV1DaemonSetForAllNamespaces({ - query: {}, - }) - return result - } else { - const result = await client.listAppsV1NamespacedDaemonSet({ - path: { namespace: ns }, - query: {}, - }) - return result - } - }, - refetchOnMount: 'always', - staleTime: 0, + const allDaemonSetsQuery = useListAppsV1DaemonSetForAllNamespacesQuery({ + query: {}, }) + + const namespacedDaemonSetsQuery = useListAppsV1NamespacedDaemonSetQuery({ + path: { namespace: ns }, + query: {}, + }) + + if (ns === '_all') { + return allDaemonSetsQuery + } else { + return namespacedDaemonSetsQuery + } } export function useDaemonSet(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...DAEMONSETS_KEY, ns, name], - queryFn: async () => { - const result = await client.readAppsV1NamespacedDaemonSet({ - path: { namespace: ns, name }, - query: {}, - }) - return result - }, - enabled: !!name, - refetchOnMount: 'always', - staleTime: 0, + return useReadAppsV1NamespacedDaemonSetQuery({ + path: { namespace: ns, name }, + query: {}, }) } export function useDeleteDaemonSet() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, namespace }) => { - const ns = namespace || defaultNamespace - await client.deleteAppsV1NamespacedDaemonSet({ - path: { namespace: ns, name }, - query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DAEMONSETS_KEY, ns] }) - }, - }) + return useDeleteAppsV1NamespacedDaemonSetMutation() } diff --git a/ui/hooks/useDeployments.ts b/ui/hooks/useDeployments.ts index e939acf..1de9956 100644 --- a/ui/hooks/useDeployments.ts +++ b/ui/hooks/useDeployments.ts @@ -1,145 +1,58 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Deployment, DeploymentList } from 'kubernetesjs' +import { + useListAppsV1NamespacedDeploymentQuery, + useListAppsV1DeploymentForAllNamespacesQuery, + useReadAppsV1NamespacedDeploymentQuery, + useCreateAppsV1NamespacedDeploymentMutation, + useReplaceAppsV1NamespacedDeploymentMutation, + useDeleteAppsV1NamespacedDeploymentMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' -// Query keys -const DEPLOYMENTS_KEY = ['deployments'] as const export function useDeployments(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...DEPLOYMENTS_KEY, ns], - queryFn: async () => { - if (ns === '_all') { - // Fetch from all namespaces - const result = await client.listAppsV1DeploymentForAllNamespaces({ - query: {}, - }) - return result - } else { - // Fetch from specific namespace - const result = await client.listAppsV1NamespacedDeployment({ - path: { namespace: ns }, - query: {}, - }) - return result - } - }, - refetchOnMount: 'always', - staleTime: 0, + const allDeploymentsQuery = useListAppsV1DeploymentForAllNamespacesQuery({ + query: {}, }) + + const namespacedDeploymentsQuery = useListAppsV1NamespacedDeploymentQuery({ + path: { namespace: ns }, + query: {}, + }) + + if (ns === '_all') { + return allDeploymentsQuery + } else { + return namespacedDeploymentsQuery + } } export function useDeployment(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...DEPLOYMENTS_KEY, ns, name], - queryFn: async () => { - const result = await client.readAppsV1NamespacedDeployment({ - path: { namespace: ns, name }, - query: {}, - }) - return result - }, - enabled: !!name, + return useReadAppsV1NamespacedDeploymentQuery({ + path: { namespace: ns, name }, + query: {}, }) } export function useCreateDeployment() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ deployment, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.createAppsV1NamespacedDeployment({ - path: { namespace: ns }, - query: {}, - body: deployment, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) + return useCreateAppsV1NamespacedDeploymentMutation() } export function useUpdateDeployment() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, deployment, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.replaceAppsV1NamespacedDeployment({ - path: { namespace: ns, name }, - query: {}, - body: deployment, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) + return useReplaceAppsV1NamespacedDeploymentMutation() } export function useDeleteDeployment() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, namespace }) => { - const ns = namespace || defaultNamespace - await client.deleteAppsV1NamespacedDeployment({ - path: { namespace: ns, name }, - query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) + return useDeleteAppsV1NamespacedDeploymentMutation() } export function useScaleDeployment() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() + const updateDeployment = useReplaceAppsV1NamespacedDeploymentMutation() - return useMutation({ - mutationFn: async ({ name, replicas, namespace }) => { - const ns = namespace || defaultNamespace - - // First, get the current deployment - const deployment = await client.readAppsV1NamespacedDeployment({ - path: { namespace: ns, name }, - query: {}, - }) - - // Update the replicas - if (deployment.spec) { - deployment.spec.replicas = replicas - } - - // Update the deployment - const result = await client.replaceAppsV1NamespacedDeployment({ - path: { namespace: ns, name }, - query: {}, - body: deployment, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) -} \ No newline at end of file + return updateDeployment +} diff --git a/ui/hooks/useJobs.ts b/ui/hooks/useJobs.ts new file mode 100644 index 0000000..5abe9e4 --- /dev/null +++ b/ui/hooks/useJobs.ts @@ -0,0 +1,42 @@ +import { + useListBatchV1NamespacedJobQuery, + useListBatchV1JobForAllNamespacesQuery, + useReadBatchV1NamespacedJobQuery, + useDeleteBatchV1NamespacedJobMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' + + +export function useJobs(namespace?: string) { + const { namespace: defaultNamespace } = usePreferredNamespace() + const ns = namespace || defaultNamespace + + const allJobsQuery = useListBatchV1JobForAllNamespacesQuery({ + query: {}, + }) + + const namespacedJobsQuery = useListBatchV1NamespacedJobQuery({ + path: { namespace: ns }, + query: {}, + }) + + if (ns === '_all') { + return allJobsQuery + } else { + return namespacedJobsQuery + } +} + +export function useJob(name: string, namespace?: string) { + const { namespace: defaultNamespace } = usePreferredNamespace() + const ns = namespace || defaultNamespace + + return useReadBatchV1NamespacedJobQuery({ + path: { namespace: ns, name }, + query: {}, + }) +} + +export function useDeleteJob() { + return useDeleteBatchV1NamespacedJobMutation() +} diff --git a/ui/hooks/useNamespaces.ts b/ui/hooks/useNamespaces.ts index 06dd2fa..8160d6c 100644 --- a/ui/hooks/useNamespaces.ts +++ b/ui/hooks/useNamespaces.ts @@ -1,80 +1,27 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Namespace, NamespaceList } from 'kubernetesjs' - -// Query keys -const NAMESPACES_KEY = ['namespaces'] as const +import { + useListCoreV1NamespaceQuery, + useReadCoreV1NamespaceQuery, + useCreateCoreV1NamespaceMutation, + useDeleteCoreV1NamespaceMutation +} from '@kubernetesjs/react' export function useNamespaces() { - const { client } = useKubernetes() - - return useQuery({ - queryKey: NAMESPACES_KEY, - queryFn: async () => { - const result = await client.listCoreV1Namespace({ - path: {}, - query: {}, - }) - return result - }, + return useListCoreV1NamespaceQuery({ + query: {}, }) } export function useNamespace(name: string) { - const { client } = useKubernetes() - - return useQuery({ - queryKey: [...NAMESPACES_KEY, name], - queryFn: async () => { - const result = await client.readCoreV1Namespace({ - path: { name }, - query: {}, - }) - return result - }, - enabled: !!name, + return useReadCoreV1NamespaceQuery({ + path: { name }, + query: {}, }) } export function useCreateNamespace() { - const { client } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation }>({ - mutationFn: async ({ name, labels }) => { - const result = await client.createCoreV1Namespace({ - path: {}, - query: {}, - body: { - apiVersion: 'v1', - kind: 'Namespace', - metadata: { - name, - labels, - }, - }, - }) - return result - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: NAMESPACES_KEY }) - }, - }) + return useCreateCoreV1NamespaceMutation() } export function useDeleteNamespace() { - const { client } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async (name) => { - await client.deleteCoreV1Namespace({ - path: { name }, - query: {}, - }) - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: NAMESPACES_KEY }) - }, - }) -} \ No newline at end of file + return useDeleteCoreV1NamespaceMutation() +} diff --git a/ui/hooks/usePods.ts b/ui/hooks/usePods.ts index 3bde486..1ad77db 100644 --- a/ui/hooks/usePods.ts +++ b/ui/hooks/usePods.ts @@ -1,103 +1,65 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Pod, PodList } from 'kubernetesjs' +import { + useListCoreV1NamespacedPodQuery, + useListCoreV1PodForAllNamespacesQuery, + useReadCoreV1NamespacedPodQuery, + useReadCoreV1NamespacedPodLogQuery, + useDeleteCoreV1NamespacedPodMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' -// Query keys -const PODS_KEY = ['pods'] as const export function usePods(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...PODS_KEY, ns], - queryFn: async () => { - if (ns === '_all') { - const result = await client.listPods({ - query: {}, - }) - return result - } else { - const result = await client.listCoreV1NamespacedPod({ - path: { namespace: ns }, - query: {}, - }) - return result - } - }, - refetchOnMount: 'always', - staleTime: 0, + const allPodsQuery = useListCoreV1PodForAllNamespacesQuery({ + query: {}, + }) + + const namespacedPodsQuery = useListCoreV1NamespacedPodQuery({ + path: { namespace: ns }, + query: {}, }) + + if (ns === '_all') { + return allPodsQuery + } else { + return namespacedPodsQuery + } } export function usePod(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...PODS_KEY, ns, name], - queryFn: async () => { - const result = await client.readCoreV1NamespacedPod({ - path: { namespace: ns, name }, - query: {}, - }) - return result - }, - enabled: !!name, + return useReadCoreV1NamespacedPodQuery({ + path: { namespace: ns, name }, + query: {}, }) } export function usePodLogs(name: string, namespace?: string, container?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...PODS_KEY, ns, name, 'logs', container], - queryFn: async () => { - const result = await client.readCoreV1NamespacedPodLog({ - path: { namespace: ns, name }, - query: container ? { container } : {}, - }) - return result as string - }, - enabled: !!name, + return useReadCoreV1NamespacedPodLogQuery({ + path: { namespace: ns, name }, + query: container ? { container } : {}, }) } export function useDeletePod() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, namespace }) => { - const ns = namespace || defaultNamespace - await client.deleteCoreV1NamespacedPod({ - path: { namespace: ns, name }, - query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...PODS_KEY, ns] }) - }, - }) + return useDeleteCoreV1NamespacedPodMutation() } export function usePodsForDeployment(deploymentName: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...PODS_KEY, ns, 'deployment', deploymentName], - queryFn: async () => { - const result = await client.listCoreV1NamespacedPod({ - path: { namespace: ns }, - query: { - labelSelector: `app=${deploymentName}`, - }, - }) - return result + return useListCoreV1NamespacedPodQuery({ + path: { namespace: ns }, + query: { + labelSelector: `app=${deploymentName}`, }, - enabled: !!deploymentName, }) -} \ No newline at end of file +} diff --git a/ui/hooks/useReplicaSets.ts b/ui/hooks/useReplicaSets.ts index 5130bd4..544a036 100644 --- a/ui/hooks/useReplicaSets.ts +++ b/ui/hooks/useReplicaSets.ts @@ -1,103 +1,49 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { ReplicaSet, ReplicaSetList } from 'kubernetesjs' +import { + useListAppsV1NamespacedReplicaSetQuery, + useListAppsV1ReplicaSetForAllNamespacesQuery, + useReadAppsV1NamespacedReplicaSetQuery, + useDeleteAppsV1NamespacedReplicaSetMutation, + useReplaceAppsV1NamespacedReplicaSetMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' -// Query keys -const REPLICASETS_KEY = ['replicasets'] as const export function useReplicaSets(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...REPLICASETS_KEY, ns], - queryFn: async () => { - if (ns === '_all') { - const result = await client.listAppsV1ReplicaSetForAllNamespaces({ - query: {}, - }) - return result - } else { - const result = await client.listAppsV1NamespacedReplicaSet({ - path: { namespace: ns }, - query: {}, - }) - return result - } - }, - refetchOnMount: 'always', - staleTime: 0, + const allReplicaSetsQuery = useListAppsV1ReplicaSetForAllNamespacesQuery({ + query: {}, }) + + const namespacedReplicaSetsQuery = useListAppsV1NamespacedReplicaSetQuery({ + path: { namespace: ns }, + query: {}, + }) + + if (ns === '_all') { + return allReplicaSetsQuery + } else { + return namespacedReplicaSetsQuery + } } export function useReplicaSet(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...REPLICASETS_KEY, ns, name], - queryFn: async () => { - const result = await client.readAppsV1NamespacedReplicaSet({ - path: { namespace: ns, name }, - query: {}, - }) - return result - }, - enabled: !!name, - refetchOnMount: 'always', - staleTime: 0, + return useReadAppsV1NamespacedReplicaSetQuery({ + path: { namespace: ns, name }, + query: {}, }) } export function useDeleteReplicaSet() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, namespace }) => { - const ns = namespace || defaultNamespace - await client.deleteAppsV1NamespacedReplicaSet({ - path: { namespace: ns, name }, - query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...REPLICASETS_KEY, ns] }) - }, - }) + return useDeleteAppsV1NamespacedReplicaSetMutation() } export function useScaleReplicaSet() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() + const updateReplicaSet = useReplaceAppsV1NamespacedReplicaSetMutation() - return useMutation({ - mutationFn: async ({ name, replicas, namespace }) => { - const ns = namespace || defaultNamespace - - // First, get the current replicaset - const replicaSet = await client.readAppsV1NamespacedReplicaSet({ - path: { namespace: ns, name }, - query: {}, - }) - - // Update the replicas - if (replicaSet.spec) { - replicaSet.spec.replicas = replicas - } - - // Update the replicaset - const result = await client.replaceAppsV1NamespacedReplicaSet({ - path: { namespace: ns, name }, - query: {}, - body: replicaSet, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...REPLICASETS_KEY, ns] }) - }, - }) + return updateReplicaSet } diff --git a/ui/hooks/useSecrets.ts b/ui/hooks/useSecrets.ts index 2cca9ee..2ac30cf 100644 --- a/ui/hooks/useSecrets.ts +++ b/ui/hooks/useSecrets.ts @@ -1,111 +1,52 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Secret, SecretList } from 'kubernetesjs' +import { + useListCoreV1NamespacedSecretQuery, + useListCoreV1SecretForAllNamespacesQuery, + useReadCoreV1NamespacedSecretQuery, + useCreateCoreV1NamespacedSecretMutation, + useReplaceCoreV1NamespacedSecretMutation, + useDeleteCoreV1NamespacedSecretMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' -// Query keys -const SECRETS_KEY = ['secrets'] as const export function useSecrets(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...SECRETS_KEY, ns], - queryFn: async () => { - if (ns === '_all') { - const result = await client.listCoreV1SecretForAllNamespaces({ - query: {}, - }) - return result - } else { - const result = await client.listCoreV1NamespacedSecret({ - path: { namespace: ns }, - query: {}, - }) - return result - } - }, - refetchOnMount: 'always', - staleTime: 0, + const allSecretsQuery = useListCoreV1SecretForAllNamespacesQuery({ + query: {}, }) + + const namespacedSecretsQuery = useListCoreV1NamespacedSecretQuery({ + path: { namespace: ns }, + query: {}, + }) + + if (ns === '_all') { + return allSecretsQuery + } else { + return namespacedSecretsQuery + } } export function useSecret(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...SECRETS_KEY, ns, name], - queryFn: async () => { - const result = await client.readCoreV1NamespacedSecret({ - path: { namespace: ns, name }, - query: {}, - }) - return result - }, - enabled: !!name, - refetchOnMount: 'always', - staleTime: 0, + return useReadCoreV1NamespacedSecretQuery({ + path: { namespace: ns, name }, + query: {}, }) } export function useCreateSecret() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ secret, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.createCoreV1NamespacedSecret({ - path: { namespace: ns }, - query: {}, - body: secret, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SECRETS_KEY, ns] }) - }, - }) + return useCreateCoreV1NamespacedSecretMutation() } export function useUpdateSecret() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, secret, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.replaceCoreV1NamespacedSecret({ - path: { namespace: ns, name }, - query: {}, - body: secret, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SECRETS_KEY, ns] }) - }, - }) + return useReplaceCoreV1NamespacedSecretMutation() } export function useDeleteSecret() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, namespace }) => { - const ns = namespace || defaultNamespace - await client.deleteCoreV1NamespacedSecret({ - path: { namespace: ns, name }, - query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SECRETS_KEY, ns] }) - }, - }) -} \ No newline at end of file + return useDeleteCoreV1NamespacedSecretMutation() +} diff --git a/ui/hooks/useServices.ts b/ui/hooks/useServices.ts index a7be032..1a5b9f1 100644 --- a/ui/hooks/useServices.ts +++ b/ui/hooks/useServices.ts @@ -1,111 +1,52 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Service, ServiceList } from 'kubernetesjs' +import { + useListCoreV1NamespacedServiceQuery, + useListCoreV1ServiceForAllNamespacesQuery, + useReadCoreV1NamespacedServiceQuery, + useCreateCoreV1NamespacedServiceMutation, + useReplaceCoreV1NamespacedServiceMutation, + useDeleteCoreV1NamespacedServiceMutation +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' -// Query keys -const SERVICES_KEY = ['services'] as const export function useServices(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...SERVICES_KEY, ns], - queryFn: async () => { - if (ns === '_all') { - const result = await client.listCoreV1ServiceForAllNamespaces({ - query: {}, - }) - return result - } else { - const result = await client.listCoreV1NamespacedService({ - path: { namespace: ns }, - query: {}, - }) - return result - } - }, - refetchOnMount: 'always', - staleTime: 0, + const allServicesQuery = useListCoreV1ServiceForAllNamespacesQuery({ + query: {}, }) + + const namespacedServicesQuery = useListCoreV1NamespacedServiceQuery({ + path: { namespace: ns }, + query: {}, + }) + + if (ns === '_all') { + return allServicesQuery + } else { + return namespacedServicesQuery + } } export function useService(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = usePreferredNamespace() const ns = namespace || defaultNamespace - return useQuery({ - queryKey: [...SERVICES_KEY, ns, name], - queryFn: async () => { - const result = await client.readCoreV1NamespacedService({ - path: { namespace: ns, name }, - query: {}, - }) - return result - }, - enabled: !!name, - refetchOnMount: 'always', - staleTime: 0, + return useReadCoreV1NamespacedServiceQuery({ + path: { namespace: ns, name }, + query: {}, }) } export function useCreateService() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ service, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.createCoreV1NamespacedService({ - path: { namespace: ns }, - query: {}, - body: service, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SERVICES_KEY, ns] }) - }, - }) + return useCreateCoreV1NamespacedServiceMutation() } export function useUpdateService() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, service, namespace }) => { - const ns = namespace || defaultNamespace - const result = await client.replaceCoreV1NamespacedService({ - path: { namespace: ns, name }, - query: {}, - body: service, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SERVICES_KEY, ns] }) - }, - }) + return useReplaceCoreV1NamespacedServiceMutation() } export function useDeleteService() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: async ({ name, namespace }) => { - const ns = namespace || defaultNamespace - await client.deleteCoreV1NamespacedService({ - path: { namespace: ns, name }, - query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SERVICES_KEY, ns] }) - }, - }) -} \ No newline at end of file + return useDeleteCoreV1NamespacedServiceMutation() +}