From f3f903984554be8ee84a2d6d8a0a240c3eda1bf5 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 1 Jun 2025 22:30:25 -0700 Subject: [PATCH] add namespace context and update hooks --- ui/app/providers.tsx | 5 +- ui/components/namespace-switcher.tsx | 4 +- ui/components/resources/pods.tsx | 4 +- ui/components/templates/template-dialog.tsx | 5 +- ui/contexts/KubernetesContext.tsx | 99 --------- ui/contexts/NamespaceContext.tsx | 32 +++ ui/hooks/index.ts | 3 +- ui/hooks/useConfigMaps.ts | 165 +++++++-------- ui/hooks/useDaemonSets.ts | 91 ++++----- ui/hooks/useDeployments.ts | 216 +++++++++----------- ui/hooks/useNamespaces.ts | 96 +++------ ui/hooks/usePods.ts | 123 ++++------- ui/hooks/useReplicaSets.ts | 142 ++++++------- ui/hooks/useSecrets.ts | 165 +++++++-------- ui/hooks/useServices.ts | 165 +++++++-------- ui/package.json | 1 + 16 files changed, 546 insertions(+), 770 deletions(-) delete mode 100644 ui/contexts/KubernetesContext.tsx create mode 100644 ui/contexts/NamespaceContext.tsx diff --git a/ui/app/providers.tsx b/ui/app/providers.tsx index 248a899..7542831 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' +import { NamespaceProvider } from '@/contexts/NamespaceContext' interface ProvidersProps { children: React.ReactNode @@ -9,7 +10,7 @@ interface ProvidersProps { export function Providers({ children }: ProvidersProps) { return ( - {children} + {children} ) } \ No newline at end of file diff --git a/ui/components/namespace-switcher.tsx b/ui/components/namespace-switcher.tsx index d843f48..5256b6b 100644 --- a/ui/components/namespace-switcher.tsx +++ b/ui/components/namespace-switcher.tsx @@ -1,6 +1,6 @@ 'use client' -import { useKubernetes, useNamespaces } from '@/hooks' +import { usePreferredNamespace, useNamespaces } from '@/hooks' import { Select, SelectContent, @@ -13,7 +13,7 @@ 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) || [] diff --git a/ui/components/resources/pods.tsx b/ui/components/resources/pods.tsx index fcbebca..688d377 100644 --- a/ui/components/resources/pods.tsx +++ b/ui/components/resources/pods.tsx @@ -17,7 +17,7 @@ import { 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 @@ -34,7 +34,7 @@ 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() diff --git a/ui/components/templates/template-dialog.tsx b/ui/components/templates/template-dialog.tsx index 2e1432e..6c9620d 100644 --- a/ui/components/templates/template-dialog.tsx +++ b/ui/components/templates/template-dialog.tsx @@ -15,7 +15,7 @@ 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 { useKubernetes, usePreferredNamespace } from '@/hooks' interface Template { id: string @@ -36,7 +36,8 @@ interface TemplateDialogProps { } export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogProps) { - const { client: k8sClient, namespace: contextNamespace } = useKubernetes() + const { client: k8sClient } = useKubernetes() + const { namespace: contextNamespace } = usePreferredNamespace() // Deploy template function const deployTemplate = async (params: { 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..6b7aab5 --- /dev/null +++ b/ui/contexts/NamespaceContext.tsx @@ -0,0 +1,32 @@ +'use client' + +import React, { createContext, useContext, useState } from 'react' + +interface NamespaceContextValue { + namespace: string + setNamespace: (namespace: string) => void +} + +const NamespaceContext = createContext(undefined) + +interface NamespaceProviderProps { + children: React.ReactNode + initialNamespace?: string +} + +export function NamespaceProvider({ children, initialNamespace = 'default' }: NamespaceProviderProps) { + const [namespace, setNamespace] = useState(initialNamespace) + return ( + + {children} + + ) +} + +export function usePreferredNamespace(): NamespaceContextValue { + 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..8177638 100644 --- a/ui/hooks/index.ts +++ b/ui/hooks/index.ts @@ -9,4 +9,5 @@ export * from './useDaemonSets' export * from './useReplicaSets' // Re-export context hook -export { useKubernetes } from '../contexts/KubernetesContext' \ No newline at end of file +export { useKubernetes } from '@kubernetesjs/react' +export { usePreferredNamespace } from '../contexts/NamespaceContext' diff --git a/ui/hooks/useConfigMaps.ts b/ui/hooks/useConfigMaps.ts index 927cf20..e6b3e01 100644 --- a/ui/hooks/useConfigMaps.ts +++ b/ui/hooks/useConfigMaps.ts @@ -1,111 +1,100 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { ConfigMap, ConfigMapList } from 'kubernetesjs' - -// Query keys -const CONFIGMAPS_KEY = ['configmaps'] as const +import { + useListCoreV1ConfigMapForAllNamespacesQuery, + useListCoreV1NamespacedConfigMapQuery, + useReadCoreV1NamespacedConfigMapQuery, + useCreateCoreV1NamespacedConfigMap, + useReplaceCoreV1NamespacedConfigMap, + useDeleteCoreV1NamespacedConfigMap +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' +import type { ConfigMap } from 'kubernetesjs' 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, - }) + 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 } = 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useCreateCoreV1NamespacedConfigMap() + return { + ...mutation, + mutate: ({ configMap, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + }, + query: {}, + body: configMap, + }), + mutateAsync: ({ configMap, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + }, query: {}, body: configMap, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...CONFIGMAPS_KEY, ns] }) - }, - }) + }), + } } 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useReplaceCoreV1NamespacedConfigMap() + return { + ...mutation, + mutate: ({ name, configMap, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + body: configMap, + }), + mutateAsync: ({ name, configMap, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, body: configMap, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...CONFIGMAPS_KEY, ns] }) - }, - }) + }), + } } 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useDeleteCoreV1NamespacedConfigMap() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...CONFIGMAPS_KEY, ns] }) - }, - }) + }), + } } \ No newline at end of file diff --git a/ui/hooks/useDaemonSets.ts b/ui/hooks/useDaemonSets.ts index 6c473f7..f82e85b 100644 --- a/ui/hooks/useDaemonSets.ts +++ b/ui/hooks/useDaemonSets.ts @@ -1,69 +1,48 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { DaemonSet, DaemonSetList } from 'kubernetesjs' - -// Query keys -const DAEMONSETS_KEY = ['daemonsets'] as const +import { + useListAppsV1DaemonSetForAllNamespacesQuery, + useListAppsV1NamespacedDaemonSetQuery, + useReadAppsV1NamespacedDaemonSetQuery, + useDeleteAppsV1NamespacedDaemonSet +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' +import type { DaemonSet } from 'kubernetesjs' 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, - }) + 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 } = 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useDeleteAppsV1NamespacedDaemonSet() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DAEMONSETS_KEY, ns] }) - }, - }) + }), + } } diff --git a/ui/hooks/useDeployments.ts b/ui/hooks/useDeployments.ts index e939acf..353fd99 100644 --- a/ui/hooks/useDeployments.ts +++ b/ui/hooks/useDeployments.ts @@ -1,145 +1,127 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Deployment, DeploymentList } from 'kubernetesjs' - -// Query keys -const DEPLOYMENTS_KEY = ['deployments'] as const +import { + useListAppsV1DeploymentForAllNamespacesQuery, + useListAppsV1NamespacedDeploymentQuery, + useReadAppsV1NamespacedDeploymentQuery, + useCreateAppsV1NamespacedDeployment, + useReplaceAppsV1NamespacedDeployment, + useDeleteAppsV1NamespacedDeployment, + useReplaceAppsV1NamespacedDeploymentScale +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' +import type { Deployment } from 'kubernetesjs' 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, - }) + 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 } = 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useCreateAppsV1NamespacedDeployment() + return { + ...mutation, + mutate: ({ deployment, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + }, query: {}, body: deployment, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) + }), + mutateAsync: ({ deployment, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useReplaceAppsV1NamespacedDeployment() + return { + ...mutation, + mutate: ({ name, deployment, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, body: deployment, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) + }), + mutateAsync: ({ name, deployment, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useDeleteAppsV1NamespacedDeployment() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...DEPLOYMENTS_KEY, ns] }) - }, - }) + }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : 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 } = usePreferredNamespace() + const mutation = useReplaceAppsV1NamespacedDeploymentScale() + return { + ...mutation, + mutate: ({ name, replicas, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : 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 === '_all' ? 'default' : 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..241d7d5 100644 --- a/ui/hooks/usePods.ts +++ b/ui/hooks/usePods.ts @@ -1,103 +1,70 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Pod, PodList } from 'kubernetesjs' - -// Query keys -const PODS_KEY = ['pods'] as const +import { + useListPodsQuery, + useListCoreV1NamespacedPodQuery, + useReadCoreV1NamespacedPodQuery, + useReadCoreV1NamespacedPodLogQuery, + useDeleteCoreV1NamespacedPod +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' +import type { Pod } from 'kubernetesjs' 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, - }) + 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 } = 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useDeleteCoreV1NamespacedPod() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...PODS_KEY, ns] }) - }, - }) + }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + }), + } } 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..31a4ae5 100644 --- a/ui/hooks/useReplicaSets.ts +++ b/ui/hooks/useReplicaSets.ts @@ -1,103 +1,75 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { ReplicaSet, ReplicaSetList } from 'kubernetesjs' - -// Query keys -const REPLICASETS_KEY = ['replicasets'] as const +import { + useListAppsV1ReplicaSetForAllNamespacesQuery, + useListAppsV1NamespacedReplicaSetQuery, + useReadAppsV1NamespacedReplicaSetQuery, + useDeleteAppsV1NamespacedReplicaSet, + useReplaceAppsV1NamespacedReplicaSetScale +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' +import type { ReplicaSet } from 'kubernetesjs' 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, - }) + 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 } = 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useDeleteAppsV1NamespacedReplicaSet() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...REPLICASETS_KEY, ns] }) - }, - }) + }), + } } 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useReplaceAppsV1NamespacedReplicaSetScale() + return { + ...mutation, + mutate: ({ name, replicas, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - - // Update the replicas - if (replicaSet.spec) { - replicaSet.spec.replicas = replicas - } - - // Update the replicaset - const result = await client.replaceAppsV1NamespacedReplicaSet({ - path: { namespace: ns, name }, + body: { spec: { replicas } }, + }), + mutateAsync: ({ name, replicas, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - body: replicaSet, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...REPLICASETS_KEY, ns] }) - }, - }) + body: { spec: { replicas } }, + }), + } } diff --git a/ui/hooks/useSecrets.ts b/ui/hooks/useSecrets.ts index 2cca9ee..3acd45b 100644 --- a/ui/hooks/useSecrets.ts +++ b/ui/hooks/useSecrets.ts @@ -1,111 +1,100 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Secret, SecretList } from 'kubernetesjs' - -// Query keys -const SECRETS_KEY = ['secrets'] as const +import { + useListCoreV1SecretForAllNamespacesQuery, + useListCoreV1NamespacedSecretQuery, + useReadCoreV1NamespacedSecretQuery, + useCreateCoreV1NamespacedSecret, + useReplaceCoreV1NamespacedSecret, + useDeleteCoreV1NamespacedSecret +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' +import type { Secret } from 'kubernetesjs' 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, - }) + 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 } = 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useCreateCoreV1NamespacedSecret() + return { + ...mutation, + mutate: ({ secret, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + }, + query: {}, + body: secret, + }), + mutateAsync: ({ secret, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + }, query: {}, body: secret, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SECRETS_KEY, ns] }) - }, - }) + }), + } } 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useReplaceCoreV1NamespacedSecret() + return { + ...mutation, + mutate: ({ name, secret, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + body: secret, + }), + mutateAsync: ({ name, secret, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, body: secret, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SECRETS_KEY, ns] }) - }, - }) + }), + } } 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useDeleteCoreV1NamespacedSecret() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SECRETS_KEY, ns] }) - }, - }) + }), + } } \ No newline at end of file diff --git a/ui/hooks/useServices.ts b/ui/hooks/useServices.ts index a7be032..c7574a1 100644 --- a/ui/hooks/useServices.ts +++ b/ui/hooks/useServices.ts @@ -1,111 +1,100 @@ -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' -import { useKubernetes } from '../contexts/KubernetesContext' -import type { Service, ServiceList } from 'kubernetesjs' - -// Query keys -const SERVICES_KEY = ['services'] as const +import { + useListCoreV1ServiceForAllNamespacesQuery, + useListCoreV1NamespacedServiceQuery, + useReadCoreV1NamespacedServiceQuery, + useCreateCoreV1NamespacedService, + useReplaceCoreV1NamespacedService, + useDeleteCoreV1NamespacedService +} from '@kubernetesjs/react' +import { usePreferredNamespace } from '../contexts/NamespaceContext' +import type { Service } from 'kubernetesjs' 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, - }) + 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 } = 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useCreateCoreV1NamespacedService() + return { + ...mutation, + mutate: ({ service, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + }, + query: {}, + body: service, + }), + mutateAsync: ({ service, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + }, query: {}, body: service, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SERVICES_KEY, ns] }) - }, - }) + }), + } } 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useReplaceCoreV1NamespacedService() + return { + ...mutation, + mutate: ({ name, service, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + body: service, + }), + mutateAsync: ({ name, service, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, body: service, - }) - return result - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SERVICES_KEY, ns] }) - }, - }) + }), + } } 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 }, + const { namespace: defaultNamespace } = usePreferredNamespace() + const mutation = useDeleteCoreV1NamespacedService() + return { + ...mutation, + mutate: ({ name, namespace }) => + mutation.mutate({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, + query: {}, + }), + mutateAsync: ({ name, namespace }) => + mutation.mutateAsync({ + path: { + namespace: namespace || (defaultNamespace === '_all' ? 'default' : defaultNamespace), + name, + }, query: {}, - }) - }, - onSuccess: (_, variables) => { - const ns = variables.namespace || defaultNamespace - queryClient.invalidateQueries({ queryKey: [...SERVICES_KEY, ns] }) - }, - }) + }), + } } \ 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",