Skip to content
Merged
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
37 changes: 37 additions & 0 deletions infrastructure/control-panel/src/lib/services/evaultService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string[]> {
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<any> {
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;
}
}
}
115 changes: 64 additions & 51 deletions infrastructure/control-panel/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
let totalPages = $state(1);

// Track selected items
let selectedEVaults = $state<number[]>([]);
let selectedPlatforms = $state<number[]>([]);
// Selection state - store unique identifiers instead of indices
let selectedEVaults = $state<string[]>([]);
let selectedPlatforms = $state<string[]>([]);

// Filtered data for search
let filteredEVaults = $derived(() => {
Expand Down Expand Up @@ -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));
}

Expand All @@ -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
Expand All @@ -200,28 +199,38 @@
}

// 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);
}

// 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 = [];
console.log('❌ Deselected all platforms, selectedPlatforms:', selectedPlatforms);
}

// 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);
}
Expand All @@ -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));
Expand Down Expand Up @@ -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}`);
}
Expand Down Expand Up @@ -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)}
/>

Expand Down Expand Up @@ -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}
</TableCard>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}`
);
Expand All @@ -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 });
}
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { EVaultService } from '$lib/services/evaultService';

// Debug: Check if methods exist
console.log('🔍 EVaultService imported:', EVaultService);
console.log('🔍 getEVaultLogs exists:', typeof EVaultService.getEVaultLogs);
console.log('🔍 getEVaultMetrics exists:', typeof EVaultService.getEVaultMetrics);

// Temporary workaround: Add methods directly if they don't exist
if (!EVaultService.getEVaultLogs) {
console.log('⚠️ Adding getEVaultLogs method directly');
EVaultService.getEVaultLogs = async (namespace: string, podName: string) => {
console.log('🔍 Direct getEVaultLogs called with:', { namespace, podName });
try {
const response = await fetch(
`/api/evaults/${encodeURIComponent(namespace)}/${encodeURIComponent(podName)}/logs`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const responseData = await response.json();
console.log('✅ Direct logs fetched successfully:', responseData);
return responseData.logs || [];
} catch (error) {
console.error('❌ Direct logs fetch failed:', error);
throw error;
}
};
}

if (!EVaultService.getEVaultMetrics) {
console.log('⚠️ Adding getEVaultMetrics method directly');
EVaultService.getEVaultMetrics = async (namespace: string, podName: string) => {
console.log('🔍 Direct getEVaultMetrics called with:', { namespace, podName });
try {
const response = await fetch(
`/api/evaults/${encodeURIComponent(namespace)}/${encodeURIComponent(podName)}/metrics`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const responseData = await response.json();
console.log('✅ Direct metrics fetched successfully:', responseData);
return responseData.metrics || {};
} catch (error) {
console.error('❌ Direct metrics fetch failed:', error);
throw error;
}
};
}
import { ButtonAction } from '$lib/ui';
import { RefreshCw, Clock, Activity, Server, Globe, ArrowLeft } from 'lucide-svelte';
import { goto } from '$app/navigation';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "eid-wallet_iOS/eid-wallet_iOS.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 0.2.0.2;
CURRENT_PROJECT_VERSION = 0.2.1.0;
DEVELOPMENT_TEAM = M49C8XS835;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
Expand All @@ -415,7 +415,7 @@
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
MARKETING_VERSION = 0.2.0;
MARKETING_VERSION = 0.2.1;
PRODUCT_BUNDLE_IDENTIFIER = "foundation.metastate.eid-wallet";
PRODUCT_NAME = "eID for W3DS";
SDKROOT = iphoneos;
Expand All @@ -436,7 +436,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "eid-wallet_iOS/eid-wallet_iOS.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 0.2.0.2;
CURRENT_PROJECT_VERSION = 0.2.1.0;
DEVELOPMENT_TEAM = M49C8XS835;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
Expand All @@ -463,7 +463,7 @@
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
MARKETING_VERSION = 0.2.0;
MARKETING_VERSION = 0.2.1;
PRODUCT_BUNDLE_IDENTIFIER = "foundation.metastate.eid-wallet";
PRODUCT_NAME = "eID for W3DS";
SDKROOT = iphoneos;
Expand Down
Loading
Loading