From d1ddd0920efe6d59974d1aebea495cb1111a3f89 Mon Sep 17 00:00:00 2001 From: utkarsh patrikar Date: Thu, 11 Jun 2026 16:14:10 +0530 Subject: [PATCH] fix(watch): add responsive layout and dynamic name truncation to Live Dashboard --- src/__tests__/dashboard-utils.test.ts | 20 ++++++++++++++ src/ui/WatchDashboard.tsx | 38 ++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 src/__tests__/dashboard-utils.test.ts diff --git a/src/__tests__/dashboard-utils.test.ts b/src/__tests__/dashboard-utils.test.ts new file mode 100644 index 0000000..002be11 --- /dev/null +++ b/src/__tests__/dashboard-utils.test.ts @@ -0,0 +1,20 @@ +import { describe, it, expect } from 'vitest'; +import { truncateName } from '../ui/WatchDashboard'; + +describe('WatchDashboard utility functions', () => { + describe('truncateName', () => { + it('should return the original name if it is shorter than or equal to maxLength', () => { + expect(truncateName('my-pod', 10)).toBe('my-pod'); + expect(truncateName('my-pod', 6)).toBe('my-pod'); + }); + + it('should truncate and add ellipses if name is longer than maxLength', () => { + expect(truncateName('my-very-long-pod-name', 10)).toBe('my-very...'); + expect(truncateName('some-container-name', 15)).toBe('some-contain...'); + }); + + it('should handle small max lengths gracefully', () => { + expect(truncateName('abcde', 4)).toBe('a...'); + }); + }); +}); diff --git a/src/ui/WatchDashboard.tsx b/src/ui/WatchDashboard.tsx index faf666f..b513e91 100644 --- a/src/ui/WatchDashboard.tsx +++ b/src/ui/WatchDashboard.tsx @@ -17,10 +17,30 @@ const StatusBadge = ({ status, type }: { status: string, type: 'pod' | 'containe ); }; +export const truncateName = (name: string, maxLength: number): string => { + if (name.length <= maxLength) return name; + return name.substring(0, maxLength - 3) + '...'; +}; + export const WatchDashboard = () => { const [pods, setPods] = useState([]); const [containers, setContainers] = useState([]); const [error, setError] = useState<{ type: string; message: string } | null>(null); + const [columns, setColumns] = useState(process.stdout.columns || 80); + + useEffect(() => { + const handleResize = () => { + setColumns(process.stdout.columns || 80); + }; + if (process.stdout && typeof process.stdout.on === 'function') { + process.stdout.on('resize', handleResize); + } + return () => { + if (process.stdout && typeof process.stdout.off === 'function') { + process.stdout.off('resize', handleResize); + } + }; + }, []); useEffect(() => { const fetchPods = async () => { @@ -53,9 +73,15 @@ export const WatchDashboard = () => { return () => clearInterval(interval); }, []); + const isCompact = columns < 80; + const layoutDirection = isCompact ? 'column' : 'row'; + const columnWidth = isCompact ? '100%' : '50%'; + const availableWidth = isCompact ? (columns - 8) : (Math.floor(columns / 2) - 8); + const maxNameLength = Math.max(10, availableWidth - 14); + return ( - + 󱔎 KDM Live Dashboard @@ -70,8 +96,8 @@ export const WatchDashboard = () => { )} - - + + Kubernetes Pods ({pods.length}) @@ -80,14 +106,14 @@ export const WatchDashboard = () => { ) : ( pods.map(p => ( - {p.name.length > 25 ? p.name.substring(0, 22) + '...' : p.name} + {truncateName(p.name, maxNameLength)} )) )} - + Docker Containers ({containers.length}) @@ -96,7 +122,7 @@ export const WatchDashboard = () => { ) : ( containers.map(c => ( - {c.name.length > 25 ? c.name.substring(0, 22) + '...' : c.name} + {truncateName(c.name, maxNameLength)} ))