Skip to content

Commit 82551a2

Browse files
Migrate UI hooks to @kubernetesjs/react and implement namespace context
- Created NamespaceContext.tsx with usePreferredNamespace() hook - Updated providers.tsx to use KubernetesProvider and NamespaceProvider - Migrated all hooks in ui/hooks/* to use generated React Query hooks - Implemented _all namespace logic for cluster-wide queries - Preserved existing hook signatures for backward compatibility - Updated components to use new namespace context - Removed old KubernetesContext.tsx Co-Authored-By: Dan Lynch <[email protected]>
1 parent cf4a56f commit 82551a2

17 files changed

+377
-808
lines changed

ui/app/providers.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client'
22

3-
import { KubernetesProvider } from '@/contexts/KubernetesContext'
3+
import { KubernetesProvider } from '@kubernetesjs/react/context'
4+
import { NamespaceProvider } from '@/contexts/NamespaceContext'
45

56
interface ProvidersProps {
67
children: React.ReactNode
@@ -9,7 +10,9 @@ interface ProvidersProps {
910
export function Providers({ children }: ProvidersProps) {
1011
return (
1112
<KubernetesProvider>
12-
{children}
13+
<NamespaceProvider>
14+
{children}
15+
</NamespaceProvider>
1316
</KubernetesProvider>
1417
)
15-
}
18+
}

ui/components/dashboard-layout.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Link from 'next/link'
55
import { usePathname } from 'next/navigation'
66
import { Button } from '@/components/ui/button'
77
import { NamespaceSwitcher } from '@/components/namespace-switcher'
8-
import { useKubernetes } from '@/hooks'
8+
import { usePreferredNamespace } from '@/hooks'
99
import {
1010
Package,
1111
Server,
@@ -38,7 +38,7 @@ interface DashboardLayoutProps {
3838
export function DashboardLayout({ children }: DashboardLayoutProps) {
3939
const [sidebarOpen, setSidebarOpen] = useState(true)
4040
const pathname = usePathname()
41-
const { config } = useKubernetes()
41+
const { namespace } = usePreferredNamespace()
4242

4343
// Find active section based on pathname
4444
const activeSection = navigationItems.find(item => item.href === pathname)?.label || 'Overview'
@@ -87,7 +87,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
8787
</h2>
8888
</div>
8989
<div className="flex items-center space-x-4">
90-
<span className="text-sm text-muted-foreground">Cluster: {config.restEndpoint}</span>
90+
<span className="text-sm text-muted-foreground">Namespace: {namespace}</span>
9191
<NamespaceSwitcher />
9292
</div>
9393
</header>
@@ -99,4 +99,4 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
9999
</div>
100100
</div>
101101
)
102-
}
102+
}

ui/components/namespace-switcher.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client'
22

3-
import { useKubernetes, useNamespaces } from '@/hooks'
3+
import { useNamespaces } from '@/hooks'
4+
import { usePreferredNamespace } from '../contexts/NamespaceContext'
45
import {
56
Select,
67
SelectContent,
@@ -13,10 +14,10 @@ import { RefreshCw } from 'lucide-react'
1314
import { Button } from '@/components/ui/button'
1415

1516
export function NamespaceSwitcher() {
16-
const { namespace, setNamespace } = useKubernetes()
17+
const { namespace, setNamespace } = usePreferredNamespace()
1718
const { data, isLoading, error, refetch } = useNamespaces()
1819

19-
const namespaces = data?.items?.map(item => item.metadata?.name).filter(Boolean) || []
20+
const namespaces = data?.items?.map((item: any) => item.metadata?.name).filter(Boolean) || []
2021

2122
return (
2223
<div className="flex items-center gap-2">
@@ -33,22 +34,22 @@ export function NamespaceSwitcher() {
3334
<SelectItem value="_all">
3435
<div className="flex items-center gap-2">
3536
All Namespaces
36-
<Badge variant="outline" className="text-xs">
37+
<Badge variant="default" className="text-xs">
3738
All
3839
</Badge>
3940
</div>
4041
</SelectItem>
41-
{namespaces.map((ns) => (
42+
{namespaces.map((ns: any) => (
4243
<SelectItem key={ns} value={ns!}>
4344
<div className="flex items-center gap-2">
4445
{ns}
4546
{ns === 'default' && (
46-
<Badge variant="secondary" className="text-xs">
47+
<Badge variant="default" className="text-xs">
4748
Default
4849
</Badge>
4950
)}
5051
{(ns === 'kube-system' || ns === 'kube-public') && (
51-
<Badge variant="outline" className="text-xs">
52+
<Badge variant="default" className="text-xs">
5253
System
5354
</Badge>
5455
)}
@@ -68,4 +69,4 @@ export function NamespaceSwitcher() {
6869
</Button>
6970
</div>
7071
)
71-
}
72+
}

ui/components/resources/pods.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import {
1616
Clock,
1717
XCircle
1818
} from 'lucide-react'
19-
import { type Pod as K8sPod } from 'kubernetesjs'
20-
import { usePods, useDeletePod, usePodLogs, useKubernetes } from '@/hooks'
19+
20+
import { usePods, useDeletePod, usePodLogs, usePreferredNamespace } from '@/hooks'
2121

2222
interface Pod {
2323
name: string
@@ -27,19 +27,19 @@ interface Pod {
2727
restarts: number
2828
age: string
2929
nodeName: string
30-
k8sData?: K8sPod
30+
k8sData?: any
3131
}
3232

3333
export function PodsView() {
3434
const [selectedPod, setSelectedPod] = useState<Pod | null>(null)
3535

3636
// Use TanStack Query hooks
37-
const { namespace } = useKubernetes()
37+
const { namespace } = usePreferredNamespace()
3838
const { data, isLoading, error, refetch } = usePods()
3939
const deletePodMutation = useDeletePod()
4040

4141
// Helper function to determine pod status
42-
function determinePodStatus(pod: K8sPod): Pod['status'] {
42+
function determinePodStatus(pod: any): Pod['status'] {
4343
const phase = pod.status?.phase
4444
if (phase === 'Running') return 'Running'
4545
if (phase === 'Pending') return 'Pending'
@@ -49,11 +49,11 @@ export function PodsView() {
4949
}
5050

5151
// Format pods from query data
52-
const pods: Pod[] = data?.items?.map(item => {
52+
const pods: Pod[] = data?.items?.map((item: any) => {
5353
const containerStatuses = item.status?.containerStatuses || []
54-
const readyContainers = containerStatuses.filter(cs => cs.ready).length
54+
const readyContainers = containerStatuses.filter((cs: any) => cs.ready).length
5555
const totalContainers = containerStatuses.length
56-
const totalRestarts = containerStatuses.reduce((sum, cs) => sum + (cs.restartCount || 0), 0)
56+
const totalRestarts = containerStatuses.reduce((sum: number, cs: any) => sum + (cs.restartCount || 0), 0)
5757

5858
return {
5959
name: item.metadata!.name!,
@@ -93,27 +93,27 @@ export function PodsView() {
9393
const getStatusBadge = (status: Pod['status']) => {
9494
switch (status) {
9595
case 'Running':
96-
return <Badge variant="success" className="flex items-center gap-1">
96+
return <Badge variant="default" className="flex items-center gap-1 bg-green-100 text-green-800">
9797
<CheckCircle className="w-3 h-3" />
9898
{status}
9999
</Badge>
100100
case 'Pending':
101-
return <Badge variant="warning" className="flex items-center gap-1">
101+
return <Badge variant="default" className="flex items-center gap-1 bg-yellow-100 text-yellow-800">
102102
<Clock className="w-3 h-3" />
103103
{status}
104104
</Badge>
105105
case 'Failed':
106-
return <Badge variant="destructive" className="flex items-center gap-1">
106+
return <Badge variant="default" className="flex items-center gap-1 bg-red-100 text-red-800">
107107
<XCircle className="w-3 h-3" />
108108
{status}
109109
</Badge>
110110
case 'Succeeded':
111-
return <Badge variant="secondary" className="flex items-center gap-1">
111+
return <Badge variant="default" className="flex items-center gap-1 bg-blue-100 text-blue-800">
112112
<CheckCircle className="w-3 h-3" />
113113
{status}
114114
</Badge>
115115
default:
116-
return <Badge variant="outline">{status}</Badge>
116+
return <Badge variant="default">{status}</Badge>
117117
}
118118
}
119119

ui/components/templates/template-dialog.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ import { Input } from '@/components/ui/input'
1414
import { Label } from '@/components/ui/label'
1515
import { Alert, AlertDescription } from '@/components/ui/alert'
1616
import { Loader2, CheckCircle, XCircle } from 'lucide-react'
17-
import { type Deployment, type Service } from 'kubernetesjs'
18-
import { useKubernetes } from '@/hooks'
17+
18+
import { usePreferredNamespace } from '@/hooks'
19+
import { useCreateAppsV1NamespacedDeploymentMutation, useCreateCoreV1NamespacedServiceMutation } from '@kubernetesjs/react'
1920

2021
interface Template {
2122
id: string
2223
name: string
2324
description: string
24-
icon: React.ComponentType<{ className?: string }>
25+
icon: any
2526
details: {
2627
image: string
2728
ports: number[]
@@ -36,7 +37,9 @@ interface TemplateDialogProps {
3637
}
3738

3839
export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogProps) {
39-
const { client: k8sClient, namespace: contextNamespace } = useKubernetes()
40+
const { namespace: contextNamespace } = usePreferredNamespace()
41+
const createDeployment = useCreateAppsV1NamespacedDeploymentMutation()
42+
const createService = useCreateCoreV1NamespacedServiceMutation()
4043

4144
// Deploy template function
4245
const deployTemplate = async (params: {
@@ -50,7 +53,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
5053
const { templateId, name, namespace, image, ports, environment } = params
5154

5255
// Create deployment configuration
53-
const deployment: Deployment = {
56+
const deployment = {
5457
apiVersion: 'apps/v1',
5558
kind: 'Deployment',
5659
metadata: {
@@ -88,11 +91,13 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
8891

8992
// Handle specific args for minio
9093
if (templateId === 'minio') {
91-
deployment.spec!.template.spec!.containers[0].args = ['server', '/data']
94+
if (deployment.spec?.template?.spec?.containers?.[0]) {
95+
(deployment.spec.template.spec.containers[0] as any).args = ['server', '/data']
96+
}
9297
}
9398

9499
// Create service configuration
95-
const service: Service = {
100+
const service = {
96101
apiVersion: 'v1',
97102
kind: 'Service',
98103
metadata: {
@@ -117,14 +122,14 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
117122
}
118123

119124
// Create deployment first using typed client
120-
await k8sClient.createAppsV1NamespacedDeployment({
125+
await createDeployment.mutateAsync({
121126
path: { namespace },
122127
query: {},
123128
body: deployment,
124129
})
125130

126131
// Then create service using typed client
127-
await k8sClient.createCoreV1NamespacedService({
132+
await createService.mutateAsync({
128133
path: { namespace },
129134
query: {},
130135
body: service,
@@ -205,7 +210,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
205210
<Input
206211
id="name"
207212
value={deploymentName}
208-
onChange={(e) => setDeploymentName(e.target.value)}
213+
onChange={(e: any) => setDeploymentName(e.target.value)}
209214
className="col-span-3"
210215
disabled={isDeploying}
211216
/>
@@ -218,7 +223,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
218223
<Input
219224
id="namespace"
220225
value={namespace}
221-
onChange={(e) => setNamespace(e.target.value)}
226+
onChange={(e: any) => setNamespace(e.target.value)}
222227
className="col-span-3"
223228
disabled={isDeploying}
224229
/>
@@ -290,4 +295,4 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
290295
</DialogContent>
291296
</Dialog>
292297
)
293-
}
298+
}

ui/contexts/KubernetesContext.tsx

Lines changed: 0 additions & 99 deletions
This file was deleted.

0 commit comments

Comments
 (0)