From 872a227190d4c020ae7e210ae6cd3bed833940ad Mon Sep 17 00:00:00 2001 From: Merul Dhiman Date: Mon, 25 Aug 2025 14:02:51 +0530 Subject: [PATCH] fix: control-panel search --- .../src/lib/services/evaultService.ts | 37 ++++++ .../control-panel/src/routes/+page.svelte | 115 ++++++++++-------- .../evaults/[namespace]/[pod]/logs/+server.ts | 43 ++++++- .../[namespace]/[service]/+page.svelte | 48 ++++++++ .../eid-wallet.xcodeproj/project.pbxproj | 8 +- .../gen/apple/eid-wallet_iOS/Info.plist | 4 +- 6 files changed, 196 insertions(+), 59 deletions(-) diff --git a/infrastructure/control-panel/src/lib/services/evaultService.ts b/infrastructure/control-panel/src/lib/services/evaultService.ts index 1d17627f..fbadda11 100644 --- a/infrastructure/control-panel/src/lib/services/evaultService.ts +++ b/infrastructure/control-panel/src/lib/services/evaultService.ts @@ -73,4 +73,41 @@ export class EVaultService { throw error; } } + + /** + * Get logs for a specific eVault pod + */ + /** + * Get logs for a specific eVault pod + */ + static async getEVaultLogs(namespace: string, podName: string): Promise { + try { + const response = await fetch(`/api/evaults/${encodeURIComponent(namespace)}/${encodeURIComponent(podName)}/logs`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + return data.logs || []; + } catch (error) { + console.error('Failed to fetch eVault logs:', error); + throw error; + } + } + + /** + * Get metrics for a specific eVault pod + */ + static async getEVaultMetrics(namespace: string, podName: string): Promise { + try { + const response = await fetch(`/api/evaults/${encodeURIComponent(namespace)}/${encodeURIComponent(podName)}/metrics`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + return data.metrics || {}; + } catch (error) { + console.error('Failed to fetch eVault metrics:', error); + throw error; + } + } } diff --git a/infrastructure/control-panel/src/routes/+page.svelte b/infrastructure/control-panel/src/routes/+page.svelte index 22342d56..34a76626 100644 --- a/infrastructure/control-panel/src/routes/+page.svelte +++ b/infrastructure/control-panel/src/routes/+page.svelte @@ -25,8 +25,9 @@ let totalPages = $state(1); // Track selected items - let selectedEVaults = $state([]); - let selectedPlatforms = $state([]); + // Selection state - store unique identifiers instead of indices + let selectedEVaults = $state([]); + let selectedPlatforms = $state([]); // Filtered data for search let filteredEVaults = $derived(() => { @@ -129,49 +130,53 @@ // Handle eVault selection changes function handleEVaultSelectionChange(index: number, checked: boolean) { - // Get the filtered eVaults to work with the current search results - const filtered = filteredEVaults(); - - // Convert page-relative index to filtered array index - const filteredIndex = (currentPage - 1) * itemsPerPage + index; + // Get the paginated eVaults to work with the current page + const paginated = paginatedEVaults(); - // Get the actual eVault from the filtered results - const selectedEVault = filtered[filteredIndex]; + // Get the actual eVault from the paginated results + const selectedEVault = paginated[index]; if (!selectedEVault) { - console.error('Selected eVault not found in filtered results'); - return; - } - - // Find the index of this eVault in the original evaults array - const originalIndex = evaults.findIndex((e) => e.evaultId === selectedEVault.evaultId); - - if (originalIndex === -1) { - console.error('Selected eVault not found in original evaults array'); + console.error('Selected eVault not found in paginated results'); return; } if (checked) { - selectedEVaults = [...selectedEVaults, originalIndex]; + selectedEVaults = [...selectedEVaults, selectedEVault.evaultId]; } else { - selectedEVaults = selectedEVaults.filter((i) => i !== originalIndex); + selectedEVaults = selectedEVaults.filter((id) => id !== selectedEVault.evaultId); } // Store selections immediately in sessionStorage - const selectedEVaultData = selectedEVaults.map((i) => evaults[i]); + const selectedEVaultData = selectedEVaults + .map((id) => evaults.find((e) => e.evaultId === id)) + .filter(Boolean); sessionStorage.setItem('selectedEVaults', JSON.stringify(selectedEVaultData)); } // Handle platform selection changes function handlePlatformSelectionChange(index: number, checked: boolean) { + // Get the filtered platforms to work with the current search results + const filtered = filteredPlatforms(); + + // Get the actual platform from the filtered results + const selectedPlatform = filtered[index]; + + if (!selectedPlatform) { + console.error('Selected platform not found in filtered results'); + return; + } + if (checked) { - selectedPlatforms = [...selectedPlatforms, index]; + selectedPlatforms = [...selectedPlatforms, selectedPlatform.name]; } else { - selectedPlatforms = selectedPlatforms.filter((i) => i !== index); + selectedPlatforms = selectedPlatforms.filter((name) => name !== selectedPlatform.name); } // Store selections immediately in sessionStorage - const selectedPlatformData = selectedPlatforms.map((i) => platforms[i]); + const selectedPlatformData = selectedPlatforms + .map((name) => platforms.find((p) => p.name === name)) + .filter(Boolean); sessionStorage.setItem('selectedPlatforms', JSON.stringify(selectedPlatformData)); } @@ -184,14 +189,8 @@ console.log('filtered eVaults length:', filtered.length); if (checked) { - // Select all filtered eVaults by finding their indices in the original array - const filteredIndices = filtered - .map((filteredEVault) => { - return evaults.findIndex((e) => e.evaultId === filteredEVault.evaultId); - }) - .filter((index) => index !== -1); - - selectedEVaults = filteredIndices; + // Select all filtered eVaults by their evaultId + selectedEVaults = filtered.map((evault) => evault.evaultId); console.log('✅ Selected all filtered eVaults, selectedEVaults:', selectedEVaults); } else { // Deselect all eVaults @@ -200,7 +199,9 @@ } // Store selections immediately in sessionStorage - const selectedEVaultData = selectedEVaults.map((i) => evaults[i]); + const selectedEVaultData = selectedEVaults + .map((id) => evaults.find((e) => e.evaultId === id)) + .filter(Boolean); sessionStorage.setItem('selectedEVaults', JSON.stringify(selectedEVaultData)); console.log('💾 Stored in sessionStorage:', selectedEVaultData); } @@ -208,12 +209,18 @@ // Handle select all platforms function handleSelectAllPlatforms(checked: boolean) { console.log('🎯 handleSelectAllPlatforms called with:', checked); - console.log('platforms.length:', platforms.length); + + // Get the filtered platforms to work with the current search results + const filtered = filteredPlatforms(); + console.log('filtered platforms length:', filtered.length); if (checked) { - // Select all platforms - selectedPlatforms = Array.from({ length: platforms.length }, (_, i) => i); - console.log('✅ Selected all platforms, selectedPlatforms:', selectedPlatforms); + // Select all filtered platforms by their name + selectedPlatforms = filtered.map((platform) => platform.name); + console.log( + '✅ Selected all filtered platforms, selectedPlatforms:', + selectedPlatforms + ); } else { // Deselect all platforms selectedPlatforms = []; @@ -221,7 +228,9 @@ } // Store selections immediately in sessionStorage - const selectedPlatformData = selectedPlatforms.map((i) => platforms[i]); + const selectedPlatformData = selectedPlatforms + .map((name) => platforms.find((p) => p.name === name)) + .filter(Boolean); sessionStorage.setItem('selectedPlatforms', JSON.stringify(selectedPlatformData)); console.log('💾 Stored in sessionStorage:', selectedPlatformData); } @@ -240,8 +249,12 @@ // Navigate to monitoring with selected items function goToMonitoring() { - const selectedEVaultData = selectedEVaults.map((i) => evaults[i]); - const selectedPlatformData = selectedPlatforms.map((i) => platforms[i]); + const selectedEVaultData = selectedEVaults + .map((id) => evaults.find((e) => e.evaultId === id)) + .filter(Boolean); + const selectedPlatformData = selectedPlatforms + .map((name) => platforms.find((p) => p.name === name)) + .filter(Boolean); // Store selected data in sessionStorage to pass to monitoring page sessionStorage.setItem('selectedEVaults', JSON.stringify(selectedEVaultData)); @@ -333,7 +346,8 @@ let currentSelectedEVaultIndex = $state(-1); function handleEVaultRowClick(index: number) { - const evault = evaults[index]; + const paginated = paginatedEVaults(); + const evault = paginated[index]; if (evault) { goto(`/monitoring/${evault.namespace}/${evault.name}`); } @@ -388,15 +402,10 @@ handleSelectedRow={handleEVaultRowClick} onSelectionChange={handleEVaultSelectionChange} onSelectAllChange={handleSelectAllEVaults} - selectedIndices={selectedEVaults - .map((globalIndex) => { - const pageStart = (currentPage - 1) * itemsPerPage; - const pageEnd = pageStart + itemsPerPage; - if (globalIndex >= pageStart && globalIndex < pageEnd) { - return globalIndex - pageStart; - } - return -1; // Not on current page - }) + selectedIndices={paginatedEVaults() + .map((evault, index) => + selectedEVaults.includes(evault.evaultId) ? index : -1 + ) .filter((index) => index !== -1)} /> @@ -469,7 +478,11 @@ withPagination={false} onSelectionChange={handlePlatformSelectionChange} onSelectAllChange={handleSelectAllPlatforms} - selectedIndices={selectedPlatforms} + selectedIndices={filteredPlatforms() + .map((platform, index) => + selectedPlatforms.includes(platform.name) ? index : -1 + ) + .filter((index) => index !== -1)} /> {/if} diff --git a/infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts b/infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts index 624376aa..caa5de85 100644 --- a/infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts +++ b/infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts @@ -10,6 +10,33 @@ export const GET: RequestHandler = async ({ params, url }) => { const tail = url.searchParams.get('tail') || '100'; try { + // First check if the namespace exists + try { + await execAsync(`kubectl get namespace ${namespace}`); + } catch (namespaceError: any) { + if (namespaceError.stderr?.includes('not found')) { + return json({ + error: `Namespace '${namespace}' not found. The eVault may have been deleted or terminated.`, + logs: [] + }, { status: 404 }); + } + throw namespaceError; + } + + // Then check if the pod exists + try { + await execAsync(`kubectl get pod ${pod} -n ${namespace}`); + } catch (podError: any) { + if (podError.stderr?.includes('not found')) { + return json({ + error: `Pod '${pod}' not found in namespace '${namespace}'. The pod may have been deleted or terminated.`, + logs: [] + }, { status: 404 }); + } + throw podError; + } + + // If both exist, fetch the logs const { stdout } = await execAsync( `kubectl logs -n ${namespace} ${pod} -c evault --tail=${tail}` ); @@ -19,8 +46,20 @@ export const GET: RequestHandler = async ({ params, url }) => { .filter((line) => line.trim()); return json({ logs }); - } catch (error) { + } catch (error: any) { console.error('Error fetching logs:', error); - return json({ error: 'Failed to fetch logs', logs: [] }, { status: 500 }); + + // Handle specific kubectl errors + if (error.stderr?.includes('not found')) { + return json({ + error: 'Resource not found. The eVault or pod may have been deleted.', + logs: [] + }, { status: 404 }); + } + + return json({ + error: 'Failed to fetch logs. Please check if the eVault is still running.', + logs: [] + }, { status: 500 }); } }; diff --git a/infrastructure/control-panel/src/routes/monitoring/[namespace]/[service]/+page.svelte b/infrastructure/control-panel/src/routes/monitoring/[namespace]/[service]/+page.svelte index 11608ee8..1d758384 100644 --- a/infrastructure/control-panel/src/routes/monitoring/[namespace]/[service]/+page.svelte +++ b/infrastructure/control-panel/src/routes/monitoring/[namespace]/[service]/+page.svelte @@ -1,6 +1,54 @@