Skip to content

Migrate UI Hooks to @kubernetesjs/react and Implement Namespace Context #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions ui/app/providers.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
'use client'

import { KubernetesProvider } from '@/contexts/KubernetesContext'
import { KubernetesProvider } from '@kubernetesjs/react/context'
import { NamespaceProvider } from '@/contexts/NamespaceContext'

interface ProvidersProps {
children: React.ReactNode
}

export function Providers({ children }: ProvidersProps) {
return (
<KubernetesProvider>
{children}
<KubernetesProvider
initialConfig={{
restEndpoint: 'http://localhost:8001'
}}
>
<NamespaceProvider>
{children}
</NamespaceProvider>
</KubernetesProvider>
)
}
}
8 changes: 4 additions & 4 deletions ui/components/dashboard-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { Button } from '@/components/ui/button'
import { NamespaceSwitcher } from '@/components/namespace-switcher'
import { useKubernetes } from '@/hooks'
import { usePreferredNamespace } from '@/hooks'
import {
Package,
Server,
Expand Down Expand Up @@ -38,7 +38,7 @@ interface DashboardLayoutProps {
export function DashboardLayout({ children }: DashboardLayoutProps) {
const [sidebarOpen, setSidebarOpen] = useState(true)
const pathname = usePathname()
const { config } = useKubernetes()
const { namespace } = usePreferredNamespace()

// Find active section based on pathname
const activeSection = navigationItems.find(item => item.href === pathname)?.label || 'Overview'
Expand Down Expand Up @@ -87,7 +87,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
</h2>
</div>
<div className="flex items-center space-x-4">
<span className="text-sm text-muted-foreground">Cluster: {config.restEndpoint}</span>
<span className="text-sm text-muted-foreground">Namespace: {namespace}</span>
<NamespaceSwitcher />
</div>
</header>
Expand All @@ -99,4 +99,4 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
</div>
</div>
)
}
}
17 changes: 9 additions & 8 deletions ui/components/namespace-switcher.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client'

import { useKubernetes, useNamespaces } from '@/hooks'
import { useNamespaces } from '@/hooks'
import { usePreferredNamespace } from '../contexts/NamespaceContext'
import {
Select,
SelectContent,
Expand All @@ -13,10 +14,10 @@ import { RefreshCw } from 'lucide-react'
import { Button } from '@/components/ui/button'

export function NamespaceSwitcher() {
const { namespace, setNamespace } = useKubernetes()
const { namespace, setNamespace } = usePreferredNamespace()
const { data, isLoading, error, refetch } = useNamespaces()

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

return (
<div className="flex items-center gap-2">
Expand All @@ -33,22 +34,22 @@ export function NamespaceSwitcher() {
<SelectItem value="_all">
<div className="flex items-center gap-2">
All Namespaces
<Badge variant="outline" className="text-xs">
<Badge variant="default" className="text-xs">
All
</Badge>
</div>
</SelectItem>
{namespaces.map((ns) => (
{namespaces.map((ns: any) => (
<SelectItem key={ns} value={ns!}>
<div className="flex items-center gap-2">
{ns}
{ns === 'default' && (
<Badge variant="secondary" className="text-xs">
<Badge variant="default" className="text-xs">
Default
</Badge>
)}
{(ns === 'kube-system' || ns === 'kube-public') && (
<Badge variant="outline" className="text-xs">
<Badge variant="default" className="text-xs">
System
</Badge>
)}
Expand All @@ -68,4 +69,4 @@ export function NamespaceSwitcher() {
</Button>
</div>
)
}
}
26 changes: 13 additions & 13 deletions ui/components/resources/pods.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import {
Clock,
XCircle
} from 'lucide-react'
import { type Pod as K8sPod } from 'kubernetesjs'
import { usePods, useDeletePod, usePodLogs, useKubernetes } from '@/hooks'

import { usePods, useDeletePod, usePodLogs, usePreferredNamespace } from '@/hooks'

interface Pod {
name: string
Expand All @@ -27,19 +27,19 @@ interface Pod {
restarts: number
age: string
nodeName: string
k8sData?: K8sPod
k8sData?: any
}

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

// Use TanStack Query hooks
const { namespace } = useKubernetes()
const { namespace } = usePreferredNamespace()
const { data, isLoading, error, refetch } = usePods()
const deletePodMutation = useDeletePod()

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

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

return {
name: item.metadata!.name!,
Expand Down Expand Up @@ -93,27 +93,27 @@ export function PodsView() {
const getStatusBadge = (status: Pod['status']) => {
switch (status) {
case 'Running':
return <Badge variant="success" className="flex items-center gap-1">
return <Badge variant="default" className="flex items-center gap-1 bg-green-100 text-green-800">
<CheckCircle className="w-3 h-3" />
{status}
</Badge>
case 'Pending':
return <Badge variant="warning" className="flex items-center gap-1">
return <Badge variant="default" className="flex items-center gap-1 bg-yellow-100 text-yellow-800">
<Clock className="w-3 h-3" />
{status}
</Badge>
case 'Failed':
return <Badge variant="destructive" className="flex items-center gap-1">
return <Badge variant="default" className="flex items-center gap-1 bg-red-100 text-red-800">
<XCircle className="w-3 h-3" />
{status}
</Badge>
case 'Succeeded':
return <Badge variant="secondary" className="flex items-center gap-1">
return <Badge variant="default" className="flex items-center gap-1 bg-blue-100 text-blue-800">
<CheckCircle className="w-3 h-3" />
{status}
</Badge>
default:
return <Badge variant="outline">{status}</Badge>
return <Badge variant="default">{status}</Badge>
}
}

Expand Down
29 changes: 17 additions & 12 deletions ui/components/templates/template-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Loader2, CheckCircle, XCircle } from 'lucide-react'
import { type Deployment, type Service } from 'kubernetesjs'
import { useKubernetes } from '@/hooks'

import { usePreferredNamespace } from '@/hooks'
import { useCreateAppsV1NamespacedDeploymentMutation, useCreateCoreV1NamespacedServiceMutation } from '@kubernetesjs/react'

interface Template {
id: string
name: string
description: string
icon: React.ComponentType<{ className?: string }>
icon: any
details: {
image: string
ports: number[]
Expand All @@ -36,7 +37,9 @@ interface TemplateDialogProps {
}

export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogProps) {
const { client: k8sClient, namespace: contextNamespace } = useKubernetes()
const { namespace: contextNamespace } = usePreferredNamespace()
const createDeployment = useCreateAppsV1NamespacedDeploymentMutation()
const createService = useCreateCoreV1NamespacedServiceMutation()

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

// Create deployment configuration
const deployment: Deployment = {
const deployment = {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
Expand Down Expand Up @@ -88,11 +91,13 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP

// Handle specific args for minio
if (templateId === 'minio') {
deployment.spec!.template.spec!.containers[0].args = ['server', '/data']
if (deployment.spec?.template?.spec?.containers?.[0]) {
(deployment.spec.template.spec.containers[0] as any).args = ['server', '/data']
}
}

// Create service configuration
const service: Service = {
const service = {
apiVersion: 'v1',
kind: 'Service',
metadata: {
Expand All @@ -117,14 +122,14 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
}

// Create deployment first using typed client
await k8sClient.createAppsV1NamespacedDeployment({
await createDeployment.mutateAsync({
path: { namespace },
query: {},
body: deployment,
})

// Then create service using typed client
await k8sClient.createCoreV1NamespacedService({
await createService.mutateAsync({
path: { namespace },
query: {},
body: service,
Expand Down Expand Up @@ -205,7 +210,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
<Input
id="name"
value={deploymentName}
onChange={(e) => setDeploymentName(e.target.value)}
onChange={(e: any) => setDeploymentName(e.target.value)}
className="col-span-3"
disabled={isDeploying}
/>
Expand All @@ -218,7 +223,7 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
<Input
id="namespace"
value={namespace}
onChange={(e) => setNamespace(e.target.value)}
onChange={(e: any) => setNamespace(e.target.value)}
className="col-span-3"
disabled={isDeploying}
/>
Expand Down Expand Up @@ -290,4 +295,4 @@ export function TemplateDialog({ template, open, onOpenChange }: TemplateDialogP
</DialogContent>
</Dialog>
)
}
}
99 changes: 0 additions & 99 deletions ui/contexts/KubernetesContext.tsx

This file was deleted.

Loading