From ac2aea7867f44e1dc9e0e720b3d072d38aab2909 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 1 Jun 2025 22:22:17 -0700 Subject: [PATCH] refactor(ui): delegate hooks to kubernetesjs react --- ui/contexts/KubernetesContext.tsx | 86 +++++++------- ui/hooks/index.ts | 2 +- ui/hooks/useConfigMaps.ts | 135 +++++++--------------- ui/hooks/useDaemonSets.ts | 79 ++++--------- ui/hooks/useDeployments.ts | 180 ++++++++++-------------------- ui/hooks/useNamespaces.ts | 96 ++++++---------- ui/hooks/usePods.ts | 111 ++++++------------ ui/hooks/useReplicaSets.ts | 120 ++++++-------------- ui/hooks/useSecrets.ts | 135 +++++++--------------- ui/hooks/useServices.ts | 135 +++++++--------------- ui/package.json | 1 + 11 files changed, 352 insertions(+), 728 deletions(-) diff --git a/ui/contexts/KubernetesContext.tsx b/ui/contexts/KubernetesContext.tsx index 9d7fb9e..e5b91f1 100644 --- a/ui/contexts/KubernetesContext.tsx +++ b/ui/contexts/KubernetesContext.tsx @@ -1,8 +1,12 @@ 'use client' -import React, { createContext, useContext, useMemo, useState } from 'react' +import React, { createContext, useContext, useState } from 'react' +import { + KubernetesProvider as BaseKubernetesProvider, + useKubernetes as useBaseKubernetes, + queryClient +} from '@kubernetesjs/react' import { KubernetesClient } from 'kubernetesjs' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' // Configuration types export interface KubernetesConfig { @@ -23,17 +27,7 @@ interface KubernetesContextValue { // 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 { @@ -42,48 +36,46 @@ interface KubernetesProviderProps { } // 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) +export function KubernetesProvider({ children, initialConfig }: KubernetesProviderProps) { + const [namespace, setNamespace] = useState(initialConfig?.namespace || 'default') + + return ( + + {children} + + ) +} + +interface InnerProviderProps { + children: React.ReactNode + namespace: string + setNamespace: (namespace: string) => void +} + +function InnerProvider({ children, namespace, setNamespace }: InnerProviderProps) { + const base = useBaseKubernetes() + + const updateConfig = (config: Partial) => { + base.updateConfig(config) + if (config.namespace) { + setNamespace(config.namespace) } } const contextValue: KubernetesContextValue = { - client, - config, + client: base.client as KubernetesClient, + config: { ...base.config, namespace }, namespace, setNamespace, updateConfig, } - return ( - - - {children} - - - ) + return {children} } // Hook to use Kubernetes context @@ -96,4 +88,4 @@ export function useKubernetes() { } // Export query client for use in hooks -export { queryClient } \ No newline at end of file +export { queryClient } diff --git a/ui/hooks/index.ts b/ui/hooks/index.ts index c1f70e3..59b66de 100644 --- a/ui/hooks/index.ts +++ b/ui/hooks/index.ts @@ -9,4 +9,4 @@ export * from './useDaemonSets' export * from './useReplicaSets' // Re-export context hook -export { useKubernetes } from '../contexts/KubernetesContext' \ No newline at end of file +export { useKubernetes } from '../contexts/KubernetesContext' diff --git a/ui/hooks/useConfigMaps.ts b/ui/hooks/useConfigMaps.ts index 927cf20..52c76a2 100644 --- a/ui/hooks/useConfigMaps.ts +++ b/ui/hooks/useConfigMaps.ts @@ -1,111 +1,62 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { + useListCoreV1ConfigMapForAllNamespacesQuery, + useListCoreV1NamespacedConfigMapQuery, + useReadCoreV1NamespacedConfigMapQuery, + useCreateCoreV1NamespacedConfigMap, + useReplaceCoreV1NamespacedConfigMap, + useDeleteCoreV1NamespacedConfigMap +} from '@kubernetesjs/react' import { useKubernetes } from '../contexts/KubernetesContext' -import type { ConfigMap, ConfigMapList } from 'kubernetesjs' - -// Query keys -const CONFIGMAPS_KEY = ['configmaps'] as const +import type { ConfigMap } from 'kubernetesjs' export function useConfigMaps(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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, - }) + if (ns === '_all') { + return useListCoreV1ConfigMapForAllNamespacesQuery({ query: {} }) + } + return useListCoreV1NamespacedConfigMapQuery({ path: { namespace: ns }, query: {} }) } export function useConfigMap(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useCreateCoreV1NamespacedConfigMap() + return { + ...mutation, + mutate: ({ configMap, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace }, query: {}, body: configMap }), + mutateAsync: ({ configMap, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace }, query: {}, body: configMap }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useReplaceCoreV1NamespacedConfigMap() + return { + ...mutation, + mutate: ({ name, configMap, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: configMap }), + mutateAsync: ({ name, configMap, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: configMap }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useDeleteCoreV1NamespacedConfigMap() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + } } \ No newline at end of file diff --git a/ui/hooks/useDaemonSets.ts b/ui/hooks/useDaemonSets.ts index 6c473f7..aba8207 100644 --- a/ui/hooks/useDaemonSets.ts +++ b/ui/hooks/useDaemonSets.ts @@ -1,69 +1,36 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { + useListAppsV1DaemonSetForAllNamespacesQuery, + useListAppsV1NamespacedDaemonSetQuery, + useReadAppsV1NamespacedDaemonSetQuery, + useDeleteAppsV1NamespacedDaemonSet +} from '@kubernetesjs/react' import { useKubernetes } from '../contexts/KubernetesContext' -import type { DaemonSet, DaemonSetList } from 'kubernetesjs' - -// Query keys -const DAEMONSETS_KEY = ['daemonsets'] as const +import type { DaemonSet } from 'kubernetesjs' export function useDaemonSets(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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, - }) + if (ns === '_all') { + return useListAppsV1DaemonSetForAllNamespacesQuery({ query: {} }) + } + return useListAppsV1NamespacedDaemonSetQuery({ path: { namespace: ns }, query: {} }) } export function useDaemonSet(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useDeleteAppsV1NamespacedDaemonSet() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + } } diff --git a/ui/hooks/useDeployments.ts b/ui/hooks/useDeployments.ts index e939acf..02aa8df 100644 --- a/ui/hooks/useDeployments.ts +++ b/ui/hooks/useDeployments.ts @@ -1,145 +1,83 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { + useListAppsV1DeploymentForAllNamespacesQuery, + useListAppsV1NamespacedDeploymentQuery, + useReadAppsV1NamespacedDeploymentQuery, + useCreateAppsV1NamespacedDeployment, + useReplaceAppsV1NamespacedDeployment, + useDeleteAppsV1NamespacedDeployment, + useReplaceAppsV1NamespacedDeploymentScale +} from '@kubernetesjs/react' import { useKubernetes } from '../contexts/KubernetesContext' -import type { Deployment, DeploymentList } from 'kubernetesjs' - -// Query keys -const DEPLOYMENTS_KEY = ['deployments'] as const +import type { Deployment } from 'kubernetesjs' export function useDeployments(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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, - }) + if (ns === '_all') { + return useListAppsV1DeploymentForAllNamespacesQuery({ query: {} }) + } + return useListAppsV1NamespacedDeploymentQuery({ path: { namespace: ns }, query: {} }) } export function useDeployment(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useCreateAppsV1NamespacedDeployment() + return { + ...mutation, + mutate: ({ deployment, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace }, query: {}, body: deployment }), + mutateAsync: ({ deployment, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace }, query: {}, body: deployment }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useReplaceAppsV1NamespacedDeployment() + return { + ...mutation, + mutate: ({ name, deployment, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: deployment }), + mutateAsync: ({ name, deployment, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: deployment }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useDeleteAppsV1NamespacedDeployment() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + } } export function useScaleDeployment() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - 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 }, + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useReplaceAppsV1NamespacedDeploymentScale() + return { + ...mutation, + mutate: ({ name, replicas, namespace }) => + mutation.mutate({ + path: { namespace: namespace || defaultNamespace, name }, query: {}, - }) - - // Update the replicas - if (deployment.spec) { - deployment.spec.replicas = replicas - } - - // Update the deployment - const result = await client.replaceAppsV1NamespacedDeployment({ - path: { namespace: ns, name }, + body: { spec: { replicas } }, + }), + mutateAsync: ({ name, replicas, namespace }) => + mutation.mutateAsync({ + path: { namespace: namespace || defaultNamespace, name }, query: {}, - body: deployment, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) + body: { spec: { replicas } }, + }), + } } \ No newline at end of file diff --git a/ui/hooks/useNamespaces.ts b/ui/hooks/useNamespaces.ts index 06dd2fa..b59cf08 100644 --- a/ui/hooks/useNamespaces.ts +++ b/ui/hooks/useNamespaces.ts @@ -1,80 +1,52 @@ -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, + useCreateCoreV1Namespace, + useDeleteCoreV1Namespace +} 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({ path: {}, 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({ + const mutation = useCreateCoreV1Namespace() + return { + ...mutation, + mutate: ({ name, labels }) => + mutation.mutate({ path: {}, query: {}, body: { apiVersion: 'v1', kind: 'Namespace', - metadata: { - name, - labels, - }, + metadata: { name, labels }, }, - }) - return result - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: NAMESPACES_KEY }) - }, - }) + }), + mutateAsync: ({ name, labels }) => + mutation.mutateAsync({ + path: {}, + query: {}, + body: { + apiVersion: 'v1', + kind: 'Namespace', + metadata: { name, labels }, + }, + }), + } } 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 }) - }, - }) + const mutation = useDeleteCoreV1Namespace() + return { + ...mutation, + mutate: (name: string) => + mutation.mutate({ path: { name }, query: {} }), + mutateAsync: (name: string) => + mutation.mutateAsync({ path: { name }, query: {} }), + } } \ No newline at end of file diff --git a/ui/hooks/usePods.ts b/ui/hooks/usePods.ts index 3bde486..cb09727 100644 --- a/ui/hooks/usePods.ts +++ b/ui/hooks/usePods.ts @@ -1,103 +1,58 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { + useListPodsQuery, + useListCoreV1NamespacedPodQuery, + useReadCoreV1NamespacedPodQuery, + useReadCoreV1NamespacedPodLogQuery, + useDeleteCoreV1NamespacedPod +} from '@kubernetesjs/react' import { useKubernetes } from '../contexts/KubernetesContext' -import type { Pod, PodList } from 'kubernetesjs' - -// Query keys -const PODS_KEY = ['pods'] as const +import type { Pod } from 'kubernetesjs' export function usePods(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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, - }) + if (ns === '_all') { + return useListPodsQuery({ query: {} }) + } + return useListCoreV1NamespacedPodQuery({ path: { namespace: ns }, query: {} }) } export function usePod(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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 } = useKubernetes() 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useDeleteCoreV1NamespacedPod() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + } } export function usePodsForDeployment(deploymentName: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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..347ec6a 100644 --- a/ui/hooks/useReplicaSets.ts +++ b/ui/hooks/useReplicaSets.ts @@ -1,103 +1,49 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { + useListAppsV1ReplicaSetForAllNamespacesQuery, + useListAppsV1NamespacedReplicaSetQuery, + useReadAppsV1NamespacedReplicaSetQuery, + useDeleteAppsV1NamespacedReplicaSet, + useReplaceAppsV1NamespacedReplicaSetScale +} from '@kubernetesjs/react' import { useKubernetes } from '../contexts/KubernetesContext' -import type { ReplicaSet, ReplicaSetList } from 'kubernetesjs' - -// Query keys -const REPLICASETS_KEY = ['replicasets'] as const +import type { ReplicaSet } from 'kubernetesjs' export function useReplicaSets(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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, - }) + if (ns === '_all') { + return useListAppsV1ReplicaSetForAllNamespacesQuery({ query: {} }) + } + return useListAppsV1NamespacedReplicaSetQuery({ path: { namespace: ns }, query: {} }) } export function useReplicaSet(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useDeleteAppsV1NamespacedReplicaSet() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + } } export function useScaleReplicaSet() { - const { client, namespace: defaultNamespace } = useKubernetes() - const queryClient = useQueryClient() - - 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useReplaceAppsV1NamespacedReplicaSetScale() + return { + ...mutation, + mutate: ({ name, replicas, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: { spec: { replicas } } }), + mutateAsync: ({ name, replicas, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: { spec: { replicas } } }), + } } diff --git a/ui/hooks/useSecrets.ts b/ui/hooks/useSecrets.ts index 2cca9ee..defcb59 100644 --- a/ui/hooks/useSecrets.ts +++ b/ui/hooks/useSecrets.ts @@ -1,111 +1,62 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { + useListCoreV1SecretForAllNamespacesQuery, + useListCoreV1NamespacedSecretQuery, + useReadCoreV1NamespacedSecretQuery, + useCreateCoreV1NamespacedSecret, + useReplaceCoreV1NamespacedSecret, + useDeleteCoreV1NamespacedSecret +} from '@kubernetesjs/react' import { useKubernetes } from '../contexts/KubernetesContext' -import type { Secret, SecretList } from 'kubernetesjs' - -// Query keys -const SECRETS_KEY = ['secrets'] as const +import type { Secret } from 'kubernetesjs' export function useSecrets(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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, - }) + if (ns === '_all') { + return useListCoreV1SecretForAllNamespacesQuery({ query: {} }) + } + return useListCoreV1NamespacedSecretQuery({ path: { namespace: ns }, query: {} }) } export function useSecret(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useCreateCoreV1NamespacedSecret() + return { + ...mutation, + mutate: ({ secret, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace }, query: {}, body: secret }), + mutateAsync: ({ secret, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace }, query: {}, body: secret }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useReplaceCoreV1NamespacedSecret() + return { + ...mutation, + mutate: ({ name, secret, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: secret }), + mutateAsync: ({ name, secret, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: secret }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useDeleteCoreV1NamespacedSecret() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + } } \ No newline at end of file diff --git a/ui/hooks/useServices.ts b/ui/hooks/useServices.ts index a7be032..3c6c1f6 100644 --- a/ui/hooks/useServices.ts +++ b/ui/hooks/useServices.ts @@ -1,111 +1,62 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { + useListCoreV1ServiceForAllNamespacesQuery, + useListCoreV1NamespacedServiceQuery, + useReadCoreV1NamespacedServiceQuery, + useCreateCoreV1NamespacedService, + useReplaceCoreV1NamespacedService, + useDeleteCoreV1NamespacedService +} from '@kubernetesjs/react' import { useKubernetes } from '../contexts/KubernetesContext' -import type { Service, ServiceList } from 'kubernetesjs' - -// Query keys -const SERVICES_KEY = ['services'] as const +import type { Service } from 'kubernetesjs' export function useServices(namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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, - }) + if (ns === '_all') { + return useListCoreV1ServiceForAllNamespacesQuery({ query: {} }) + } + return useListCoreV1NamespacedServiceQuery({ path: { namespace: ns }, query: {} }) } export function useService(name: string, namespace?: string) { - const { client, namespace: defaultNamespace } = useKubernetes() + const { namespace: defaultNamespace } = useKubernetes() 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useCreateCoreV1NamespacedService() + return { + ...mutation, + mutate: ({ service, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace }, query: {}, body: service }), + mutateAsync: ({ service, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace }, query: {}, body: service }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useReplaceCoreV1NamespacedService() + return { + ...mutation, + mutate: ({ name, service, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: service }), + mutateAsync: ({ name, service, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {}, body: service }), + } } 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] }) - }, - }) + const { namespace: defaultNamespace } = useKubernetes() + const mutation = useDeleteCoreV1NamespacedService() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ path: { namespace: namespace || defaultNamespace, name }, query: {} }), + } } \ No newline at end of file diff --git a/ui/package.json b/ui/package.json index 29418da..c58334f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,6 +13,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "kubernetesjs": "^0.6.1", + "@kubernetesjs/react": "workspace:*", "@tanstack/react-query": "^5.29.0", "react-router-dom": "^6.22.3", "@radix-ui/react-dialog": "^1.0.5",